Merge "libfs_avb: support loading vbmeta structs from any partition"
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 21e0874..d56a25f 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -35,7 +35,6 @@
#include "client/file_sync_client.h"
#include "commandline.h"
#include "fastdeploy.h"
-#include "sysdeps.h"
static constexpr int kFastDeployMinApi = 24;
@@ -161,17 +160,23 @@
if (use_fastdeploy == true) {
TemporaryFile metadataTmpFile;
- TemporaryFile patchTmpFile;
+ std::string patchTmpFilePath;
+ {
+ TemporaryFile patchTmpFile;
+ patchTmpFile.DoNotRemove();
+ patchTmpFilePath = patchTmpFile.path;
+ }
FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
extract_metadata(file, metadataFile);
fclose(metadataFile);
- create_patch(file, metadataTmpFile.path, patchTmpFile.path);
+ create_patch(file, metadataTmpFile.path, patchTmpFilePath.c_str());
// pass all but 1st (command) and last (apk path) parameters through to pm for
// session creation
std::vector<const char*> pm_args{argv + 1, argv + argc - 1};
- install_patch(file, patchTmpFile.path, pm_args.size(), pm_args.data());
+ install_patch(file, patchTmpFilePath.c_str(), pm_args.size(), pm_args.data());
+ adb_unlink(patchTmpFilePath.c_str());
delete_device_patch_file(file);
return 0;
} else {
diff --git a/adb/client/line_printer.cpp b/adb/client/line_printer.cpp
index 4dc2d28..50c03e8 100644
--- a/adb/client/line_printer.cpp
+++ b/adb/client/line_printer.cpp
@@ -31,6 +31,8 @@
// Stuff from ninja's util.h that's needed below.
#include <vector>
using namespace std;
+// This does not account for multiple UTF-8 bytes corresponding to a single Unicode code point, or
+// multiple code points corresponding to a single grapheme cluster (user-perceived character).
string ElideMiddle(const string& str, size_t width) {
const int kMargin = 3; // Space for "...".
string result = str;
@@ -85,9 +87,10 @@
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(console_, &csbi);
- // TODO: std::wstring to_print_wide; if (!android::base::UTF8ToWide(to_print, &to_print_wide)...
- // TODO: wstring ElideMiddle.
to_print = ElideMiddle(to_print, static_cast<size_t>(csbi.dwSize.X));
+ std::wstring to_print_wide;
+ // ElideMiddle may create invalid UTF-8, so ignore conversion errors.
+ (void)android::base::UTF8ToWide(to_print, &to_print_wide);
// We don't want to have the cursor spamming back and forth, so instead of
// printf use WriteConsoleOutput which updates the contents of the buffer,
// but doesn't move the cursor position.
@@ -100,12 +103,10 @@
};
vector<CHAR_INFO> char_data(csbi.dwSize.X);
for (size_t i = 0; i < static_cast<size_t>(csbi.dwSize.X); ++i) {
- // TODO: UnicodeChar instead of AsciiChar, to_print_wide[i].
- char_data[i].Char.AsciiChar = i < to_print.size() ? to_print[i] : ' ';
- char_data[i].Attributes = csbi.wAttributes;
+ char_data[i].Char.UnicodeChar = i < to_print_wide.size() ? to_print_wide[i] : L' ';
+ char_data[i].Attributes = csbi.wAttributes;
}
- // TODO: WriteConsoleOutputW.
- WriteConsoleOutput(console_, &char_data[0], buf_size, zero_zero, &target);
+ WriteConsoleOutputW(console_, &char_data[0], buf_size, zero_zero, &target);
#else
// Limit output to width of the terminal if provided so we don't cause
// line-wrapping.
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index dbc8920..d587589 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -719,7 +719,7 @@
/**************************************************************************/
/**************************************************************************/
-static int _init_winsock(void) {
+static void _init_winsock() {
static std::once_flag once;
std::call_once(once, []() {
WSADATA wsaData;
@@ -743,11 +743,8 @@
// crypt32.dll which calls atexit() which tries to acquire the C
// Runtime lock that the other thread holds.
});
- return 0;
}
-static int _winsock_init = _init_winsock();
-
// Map a socket type to an explicit socket protocol instead of using the socket
// protocol of 0. Explicit socket protocols are used by most apps and we should
// do the same to reduce the chance of exercising uncommon code-paths that might
@@ -2621,14 +2618,13 @@
}
// Shadow UTF-8 environment variable name/value pairs that are created from
-// _wenviron the first time that adb_getenv() is called. Note that this is not
-// currently updated if putenv, setenv, unsetenv are called. Note that no
-// thread synchronization is done, but we're called early enough in
+// _wenviron by _init_env(). Note that this is not currently updated if putenv, setenv, unsetenv are
+// called. Note that no thread synchronization is done, but we're called early enough in
// single-threaded startup that things work ok.
static auto& g_environ_utf8 = *new std::unordered_map<std::string, char*>();
-// Make sure that shadow UTF-8 environment variables are setup.
-static void _ensure_env_setup() {
+// Setup shadow UTF-8 environment variables.
+static void _init_env() {
// If some name/value pairs exist, then we've already done the setup below.
if (g_environ_utf8.size() != 0) {
return;
@@ -2681,8 +2677,6 @@
// Version of getenv() that takes a UTF-8 environment variable name and
// retrieves a UTF-8 value. Case-insensitive to match getenv() on Windows.
char* adb_getenv(const char* name) {
- _ensure_env_setup();
-
// Case-insensitive search by searching for lowercase name in a map of
// lowercase names.
const auto it = g_environ_utf8.find(ToLower(std::string(name)));
@@ -2757,3 +2751,65 @@
return 0;
}
+
+#if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
+#if !defined(DISABLE_NEWLINE_AUTO_RETURN)
+#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
+#endif
+
+static void _init_console() {
+ DWORD old_out_console_mode;
+
+ const HANDLE out = _get_console_handle(STDOUT_FILENO, &old_out_console_mode);
+ if (out == nullptr) {
+ return;
+ }
+
+ // Try to use ENABLE_VIRTUAL_TERMINAL_PROCESSING on the output console to process virtual
+ // terminal sequences on newer versions of Windows 10 and later.
+ // https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
+ // On older OSes that don't support the flag, SetConsoleMode() will return an error.
+ // ENABLE_VIRTUAL_TERMINAL_PROCESSING also solves a problem where the last column of the
+ // console cannot be overwritten.
+ //
+ // Note that we don't use DISABLE_NEWLINE_AUTO_RETURN because it doesn't seem to be necessary.
+ // If we use DISABLE_NEWLINE_AUTO_RETURN, _console_write_utf8() would need to be modified to
+ // translate \n to \r\n.
+ if (!SetConsoleMode(out, old_out_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
+ return;
+ }
+
+ // If SetConsoleMode() succeeded, the console supports virtual terminal processing, so we
+ // should set the TERM env var to match so that it will be propagated to adbd on devices.
+ //
+ // Below's direct manipulation of env vars and not g_environ_utf8 assumes that _init_env() has
+ // not yet been called. If this fails, _init_env() should be called after _init_console().
+ if (g_environ_utf8.size() > 0) {
+ LOG(FATAL) << "environment variables have already been converted to UTF-8";
+ }
+
+#pragma push_macro("getenv")
+#undef getenv
+#pragma push_macro("putenv")
+#undef putenv
+ if (getenv("TERM") == nullptr) {
+ // This is the same TERM value used by Gnome Terminal and the version of ssh included with
+ // Windows.
+ putenv("TERM=xterm-256color");
+ }
+#pragma pop_macro("putenv")
+#pragma pop_macro("getenv")
+}
+
+static bool _init_sysdeps() {
+ // _init_console() depends on _init_env() not being called yet.
+ _init_console();
+ _init_env();
+ _init_winsock();
+ return true;
+}
+
+static bool _sysdeps_init = _init_sysdeps();
diff --git a/fs_mgr/OWNERS b/fs_mgr/OWNERS
index 817a0b8..cbbd3bc 100644
--- a/fs_mgr/OWNERS
+++ b/fs_mgr/OWNERS
@@ -1,2 +1,3 @@
bowgotsai@google.com
+dvander@google.com
tomcherry@google.com
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 70a1045..ded3678 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -81,6 +81,8 @@
#define ZRAM_CONF_MCS "/sys/block/zram0/max_comp_streams"
#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
+#define SYSFS_EXT4_VERITY "/sys/fs/ext4/features/verity"
+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
using android::base::Realpath;
@@ -110,6 +112,7 @@
FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000,
+ FS_STAT_ENABLE_VERITY_FAILED = 0x80000,
};
// TODO: switch to inotify()
@@ -440,6 +443,43 @@
}
}
+// Enable fs-verity if needed.
+static void tune_verity(const std::string& blk_device, const FstabEntry& entry,
+ const struct ext4_super_block* sb, int* fs_stat) {
+ bool has_verity = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_VERITY)) != 0;
+ bool want_verity = entry.fs_mgr_flags.fs_verity;
+
+ if (has_verity || !want_verity) {
+ return;
+ }
+
+ std::string verity_support;
+ if (!android::base::ReadFileToString(SYSFS_EXT4_VERITY, &verity_support)) {
+ LERROR << "Failed to open " << SYSFS_EXT4_VERITY;
+ return;
+ }
+
+ if (!(android::base::Trim(verity_support) == "supported")) {
+ LERROR << "Current ext4 verity not supported by kernel";
+ return;
+ }
+
+ if (!tune2fs_available()) {
+ LERROR << "Unable to enable ext4 verity on " << blk_device
+ << " because " TUNE2FS_BIN " is missing";
+ return;
+ }
+
+ LINFO << "Enabling ext4 verity on " << blk_device;
+
+ const char* argv[] = {TUNE2FS_BIN, "-O", "verity", blk_device.c_str()};
+ if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+ LERROR << "Failed to run " TUNE2FS_BIN " to enable "
+ << "ext4 verity on " << blk_device;
+ *fs_stat |= FS_STAT_ENABLE_VERITY_FAILED;
+ }
+}
+
// Read the primary superblock from an f2fs filesystem. On failure return
// false. If it's not an f2fs filesystem, also set FS_STAT_INVALID_MAGIC.
#define F2FS_BLKSIZE 4096
@@ -511,12 +551,14 @@
}
if (is_extfs(entry.fs_type) &&
- (entry.fs_mgr_flags.reserved_size || entry.fs_mgr_flags.file_encryption)) {
+ (entry.fs_mgr_flags.reserved_size || entry.fs_mgr_flags.file_encryption ||
+ entry.fs_mgr_flags.fs_verity)) {
struct ext4_super_block sb;
if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
tune_reserved_size(blk_device, entry, &sb, &fs_stat);
tune_encrypt(blk_device, entry, &sb, &fs_stat);
+ tune_verity(blk_device, entry, &sb, &fs_stat);
}
}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index c9f34a7..9d4f280 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -125,6 +125,7 @@
{"zram_loopback_path=", MF_ZRAM_LOOPBACK_PATH},
{"zram_loopback_size=", MF_ZRAM_LOOPBACK_SIZE},
{"zram_backing_dev_path=", MF_ZRAM_BACKING_DEV_PATH},
+ {"fsverity", MF_FS_VERITY},
{0, 0},
};
@@ -1087,6 +1088,10 @@
return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
}
+int fs_mgr_is_fs_verity(const struct fstab_rec* fstab) {
+ return fstab->fs_mgr_flags & MF_FS_VERITY;
+}
+
FstabEntry BuildGsiSystemFstabEntry() {
FstabEntry system = {
.blk_device = "system_gsi",
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 0f89467..2c4299a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -137,9 +137,9 @@
bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
// readonly filesystem, can not be mount -o remount,rw
- // if squashfs or if free space is (near) zero making such a remount
+ // for squashfs, erofs or if free space is (near) zero making such a remount
// virtually useless, or if there are shared blocks that prevent remount,rw
- if ("squashfs" == entry->fs_type || !fs_mgr_filesystem_has_space(entry->mount_point)) {
+ if (!fs_mgr_filesystem_has_space(entry->mount_point)) {
return true;
}
if (entry->fs_mgr_flags.logical) {
@@ -626,8 +626,8 @@
// Only a suggestion for _first_ try during mounting
std::string fs_mgr_overlayfs_scratch_mount_type() {
- if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
- if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
+ if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_access("/sys/fs/f2fs")) return "f2fs";
+ if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_access("/sys/fs/ext4")) return "ext4";
return "auto";
}
@@ -642,7 +642,11 @@
// Create from within single super device;
auto& dm = DeviceMapper::Instance();
const auto partition_name = android::base::Basename(kScratchMountPoint);
- if (!dm.GetDmDevicePathByName(partition_name, &path)) return "";
+ if (!dm.GetDmDevicePathByName(partition_name, &path)) {
+ // non-DAP A/B device?
+ if (fs_mgr_access(super_device)) return "";
+ path = kPhysicalDevice + "system" + (slot_number ? "_a" : "_b");
+ }
}
return scratch_device_cache = path;
}
@@ -829,8 +833,9 @@
true /* readonly */)) {
auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
fs_mgr_overlayfs_umount_scratch();
- if (has_overlayfs_dir)
+ if (has_overlayfs_dir) {
fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+ }
}
}
}
@@ -882,10 +887,6 @@
for (const auto& overlay_mount_point : kOverlayMountPoints) {
if (backing && backing[0] && (overlay_mount_point != backing)) continue;
if (overlay_mount_point == kScratchMountPoint) {
- if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) ||
- !fs_mgr_overlayfs_has_logical(fstab)) {
- continue;
- }
if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
} else {
if (std::find_if(fstab.begin(), fstab.end(), [&overlay_mount_point](const auto& entry) {
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 39ceff7..3b9ddee 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -128,6 +128,8 @@
0x400000000
#define MF_ZRAM_BACKING_DEV_PATH \
0x800000000
+#define MF_FS_VERITY \
+ 0x1000000000
// clang-format on
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 68ce4b0..38f96c0 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -95,6 +95,7 @@
int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab);
int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab);
int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
+int fs_mgr_is_fs_verity(const struct fstab_rec* fstab);
std::string fs_mgr_get_slot_suffix();
std::string fs_mgr_get_other_slot_suffix();
@@ -175,6 +176,10 @@
// bit 32
bool slot_select_other : 1;
+ bool zram_loopback_path : 1;
+ bool zram_loopback_size : 1;
+ bool zram_backing_dev_path : 1;
+ bool fs_verity : 1;
};
} fs_mgr_flags;
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 71b39a9..6ccdb57 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -220,7 +220,7 @@
}
static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz,
- uint64_t file_size) {
+ uint64_t file_size, std::function<bool(uint64_t, uint64_t)> on_progress) {
// Reserve space for the file on the file system and write it out to make sure the extents
// don't come back unwritten. Return from this function with the kernel file offset set to 0.
// If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks
@@ -245,12 +245,22 @@
return false;
}
+ int permille = -1;
for (; offset < file_size; offset += blocksz) {
if (!::android::base::WriteFully(file_fd, buffer.get(), blocksz)) {
PLOG(ERROR) << "Failed to write" << blocksz << " bytes at offset" << offset
<< " in file " << file_path;
return false;
}
+ // Don't invoke the callback every iteration - wait until a significant
+ // chunk (here, 1/1000th) of the data has been processed.
+ int new_permille = (static_cast<uint64_t>(offset) * 1000) / file_size;
+ if (new_permille != permille) {
+ if (on_progress && !on_progress(offset, file_size)) {
+ return false;
+ }
+ permille = new_permille;
+ }
}
if (lseek64(file_fd, 0, SEEK_SET) < 0) {
@@ -264,6 +274,10 @@
return false;
}
+ // Send one last progress notification.
+ if (on_progress && !on_progress(file_size, file_size)) {
+ return false;
+ }
return true;
}
@@ -345,6 +359,21 @@
return moved_blocks_nr == 0;
}
+bool FiemapWriter::HasPinnedExtents(const std::string& file_path) {
+ android::base::unique_fd fd(open(file_path.c_str(), O_NOFOLLOW | O_CLOEXEC | O_RDONLY));
+ if (fd < 0) {
+ PLOG(ERROR) << "open: " << file_path;
+ return false;
+ }
+
+ struct statfs64 sfs;
+ if (fstatfs64(fd, &sfs)) {
+ PLOG(ERROR) << "fstatfs64: " << file_path;
+ return false;
+ }
+ return IsFilePinned(fd, file_path, sfs.f_type);
+}
+
static void LogExtent(uint32_t num, const struct fiemap_extent& ext) {
LOG(INFO) << "Extent #" << num;
LOG(INFO) << " fe_logical: " << ext.fe_logical;
@@ -412,7 +441,8 @@
return last_extent_seen;
}
-FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create) {
+FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create,
+ std::function<bool(uint64_t, uint64_t)> progress) {
// if 'create' is false, open an existing file and do not truncate.
int open_flags = O_RDWR | O_CLOEXEC;
if (create) {
@@ -474,7 +504,7 @@
}
if (create) {
- if (!AllocateFile(file_fd, abs_path, blocksz, file_size)) {
+ if (!AllocateFile(file_fd, abs_path, blocksz, file_size, std::move(progress))) {
LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size
<< " bytes";
cleanup(abs_path, create);
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index 6dff0e8..3d20ff3 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -51,6 +51,8 @@
testfile = ::android::base::StringPrintf("%s/testdata/%s", exec_dir.c_str(), tinfo->name());
}
+ void TearDown() override { unlink(testfile.c_str()); }
+
// name of the file we use for testing
std::string testfile;
};
@@ -83,6 +85,31 @@
EXPECT_EQ(access(testfile.c_str(), F_OK), 0);
}
+TEST_F(FiemapWriterTest, CheckProgress) {
+ std::vector<uint64_t> expected{
+ 0,
+ 4096,
+ };
+ size_t invocations = 0;
+ auto callback = [&](uint64_t done, uint64_t total) -> bool {
+ EXPECT_LT(invocations, expected.size());
+ EXPECT_EQ(done, expected[invocations]);
+ EXPECT_EQ(total, 4096);
+ invocations++;
+ return true;
+ };
+
+ auto ptr = FiemapWriter::Open(testfile, 4096, true, std::move(callback));
+ EXPECT_NE(ptr, nullptr);
+ EXPECT_EQ(invocations, 2);
+}
+
+TEST_F(FiemapWriterTest, CheckPinning) {
+ auto ptr = FiemapWriter::Open(testfile, 4096);
+ ASSERT_NE(ptr, nullptr);
+ EXPECT_TRUE(FiemapWriter::HasPinnedExtents(testfile));
+}
+
TEST_F(FiemapWriterTest, CheckBlockDevicePath) {
FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
EXPECT_EQ(fptr->size(), 4096);
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
index ae61344..a0085cf 100644
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
+++ b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <functional>
#include <string>
#include <vector>
@@ -36,9 +37,25 @@
public:
// Factory method for FiemapWriter.
// The method returns FiemapUniquePtr that contains all the data necessary to be able to write
- // to the given file directly using raw block i/o.
+ // to the given file directly using raw block i/o. The optional progress callback will be
+ // invoked, if create is true, while the file is being initialized. It receives the bytes
+ // written and the number of total bytes. If the callback returns false, the operation will
+ // fail.
static FiemapUniquePtr Open(const std::string& file_path, uint64_t file_size,
- bool create = true);
+ bool create = true,
+ std::function<bool(uint64_t, uint64_t)> progress = {});
+
+ // Check that a file still has the same extents since it was last opened with FiemapWriter,
+ // assuming the file was not resized outside of FiemapWriter. Returns false either on error
+ // or if the file was not pinned.
+ //
+ // This will always return true on Ext4. On F2FS, it will return true if either of the
+ // following cases are true:
+ // - The file was never pinned.
+ // - The file is pinned and has not been moved by the GC.
+ // Thus, this method should only be called for pinned files (such as those returned by
+ // FiemapWriter::Open).
+ static bool HasPinnedExtents(const std::string& file_path);
// Syncs block device writes.
bool Flush() const;
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 0765f04..42f3f29 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -309,7 +309,7 @@
-e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
-e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
-e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
- -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\) "
+ -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
}
if [ X"-s" = X"${1}" -a -n "${2}" ]; then
@@ -403,9 +403,15 @@
echo "${D}" | grep -v /dev/root`
fi
D=`echo "${D}" | cut -s -d' ' -f1 | sort -u`
+no_dedupe=true
+for d in ${D}; do
+ adb_sh tune2fs -l $d 2>&1 |
+ grep "Filesystem features:.*shared_blocks" >/dev/null &&
+ no_dedupe=false
+done
D=`adb_sh df -k ${D} </dev/null`
echo "${D}"
-if [ X"${D}" = X"${D##* 100[%] }" ]; then
+if [ X"${D}" = X"${D##* 100[%] }" ] && ${no_dedupe} ; then
overlayfs_needed=false
elif ! ${overlayfs_supported}; then
die "need overlayfs, but do not have it"
@@ -597,6 +603,7 @@
echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
+is_userspace_fastboot=false
if [ -z "${ANDROID_PRODUCT_OUT}" ]; then
echo "${ORANGE}[ WARNING ]${NORMAL} build tree not setup, skipping"
elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
@@ -609,6 +616,8 @@
fastboot flash vendor ||
( fastboot reboot && false) ||
die "fastboot flash vendor"
+ fastboot_getvar is-userspace yes &&
+ is_userspace_fastboot=true
if [ -n "${scratch_paritition}" ]; then
fastboot_getvar partition-type:${scratch_partition} raw ||
( fastboot reboot && false) ||
@@ -654,7 +663,12 @@
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay /system takeover after flash vendor"
echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
- die "overlay supposed to be minus /vendor takeover after flash vendor"
+ if ${is_userspace_fastboot}; then
+ die "overlay supposed to be minus /vendor takeover after flash vendor"
+ else
+ echo "${ORANGE}[ WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
+ ( die "overlay supposed to be minus /vendor takeover after flash vendor" )
+ fi
fi
B="`adb_cat /system/hello`" ||
die "re-read /system/hello after flash vendor"
@@ -662,8 +676,17 @@
adb_root ||
die "adb root"
B="`adb_cat /vendor/hello`" &&
- die "re-read /vendor/hello after flash vendor"
- check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+ if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
+ die "re-read /vendor/hello after flash vendor"
+ else
+ echo "${ORANGE}[ WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
+ ( die "re-read /vendor/hello after flash vendor" )
+ fi
+ if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
+ check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+ else
+ ( check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor )
+ fi
fi
echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index affa39e..153b857 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -73,7 +73,9 @@
bool InitRequiredDevices();
bool InitMappedDevice(const std::string& verity_device);
bool CreateLogicalPartitions();
- bool MountPartition(FstabEntry* fstab_entry);
+ bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+ Fstab::iterator* end = nullptr);
+
bool MountPartitions();
bool TrySwitchSystemAsRoot();
bool TrySkipMountingPartitions();
@@ -385,29 +387,40 @@
return true;
}
-bool FirstStageMount::MountPartition(FstabEntry* fstab_entry) {
- if (fstab_entry->fs_mgr_flags.logical) {
- if (!fs_mgr_update_logical_partition(fstab_entry)) {
+bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+ Fstab::iterator* end) {
+ if (begin->fs_mgr_flags.logical) {
+ if (!fs_mgr_update_logical_partition(&(*begin))) {
return false;
}
- if (!InitMappedDevice(fstab_entry->blk_device)) {
+ if (!InitMappedDevice(begin->blk_device)) {
return false;
}
}
- if (!SetUpDmVerity(fstab_entry)) {
- PLOG(ERROR) << "Failed to setup verity for '" << fstab_entry->mount_point << "'";
+ if (!SetUpDmVerity(&(*begin))) {
+ PLOG(ERROR) << "Failed to setup verity for '" << begin->mount_point << "'";
return false;
}
- if (fs_mgr_do_mount_one(*fstab_entry)) {
- if (fstab_entry->fs_mgr_flags.formattable) {
- PLOG(INFO) << "Failed to mount '" << fstab_entry->mount_point << "', "
- << "ignoring mount for formattable partition";
- return true;
+
+ bool mounted = (fs_mgr_do_mount_one(*begin) == 0);
+
+ // Try other mounts with the same mount point.
+ Fstab::iterator current = begin + 1;
+ for (; current != fstab_.end() && current->mount_point == begin->mount_point; current++) {
+ if (!mounted) {
+ // blk_device is already updated to /dev/dm-<N> by SetUpDmVerity() above.
+ // Copy it from the begin iterator.
+ current->blk_device = begin->blk_device;
+ mounted = (fs_mgr_do_mount_one(*current) == 0);
}
- PLOG(ERROR) << "Failed to mount '" << fstab_entry->mount_point << "'";
- return false;
}
- return true;
+ if (erase_used_fstab_entry) {
+ current = fstab_.erase(begin, current);
+ }
+ if (end) {
+ *end = current;
+ }
+ return mounted;
}
// If system is in the fstab then we're not a system-as-root device, and in
@@ -418,8 +431,7 @@
return entry.mount_point == "/metadata";
});
if (metadata_partition != fstab_.end()) {
- if (MountPartition(&(*metadata_partition))) {
- fstab_.erase(metadata_partition);
+ if (MountPartition(metadata_partition, true /* erase_used_fstab_entry */)) {
UseGsiIfPresent();
}
}
@@ -430,30 +442,13 @@
if (system_partition == fstab_.end()) return true;
- bool mounted = false;
- bool no_fail = false;
- for (auto it = system_partition; it != fstab_.end();) {
- if (it->mount_point != "/system") {
- break;
- }
- no_fail |= (it->fs_mgr_flags).no_fail;
- if (MountPartition(&(*it))) {
- mounted = true;
- SwitchRoot("/system");
- break;
- }
- it++;
- }
-
- if (!mounted && !no_fail) {
- LOG(ERROR) << "Failed to mount /system";
+ if (MountPartition(system_partition, true /* erase_used_fstab_entry */)) {
+ SwitchRoot("/system");
+ } else {
+ PLOG(ERROR) << "Failed to mount /system";
return false;
}
- auto it = std::remove_if(fstab_.begin(), fstab_.end(),
- [](const auto& entry) { return entry.mount_point == "/system"; });
- fstab_.erase(it, fstab_.end());
-
return true;
}
@@ -490,23 +485,21 @@
if (!TrySkipMountingPartitions()) return false;
- for (auto it = fstab_.begin(); it != fstab_.end();) {
- bool mounted = false;
- bool no_fail = false;
- auto start_mount_point = it->mount_point;
- do {
- no_fail |= (it->fs_mgr_flags).no_fail;
- if (!mounted)
- mounted = MountPartition(&(*it));
- else
- LOG(INFO) << "Skip already-mounted partition: " << start_mount_point;
- it++;
- } while (it != fstab_.end() && it->mount_point == start_mount_point);
-
- if (!mounted && !no_fail) {
- LOG(ERROR) << start_mount_point << " mounted unsuccessfully but it is required!";
- return false;
+ for (auto current = fstab_.begin(); current != fstab_.end();) {
+ Fstab::iterator end;
+ if (!MountPartition(current, false, &end)) {
+ if (current->fs_mgr_flags.no_fail) {
+ LOG(INFO) << "Failed to mount " << current->mount_point
+ << ", ignoring mount for no_fail partition";
+ } else if (current->fs_mgr_flags.formattable) {
+ LOG(INFO) << "Failed to mount " << current->mount_point
+ << ", ignoring mount for formattable partition";
+ } else {
+ PLOG(ERROR) << "Failed to mount " << current->mount_point;
+ return false;
+ }
}
+ current = end;
}
// heads up for instantiating required device(s) for overlayfs logic
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 0aa7810..5b90969 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -57,6 +57,7 @@
#include "service.h"
#include "sigchld_handler.h"
+using android::base::GetBoolProperty;
using android::base::Split;
using android::base::StringPrintf;
using android::base::Timer;
@@ -398,9 +399,31 @@
Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
- // will not check animation class separately
+ bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false);
+
+ if (do_shutdown_animation) {
+ property_set("service.bootanim.exit", "0");
+ // Could be in the middle of animation. Stop and start so that it can pick
+ // up the right mode.
+ bootAnim->Stop();
+ }
+
for (const auto& service : ServiceList::GetInstance()) {
- if (service->classnames().count("animation")) service->SetShutdownCritical();
+ if (service->classnames().count("animation") == 0) {
+ continue;
+ }
+
+ // start all animation classes if stopped.
+ if (do_shutdown_animation) {
+ service->Start().IgnoreError();
+ }
+ service->SetShutdownCritical(); // will not check animation class separately
+ }
+
+ if (do_shutdown_animation) {
+ bootAnim->Start().IgnoreError();
+ surfaceFlinger->SetShutdownCritical();
+ bootAnim->SetShutdownCritical();
}
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c0fc3ce..d93e9ec 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -304,13 +304,18 @@
if (!GetVendorMappingVersion(&vend_plat_vers)) {
return false;
}
- std::string mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
+ std::string plat_mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
std::string product_policy_cil_file("/product/etc/selinux/product_sepolicy.cil");
if (access(product_policy_cil_file.c_str(), F_OK) == -1) {
product_policy_cil_file.clear();
}
+ std::string product_mapping_file("/product/etc/selinux/mapping/" + vend_plat_vers + ".cil");
+ if (access(product_mapping_file.c_str(), F_OK) == -1) {
+ product_mapping_file.clear();
+ }
+
// vendor_sepolicy.cil and plat_pub_versioned.cil are the new design to replace
// nonplat_sepolicy.cil.
std::string plat_pub_versioned_cil_file("/vendor/etc/selinux/plat_pub_versioned.cil");
@@ -340,7 +345,7 @@
"-m", "-M", "true", "-G", "-N",
// Target the highest policy language version supported by the kernel
"-c", version_as_string.c_str(),
- mapping_file.c_str(),
+ plat_mapping_file.c_str(),
"-o", compiled_sepolicy,
// We don't care about file_contexts output by the compiler
"-f", "/sys/fs/selinux/null", // /dev/null is not yet available
@@ -350,6 +355,9 @@
if (!product_policy_cil_file.empty()) {
compile_args.push_back(product_policy_cil_file.c_str());
}
+ if (!product_mapping_file.empty()) {
+ compile_args.push_back(product_mapping_file.c_str());
+ }
if (!plat_pub_versioned_cil_file.empty()) {
compile_args.push_back(plat_pub_versioned_cil_file.c_str());
}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 4fd36f5..bd7a551 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -73,6 +73,7 @@
cflags: ["-DFAKE_LOG_DEVICE=1"],
},
android: {
+ version_script: "liblog.map.txt",
srcs: liblog_target_sources,
// AddressSanitizer runtime library depends on liblog.
sanitize: {
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 015c9cb..191ef1b 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -59,3 +59,24 @@
android_log_reset; #vndk
android_log_parser_reset; #vndk
};
+
+LIBLOG_PRIVATE {
+ global:
+ __android_log_bswrite;
+ __android_log_btwrite;
+ __android_log_bwrite;
+ __android_log_close;
+ __android_log_pmsg_file_read;
+ __android_log_pmsg_file_write;
+ __android_log_security;
+ __android_log_security_bswrite;
+ __android_logger_get_buffer_size;
+ __android_logger_property_get_bool;
+ android_openEventTagMap;
+ android_log_processBinaryLogBuffer;
+ android_log_processLogBuffer;
+ android_log_read_next;
+ android_log_write_list_buffer;
+ android_lookupEventTagNum;
+ create_android_log_parser;
+};
diff --git a/libmeminfo/include/meminfo/pageacct.h b/libmeminfo/include/meminfo/pageacct.h
index 8ddaef2..8483d84 100644
--- a/libmeminfo/include/meminfo/pageacct.h
+++ b/libmeminfo/include/meminfo/pageacct.h
@@ -65,5 +65,17 @@
::android::base::unique_fd pageidle_fd_;
};
+// Returns if the page present bit is set in the value
+// passed in.
+bool page_present(uint64_t pagemap_val);
+
+// Returns if the page swapped bit is set in the value
+// passed in.
+bool page_swapped(uint64_t pagemap_val);
+
+// Returns the page frame number (physical page) from
+// pagemap value
+uint64_t page_pfn(uint64_t pagemap_val);
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h
index 0b66074..95e5053 100644
--- a/libmeminfo/include/meminfo/procmeminfo.h
+++ b/libmeminfo/include/meminfo/procmeminfo.h
@@ -73,6 +73,13 @@
const std::vector<uint16_t>& SwapOffsets();
+ // Reads /proc/<pid>/pagemap for this process for each page within
+ // the 'vma' and stores that in 'pagemap'. It is assumed that the 'vma'
+ // is obtained by calling Maps() or 'ForEachVma' for the same object. No special checks
+ // are made to see if 'vma' is *valid*.
+ // Returns false if anything goes wrong, 'true' otherwise.
+ bool PageMap(const Vma& vma, std::vector<uint64_t>* pagemap);
+
~ProcMemInfo() = default;
private:
diff --git a/libmeminfo/include/meminfo/sysmeminfo.h b/libmeminfo/include/meminfo/sysmeminfo.h
index 450a469..8388920 100644
--- a/libmeminfo/include/meminfo/sysmeminfo.h
+++ b/libmeminfo/include/meminfo/sysmeminfo.h
@@ -58,7 +58,7 @@
// in vmalloc area by the kernel.
// Note that this deliberately ignores binder buffers. They are _always_
// mapped in a process and are counted for in each process.
- uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");
+ uint64_t ReadVmallocInfo();
// getters
uint64_t mem_total_kb() { return mem_in_kb_[kMemTotal]; }
@@ -84,5 +84,10 @@
std::function<void(const std::string&, uint64_t)> store_val);
};
+// Parse /proc/vmallocinfo and return total physical memory mapped
+// in vmalloc area by the kernel. Note that this deliberately ignores binder buffers. They are
+// _always_ mapped in a process and are counted for in each process.
+uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/libmeminfo_benchmark.cpp b/libmeminfo/libmeminfo_benchmark.cpp
index 81fc3b3..d88919b 100644
--- a/libmeminfo/libmeminfo_benchmark.cpp
+++ b/libmeminfo/libmeminfo_benchmark.cpp
@@ -455,8 +455,7 @@
std::string vmallocinfo =
::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
for (auto _ : state) {
- SysMemInfo smi;
- CHECK_EQ(smi.ReadVmallocInfo(vmallocinfo), 29884416);
+ CHECK_EQ(::android::meminfo::ReadVmallocInfo(vmallocinfo), 29884416);
}
}
BENCHMARK(BM_VmallocInfo_new);
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 7d85dd2..ccc40d1 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -121,6 +121,23 @@
EXPECT_EQ(proc_usage.swap / getpagesize(), swap_offsets.size());
}
+TEST_F(ValidateProcMemInfo, TestPageMap) {
+ std::vector<uint64_t> pagemap;
+
+ auto vma_callback = [&](const Vma& vma) {
+ uint64_t* pmap_out;
+ size_t len;
+ ASSERT_EQ(0, pm_process_pagemap_range(proc, vma.start, vma.end, &pmap_out, &len));
+ ASSERT_TRUE(proc_mem->PageMap(vma, &pagemap));
+
+ EXPECT_EQ(len, ((vma.end - vma.start) / getpagesize()));
+ for (size_t i = 0; i < len; i++) {
+ EXPECT_EQ(pmap_out[i], pagemap[i]);
+ }
+ };
+ ASSERT_TRUE(proc_mem->ForEachVma(vma_callback));
+}
+
class ValidateProcMemInfoWss : public ::testing::Test {
protected:
void SetUp() override {
@@ -844,8 +861,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), 0);
+ EXPECT_EQ(ReadVmallocInfo(file), 0);
}
TEST(SysMemInfoParser, TestVmallocInfoKernel) {
@@ -857,8 +873,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), getpagesize());
+ EXPECT_EQ(ReadVmallocInfo(file), getpagesize());
}
TEST(SysMemInfoParser, TestVmallocInfoModule) {
@@ -870,8 +885,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), 6 * getpagesize());
+ EXPECT_EQ(ReadVmallocInfo(file), 6 * getpagesize());
}
TEST(SysMemInfoParser, TestVmallocInfoAll) {
@@ -888,8 +902,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), 7 * getpagesize());
+ EXPECT_EQ(ReadVmallocInfo(file), 7 * getpagesize());
}
int main(int argc, char** argv) {
diff --git a/libmeminfo/pageacct.cpp b/libmeminfo/pageacct.cpp
index 887a74d..0a26c08 100644
--- a/libmeminfo/pageacct.cpp
+++ b/libmeminfo/pageacct.cpp
@@ -138,5 +138,18 @@
return !!(idle_bits & (1ULL << (pfn % 64)));
}
+// Public methods
+bool page_present(uint64_t pagemap_val) {
+ return PAGE_PRESENT(pagemap_val);
+}
+
+bool page_swapped(uint64_t pagemap_val) {
+ return PAGE_SWAPPED(pagemap_val);
+}
+
+uint64_t page_pfn(uint64_t pagemap_val) {
+ return PAGE_PFN(pagemap_val);
+}
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index d6332a3..1df03b2 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -199,6 +199,33 @@
return swap_offsets_;
}
+bool ProcMemInfo::PageMap(const Vma& vma, std::vector<uint64_t>* pagemap) {
+ pagemap->clear();
+ std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
+ ::android::base::unique_fd pagemap_fd(
+ TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (pagemap_fd < 0) {
+ PLOG(ERROR) << "Failed to open " << pagemap_file;
+ return false;
+ }
+
+ uint64_t nr_pages = (vma.end - vma.start) / getpagesize();
+ pagemap->reserve(nr_pages);
+
+ uint64_t idx = vma.start / getpagesize();
+ uint64_t last = idx + nr_pages;
+ uint64_t val;
+ for (; idx < last; idx++) {
+ if (pread64(pagemap_fd, &val, sizeof(uint64_t), idx * sizeof(uint64_t)) < 0) {
+ PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
+ return false;
+ }
+ pagemap->emplace_back(val);
+ }
+
+ return true;
+}
+
bool ProcMemInfo::ReadMaps(bool get_wss) {
// Each object reads /proc/<pid>/maps only once. This is done to make sure programs that are
// running for the lifetime of the system can recycle the objects and don't have to
diff --git a/libmeminfo/sysmeminfo.cpp b/libmeminfo/sysmeminfo.cpp
index 8fd18d0..5cfa6c3 100644
--- a/libmeminfo/sysmeminfo.cpp
+++ b/libmeminfo/sysmeminfo.cpp
@@ -79,36 +79,8 @@
});
}
-uint64_t SysMemInfo::ReadVmallocInfo(const std::string& path) {
- uint64_t vmalloc_total = 0;
- auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
- if (fp == nullptr) {
- return vmalloc_total;
- }
-
- char line[1024];
- while (fgets(line, 1024, fp.get()) != nullptr) {
- // We are looking for lines like
- // 0x0000000000000000-0x0000000000000000 12288 drm_property_create_blob+0x44/0xec pages=2
- // vmalloc 0x0000000000000000-0x0000000000000000 8192
- // wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc Notice that if the caller is
- // coming from a module, the kernel prints and extra "[module_name]" after the address and
- // the symbol of the call site. This means we can't use the old sscanf() method of getting
- // the # of pages.
- char* p_start = strstr(line, "pages=");
- if (p_start == nullptr) {
- // we didn't find anything
- continue;
- }
-
- p_start = strtok(p_start, " ");
- long nr_pages;
- if (sscanf(p_start, "pages=%ld", &nr_pages) == 1) {
- vmalloc_total += (nr_pages * getpagesize());
- }
- }
-
- return vmalloc_total;
+uint64_t SysMemInfo::ReadVmallocInfo() {
+ return ::android::meminfo::ReadVmallocInfo();
}
// TODO: Delete this function if it can't match up with the c-like implementation below.
@@ -263,5 +235,41 @@
return false;
}
+// Public methods
+uint64_t ReadVmallocInfo(const std::string& path) {
+ uint64_t vmalloc_total = 0;
+ auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+ if (fp == nullptr) {
+ return vmalloc_total;
+ }
+
+ char* line = nullptr;
+ size_t line_alloc = 0;
+ while (getline(&line, &line_alloc, fp.get()) > 0) {
+ // We are looking for lines like
+ //
+ // 0x0000000000000000-0x0000000000000000 12288 drm_property_create_blob+0x44/0xec pages=2 vmalloc
+ // 0x0000000000000000-0x0000000000000000 8192 wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc
+ //
+ // Notice that if the caller is coming from a module, the kernel prints and extra
+ // "[module_name]" after the address and the symbol of the call site. This means we can't
+ // use the old sscanf() method of getting the # of pages.
+ char* p_start = strstr(line, "pages=");
+ if (p_start == nullptr) {
+ // we didn't find anything
+ continue;
+ }
+
+ uint64_t nr_pages;
+ if (sscanf(p_start, "pages=%" SCNu64 "", &nr_pages) == 1) {
+ vmalloc_total += (nr_pages * getpagesize());
+ }
+ }
+
+ free(line);
+
+ return vmalloc_total;
+}
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/tools/Android.bp b/libmeminfo/tools/Android.bp
index c852bbb..24054c6 100644
--- a/libmeminfo/tools/Android.bp
+++ b/libmeminfo/tools/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
cc_binary {
- name: "librank2",
+ name: "librank",
cflags: [
"-Wall",
"-Werror",
@@ -27,7 +27,7 @@
}
cc_binary {
- name: "procmem2",
+ name: "procmem",
cflags: [
"-Wall",
"-Werror",
@@ -41,7 +41,7 @@
}
cc_binary {
- name: "procrank2",
+ name: "procrank",
cflags: [
"-Wall",
"-Werror",
@@ -55,7 +55,7 @@
}
cc_binary {
- name: "showmap2",
+ name: "showmap",
cflags: [
"-Wall",
"-Werror",
diff --git a/libmemtrack/.clang-format b/libmemtrack/.clang-format
new file mode 120000
index 0000000..1af4f51
--- /dev/null
+++ b/libmemtrack/.clang-format
@@ -0,0 +1 @@
+../.clang-format-4
\ No newline at end of file
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 0955633..4e4554a 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -28,10 +28,11 @@
cc_binary {
name: "memtrack_test",
- srcs: ["memtrack_test.c"],
+ srcs: ["memtrack_test.cpp"],
+ static_libs: ["libc++fs"],
shared_libs: [
+ "libbase",
"libmemtrack",
- "libpagemap",
],
cflags: [
"-Wall",
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
deleted file mode 100644
index 77c935e..0000000
--- a/libmemtrack/memtrack_test.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <memtrack/memtrack.h>
-
-#include <pagemap/pagemap.h>
-
-#define DIV_ROUND_UP(x,y) (((x) + (y) - 1) / (y))
-
-static int getprocname(pid_t pid, char *buf, int len) {
- char *filename;
- FILE *f;
- int rc = 0;
- static const char* unknown_cmdline = "<unknown>";
-
- if (len <= 0) {
- return -1;
- }
-
- if (asprintf(&filename, "/proc/%d/cmdline", pid) < 0) {
- rc = 1;
- goto exit;
- }
-
- f = fopen(filename, "r");
- if (f == NULL) {
- rc = 2;
- goto releasefilename;
- }
-
- if (fgets(buf, len, f) == NULL) {
- rc = 3;
- goto closefile;
- }
-
-closefile:
- (void) fclose(f);
-releasefilename:
- free(filename);
-exit:
- if (rc != 0) {
- /*
- * The process went away before we could read its process name. Try
- * to give the user "<unknown>" here, but otherwise they get to look
- * at a blank.
- */
- if (strlcpy(buf, unknown_cmdline, (size_t)len) >= (size_t)len) {
- rc = 4;
- }
- }
-
- return rc;
-}
-
-int main(int argc, char *argv[])
-{
- int ret;
- pm_kernel_t *ker;
- size_t num_procs;
- pid_t *pids;
- struct memtrack_proc *p;
- size_t i;
-
- (void)argc;
- (void)argv;
-
- ret = pm_kernel_create(&ker);
- if (ret) {
- fprintf(stderr, "Error creating kernel interface -- "
- "does this kernel have pagemap?\n");
- exit(EXIT_FAILURE);
- }
-
- ret = pm_kernel_pids(ker, &pids, &num_procs);
- if (ret) {
- fprintf(stderr, "Error listing processes.\n");
- exit(EXIT_FAILURE);
- }
-
- p = memtrack_proc_new();
- if (ret) {
- fprintf(stderr, "failed to create memtrack process handle\n");
- exit(EXIT_FAILURE);
- }
-
- for (i = 0; i < num_procs; i++) {
- pid_t pid = pids[i];
- char cmdline[256];
- size_t v1;
- size_t v2;
- size_t v3;
- size_t v4;
- size_t v5;
- size_t v6;
-
- getprocname(pid, cmdline, (int)sizeof(cmdline));
-
- ret = memtrack_proc_get(p, pid);
- if (ret) {
- fprintf(stderr, "failed to get memory info for pid %d: %s (%d)\n",
- pid, strerror(-ret), ret);
- continue;
- }
-
- v1 = DIV_ROUND_UP(memtrack_proc_graphics_total(p), 1024);
- v2 = DIV_ROUND_UP(memtrack_proc_graphics_pss(p), 1024);
- v3 = DIV_ROUND_UP(memtrack_proc_gl_total(p), 1024);
- v4 = DIV_ROUND_UP(memtrack_proc_gl_pss(p), 1024);
- v5 = DIV_ROUND_UP(memtrack_proc_other_total(p), 1024);
- v6 = DIV_ROUND_UP(memtrack_proc_other_pss(p), 1024);
-
- if (v1 | v2 | v3 | v4 | v5 | v6) {
- printf("%5d %6zu %6zu %6zu %6zu %6zu %6zu %s\n", pid,
- v1, v2, v3, v4, v5, v6, cmdline);
- }
- }
-
- memtrack_proc_destroy(p);
-
- return 0;
-}
diff --git a/libmemtrack/memtrack_test.cpp b/libmemtrack/memtrack_test.cpp
new file mode 100644
index 0000000..aeeaf24
--- /dev/null
+++ b/libmemtrack/memtrack_test.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <filesystem>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <memtrack/memtrack.h>
+
+#define DIV_ROUND_UP(x, y) (((x) + (y)-1) / (y))
+
+static void getprocname(pid_t pid, std::string* name) {
+ std::string fname = ::android::base::StringPrintf("/proc/%d/cmdline", pid);
+ if (!::android::base::ReadFileToString(fname, name)) {
+ fprintf(stderr, "Failed to read cmdline from: %s\n", fname.c_str());
+ *name = "<unknown>";
+ }
+}
+
+int main(int /* argc */, char** /* argv */) {
+ int ret;
+ struct memtrack_proc* p;
+ std::vector<pid_t> pids;
+
+ p = memtrack_proc_new();
+ if (p == nullptr) {
+ fprintf(stderr, "failed to create memtrack process handle\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (auto& de : std::filesystem::directory_iterator("/proc")) {
+ if (!std::filesystem::is_directory(de.status())) {
+ continue;
+ }
+
+ pid_t pid;
+ if (!::android::base::ParseInt(de.path().filename().string(), &pid)) {
+ continue;
+ }
+ pids.emplace_back(pid);
+ }
+
+ for (auto& pid : pids) {
+ size_t v1;
+ size_t v2;
+ size_t v3;
+ size_t v4;
+ size_t v5;
+ size_t v6;
+ std::string cmdline;
+
+ getprocname(pid, &cmdline);
+
+ ret = memtrack_proc_get(p, pid);
+ if (ret) {
+ fprintf(stderr, "failed to get memory info for pid %d: %s (%d)\n", pid, strerror(-ret),
+ ret);
+ continue;
+ }
+
+ v1 = DIV_ROUND_UP(memtrack_proc_graphics_total(p), 1024);
+ v2 = DIV_ROUND_UP(memtrack_proc_graphics_pss(p), 1024);
+ v3 = DIV_ROUND_UP(memtrack_proc_gl_total(p), 1024);
+ v4 = DIV_ROUND_UP(memtrack_proc_gl_pss(p), 1024);
+ v5 = DIV_ROUND_UP(memtrack_proc_other_total(p), 1024);
+ v6 = DIV_ROUND_UP(memtrack_proc_other_pss(p), 1024);
+
+ if (v1 | v2 | v3 | v4 | v5 | v6) {
+ fprintf(stdout, "%5d %6zu %6zu %6zu %6zu %6zu %6zu %s\n", pid, v1, v2, v3, v4, v5, v6,
+ cmdline.c_str());
+ }
+ }
+
+ memtrack_proc_destroy(p);
+
+ return ret;
+}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 0a808ce..ad967db 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -119,6 +119,8 @@
// This list includes all directories app is allowed to access this way.
static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
+static constexpr const char* kApexPath = "/apex/";
+
static bool is_debuggable() {
char debuggable[PROP_VALUE_MAX];
property_get("ro.debuggable", debuggable, "0");
@@ -623,14 +625,51 @@
return nullptr;
}
+#if defined(__ANDROID__)
+static android_namespace_t* FindExportedNamespace(const char* caller_location) {
+ std::string location = caller_location;
+ // Lots of implicit assumptions here: we expect `caller_location` to be of the form:
+ // /apex/com.android...modulename/...
+ //
+ // And we extract from it 'modulename', which is the name of the linker namespace.
+ if (android::base::StartsWith(location, kApexPath)) {
+ size_t slash_index = location.find_first_of('/', strlen(kApexPath));
+ LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
+ "Error finding namespace of apex: no slash in path %s", caller_location);
+ size_t dot_index = location.find_last_of('.', slash_index);
+ LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
+ "Error finding namespace of apex: no dot in apex name %s", caller_location);
+ std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
+ android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
+ LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
+ "Error finding namespace of apex: no namespace called %s", name.c_str());
+ return boot_namespace;
+ }
+ return nullptr;
+}
+#endif
+
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
jobject class_loader, const char* caller_location, jstring library_path,
bool* needs_native_bridge, char** error_msg) {
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
- UNUSED(caller_location);
if (class_loader == nullptr) {
*needs_native_bridge = false;
+ if (caller_location != nullptr) {
+ android_namespace_t* boot_namespace = FindExportedNamespace(caller_location);
+ if (boot_namespace != nullptr) {
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = boot_namespace,
+ };
+ void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
+ if (handle == nullptr) {
+ *error_msg = strdup(dlerror());
+ }
+ return handle;
+ }
+ }
void* handle = dlopen(path, RTLD_NOW);
if (handle == nullptr) {
*error_msg = strdup(dlerror());
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 57207de..0dd95cf 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -144,7 +144,6 @@
bool return_address_attempt = false;
bool adjust_pc = false;
- std::unique_ptr<JitDebug> jit_debug;
for (; frames_.size() < max_frames_;) {
uint64_t cur_pc = regs_->pc();
uint64_t cur_sp = regs_->sp();
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index 0336173..67a9640 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -40,7 +40,7 @@
public:
explicit DexFiles(std::shared_ptr<Memory>& memory);
DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
- ~DexFiles();
+ virtual ~DexFiles();
DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index f64b04f..8b7b4b5 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -38,7 +38,7 @@
public:
explicit JitDebug(std::shared_ptr<Memory>& memory);
JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
- ~JitDebug();
+ virtual ~JitDebug();
Elf* GetElf(Maps* maps, uint64_t pc);
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index ab239c1..f4788d7 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -72,7 +72,7 @@
frames_.reserve(max_frames);
}
- ~Unwinder() = default;
+ virtual ~Unwinder() = default;
void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
@@ -124,7 +124,7 @@
class UnwinderFromPid : public Unwinder {
public:
UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
- ~UnwinderFromPid() = default;
+ virtual ~UnwinderFromPid() = default;
bool Init(ArchEnum arch);
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index a91bd95..c747eab 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -47,6 +47,7 @@
enum TestTypeEnum : uint8_t {
TEST_TYPE_LOCAL_UNWINDER = 0,
TEST_TYPE_LOCAL_UNWINDER_FROM_PID,
+ TEST_TYPE_LOCAL_WAIT_FOR_FINISH,
TEST_TYPE_REMOTE,
TEST_TYPE_REMOTE_WITH_INVALID_CALL,
};
@@ -79,7 +80,10 @@
extern "C" void SignalInnerFunction() {
g_signal_ready_for_remote = true;
- while (!g_finish.load()) {
+ // Avoid any function calls because not every instruction will be
+ // unwindable.
+ // This method of looping is only used when testing a remote unwind.
+ while (true) {
}
}
@@ -134,6 +138,11 @@
// off. If this doesn't happen, then all of the calls will be optimized
// away.
extern "C" void InnerFunction(TestTypeEnum test_type) {
+ if (test_type == TEST_TYPE_LOCAL_WAIT_FOR_FINISH) {
+ while (!g_finish.load()) {
+ }
+ return;
+ }
if (test_type == TEST_TYPE_REMOTE || test_type == TEST_TYPE_REMOTE_WITH_INVALID_CALL) {
g_ready_for_remote = true;
g_ready = true;
@@ -141,7 +150,10 @@
void (*crash_func)() = nullptr;
crash_func();
}
- while (!g_finish.load()) {
+ // Avoid any function calls because not every instruction will be
+ // unwindable.
+ // This method of looping is only used when testing a remote unwind.
+ while (true) {
}
return;
}
@@ -271,7 +283,7 @@
std::atomic_int tid(0);
std::thread thread([&]() {
tid = syscall(__NR_gettid);
- OuterFunction(TEST_TYPE_REMOTE);
+ OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
});
struct sigaction act, oldact;
diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index 4432f9e..9ee7869 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -115,7 +115,7 @@
uint32_t header_size;
} __attribute__((packed));
-/* When the boot image header has a version of 1, the structure of the boot
+/* When the boot image header has a version of 2, the structure of the boot
* image is as follows:
*
* +---------------------+
@@ -129,17 +129,21 @@
* +---------------------+
* | recovery dtbo/acpio | p pages
* +---------------------+
+ * | dtb | q pages
+ * +---------------------+
+
* n = (kernel_size + page_size - 1) / page_size
* m = (ramdisk_size + page_size - 1) / page_size
* o = (second_size + page_size - 1) / page_size
* p = (recovery_dtbo_size + page_size - 1) / page_size
+ * q = (dtb_size + page_size - 1) / page_size
*
* 0. all entities are page_size aligned in flash
- * 1. kernel and ramdisk are required (size != 0)
+ * 1. kernel, ramdisk and DTB are required (size != 0)
* 2. recovery_dtbo/recovery_acpio is required for recovery.img in non-A/B
* devices(recovery_dtbo_size != 0)
* 3. second is optional (second_size == 0 -> no second)
- * 4. load each element (kernel, ramdisk, second) at
+ * 4. load each element (kernel, ramdisk, second, dtb) at
* the specified physical address (kernel_addr, etc)
* 5. If booting to recovery mode in a non-A/B device, extract recovery
* dtbo/acpio and apply the correct set of overlays on the base device tree
@@ -150,3 +154,7 @@
* 8. if second_size != 0: jump to second_addr
* else: jump to kernel_addr
*/
+struct boot_img_hdr_v2 : public boot_img_hdr_v1 {
+ uint32_t dtb_size; /* size in bytes for DTB image */
+ uint64_t dtb_addr; /* physical load address for DTB image */
+} __attribute__((packed));
diff --git a/mkbootimg/mkbootimg.py b/mkbootimg/mkbootimg.py
index 2eb2bab..859b1e4 100644
--- a/mkbootimg/mkbootimg.py
+++ b/mkbootimg/mkbootimg.py
@@ -85,6 +85,8 @@
if args.header_version > 0:
update_sha(sha, args.recovery_dtbo)
+ if args.header_version > 1:
+ update_sha(sha, args.dtb)
img_id = pack('32s', sha.digest())
@@ -99,6 +101,10 @@
args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
args.output.write(pack('I', args.output.tell() + 4)) # size of boot header
+
+ if args.header_version > 1:
+ args.output.write(pack('I', filesize(args.dtb))) # size in bytes
+ args.output.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
pad_file(args.output, args.pagesize)
return img_id
@@ -161,6 +167,7 @@
required=True)
parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
+ parser.add_argument('--dtb', help='path to dtb', type=FileType('rb'))
recovery_dtbo_group = parser.add_mutually_exclusive_group()
recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO', type=FileType('rb'))
recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
@@ -172,6 +179,8 @@
parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000)
parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
default=0x00f00000)
+ parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)
+
parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
default=0)
parser.add_argument('--os_patch_level', help='operating system patch level',
@@ -196,6 +205,8 @@
if args.header_version > 0:
write_padded_file(args.output, args.recovery_dtbo, args.pagesize)
+ if args.header_version > 1:
+ write_padded_file(args.output, args.dtb, args.pagesize)
def main():
args = parse_cmdline()
diff --git a/mkbootimg/unpack_bootimg.py b/mkbootimg/unpack_bootimg.py
old mode 100644
new mode 100755
index c37acd5..6b5d5d0
--- a/mkbootimg/unpack_bootimg.py
+++ b/mkbootimg/unpack_bootimg.py
@@ -15,7 +15,7 @@
"""unpacks the bootimage.
-Extracts the kernel, ramdisk, second bootloader and recovery dtbo images.
+Extracts the kernel, ramdisk, second bootloader, dtb and recovery dtbo images.
"""
from __future__ import print_function
@@ -82,6 +82,14 @@
print('boot header size: %s' % boot_header_size)
else:
recovery_dtbo_size = 0
+ if version > 1:
+ dtb_size = unpack('I', args.boot_img.read(4))[0]
+ print('dtb size: %s' % dtb_size)
+ dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
+ print('dtb address: %s' % dtb_load_address)
+ else:
+ dtb_size = 0
+
# The first page contains the boot header
num_header_pages = 1
@@ -103,6 +111,15 @@
if recovery_dtbo_size > 0:
image_info_list.append((recovery_dtbo_offset, recovery_dtbo_size,
'recovery_dtbo'))
+ if dtb_size > 0:
+ num_second_pages = get_number_of_pages(second_size, page_size)
+ num_recovery_dtbo_pages = get_number_of_pages(recovery_dtbo_size, page_size)
+ dtb_offset = page_size * (
+ num_header_pages + num_kernel_pages + num_ramdisk_pages + num_second_pages +
+ num_recovery_dtbo_pages
+ )
+
+ image_info_list.append((dtb_offset, dtb_size, 'dtb'))
for image_info in image_info_list:
extract_image(image_info[0], image_info[1], args.boot_img,
@@ -113,7 +130,7 @@
"""parse command line arguments"""
parser = ArgumentParser(
description='Unpacks boot.img/recovery.img, extracts the kernel,'
- 'ramdisk, second bootloader and recovery dtbo')
+ 'ramdisk, second bootloader, recovery dtbo and dtb')
parser.add_argument(
'--boot_img',
help='path to boot image',
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 85c7e9e..1871ca7 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -129,6 +129,19 @@
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
+# Start of runtime APEX compatibility.
+# Keeping the appearance of files/dirs having old locations for apps that have
+# come to rely on them.
+
+# http://b/121248172 - create a link from /system/usr/icu to
+# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
+# A symlink can't overwrite a directory and the /system/usr/icu directory once
+# existed so the required structure must be created whatever we find.
+LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
+LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
+
+# End of runtime APEX compatibilty.
+
ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
else
@@ -253,14 +266,11 @@
include $(LOCAL_PATH)/update_and_install_ld_config.mk
endef
-# For VNDK snapshot versions prior to 28, ld.config.txt is installed from the
-# prebuilt under /prebuilts/vndk
vndk_snapshots := $(wildcard prebuilts/vndk/*)
supported_vndk_snapshot_versions := \
- $(strip $(foreach ver,$(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)),\
- $(if $(call math_gt_or_eq,$(ver),28),$(ver),)))
-$(eval $(foreach ver,$(supported_vndk_snapshot_versions),\
- $(call build_versioned_ld_config,$(ver))))
+ $(strip $(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)))
+$(foreach ver,$(supported_vndk_snapshot_versions),\
+ $(eval $(call build_versioned_ld_config,$(ver))))
vndk_snapshots :=
supported_vndk_snapshot_versions :=
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 2dda648..54e7c7e 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -28,7 +28,7 @@
dir.postinstall = /postinstall
[system]
-additional.namespaces = runtime,sphal,vndk,rs
+additional.namespaces = runtime,conscrypt,media,sphal,vndk,rs
###############################################################################
# "default" namespace
@@ -109,7 +109,11 @@
# Keep in sync with ld.config.txt in the com.android.runtime APEX.
namespace.default.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
namespace.default.link.runtime.shared_libs = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativebridge.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -123,12 +127,46 @@
# Keep in sync with ld.config.txt in the com.android.runtime APEX.
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
# when it exists.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
+# "media" APEX namespace
+#
+# This namespace is for libraries within the media APEX.
+###############################################################################
+namespace.media.isolated = true
+namespace.media.visible = true
+
+namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
+
+namespace.media.links = default
+namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.media.link.default.shared_libs += libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# "conscrypt" APEX namespace
+#
+# This namespace is for libraries within the conscrypt APEX.
+###############################################################################
+namespace.conscrypt.isolated = true
+namespace.conscrypt.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.links = default
+namespace.conscrypt.link.default.shared_libs = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
+
+###############################################################################
# "sphal" namespace
#
# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
@@ -280,7 +318,7 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-additional.namespaces = system,vndk
+additional.namespaces = runtime,system,vndk
###############################################################################
# "default" namespace
@@ -317,6 +355,20 @@
namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = system
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.system.allow_all_shared_libs = true
+
+###############################################################################
# "vndk" namespace
#
# This namespace is where VNDK and VNDK-SP libraries are loaded for
@@ -373,6 +425,9 @@
namespace.system.asan.search.paths += /data/asan/product_services/${LIB}
namespace.system.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
+namespace.system.links = runtime
+namespace.system.link.runtime.shared_libs = libdexfile_external.so
+
###############################################################################
# Namespace config for binaries under /postinstall.
# Only default namespace is defined and default has no directories
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 33b4698..39f69ca 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -28,7 +28,7 @@
dir.postinstall = /postinstall
[system]
-additional.namespaces = runtime,sphal,vndk,rs
+additional.namespaces = runtime,conscrypt,media,sphal,vndk,rs
###############################################################################
# "default" namespace
@@ -55,9 +55,14 @@
namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the platform namespace in the com.android.runtime APEX
+# ld.config.txt.
namespace.default.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
namespace.default.link.runtime.shared_libs = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -68,14 +73,49 @@
###############################################################################
namespace.runtime.isolated = true
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the default namespace in the com.android.runtime APEX
+# ld.config.txt.
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
# when it exists.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
+# "media" APEX namespace
+#
+# This namespace is for libraries within the media APEX.
+###############################################################################
+namespace.media.isolated = true
+namespace.media.visible = true
+
+namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
+
+namespace.media.links = default
+namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.media.link.default.shared_libs += libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# "conscrypt" APEX namespace
+#
+# This namespace is for libraries within the conscrypt APEX.
+###############################################################################
+namespace.conscrypt.isolated = true
+namespace.conscrypt.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.links = default
+namespace.conscrypt.link.default.shared_libs = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
+
+###############################################################################
# "sphal" namespace
#
# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
@@ -221,6 +261,8 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
+additional.namespaces = runtime
+
namespace.default.isolated = false
namespace.default.search.paths = /odm/${LIB}
@@ -260,6 +302,23 @@
namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
###############################################################################
# Namespace config for binaries under /postinstall.
# Only default namespace is defined and default has no directories
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index ac87979..e8c5d8e 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -4,6 +4,8 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
+ updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index a535846..9c7e807 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -4,6 +4,8 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
+ updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
@@ -19,5 +21,7 @@
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
+ socket blastula_pool_secondary stream 660 root system
+ updatable
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 6fc810b..9908c99 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -4,6 +4,8 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
+ updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 7ddd52e..0b5edff 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -4,6 +4,8 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
+ updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
@@ -19,5 +21,7 @@
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
+ socket blastula_pool_secondary stream 660 root system
+ updatable
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks