Merge "Move DwarfCfaInfo::kTable from data.rel.ro to rodata"
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index 6cc274b..e6fefda 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -38,7 +38,8 @@
// The cost of sending two strings outweighs the cost of formatting.
// "adb sync" performance is affected by this.
- return WriteFdFmt(fd, "%04x%.*s", length, length, s.c_str());
+ auto str = android::base::StringPrintf("%04x", length).append(s);
+ return WriteFdExactly(fd, str);
}
bool ReadProtocolString(int fd, std::string* s, std::string* error) {
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 079a975..054cbac 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -331,11 +331,6 @@
error_exit("Attempting to use streaming install on unsupported device");
}
- if (use_fastdeploy == true && is_reinstall == false) {
- printf("Fast Deploy is only available with -r.\n");
- use_fastdeploy = false;
- }
-
if (use_fastdeploy == true && get_device_api_level() < kFastDeployMinApi) {
printf("Fast Deploy is only compatible with devices of API version %d or higher, "
"ignoring.\n",
@@ -350,10 +345,17 @@
passthrough_argv.push_back(argv[i]);
}
}
+ if (passthrough_argv.size() < 2) {
+ error_exit("install requires an apk argument");
+ }
if (use_fastdeploy == true) {
fastdeploy_set_local_agent(use_localagent);
update_agent(agent_update_strategy);
+
+ // The last argument must be the APK file
+ const char* file = passthrough_argv.back();
+ use_fastdeploy = find_package(file);
}
switch (installMode) {
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index c8e834e..8676214 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -154,8 +154,8 @@
" --instant: cause the app to be installed as an ephemeral install app\n"
" --no-streaming: always push APK to device and invoke Package Manager as separate steps\n"
" --streaming: force streaming APK directly into Package Manager\n"
- " --fastdeploy: use fast deploy (only valid with -r)\n"
- " --no-fastdeploy: prevent use of fast deploy (only valid with -r)\n"
+ " --fastdeploy: use fast deploy\n"
+ " --no-fastdeploy: prevent use of fast deploy\n"
" --force-agent: force update of deployment agent when using fast deploy\n"
" --date-check-agent: update deployment agent when local version is newer and using fast deploy\n"
" --version-check-agent: update deployment agent when local version has different version code and using fast deploy\n"
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index e82f15a..f4e8664 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -16,6 +16,7 @@
#include "fastdeploy.h"
+#include <string.h>
#include <algorithm>
#include <array>
#include <memory>
@@ -31,7 +32,7 @@
#include "adb_utils.h"
-static constexpr long kRequiredAgentVersion = 0x00000001;
+static constexpr long kRequiredAgentVersion = 0x00000002;
static constexpr const char* kDeviceAgentPath = "/data/local/tmp/";
@@ -313,9 +314,16 @@
std::vector<unsigned char> applyErrorBuffer;
std::string argsString;
+ bool rSwitchPresent = false;
for (int i = 0; i < argc; i++) {
argsString.append(argv[i]);
argsString.append(" ");
+ if (!strcmp(argv[i], "-r")) {
+ rSwitchPresent = true;
+ }
+ }
+ if (!rSwitchPresent) {
+ argsString.append("-r");
}
std::string applyPatchCommand =
@@ -326,3 +334,9 @@
error_exit("Executing %s returned %d", applyPatchCommand.c_str(), returnCode);
}
}
+
+bool find_package(const char* apkPath) {
+ const std::string findCommand =
+ "/data/local/tmp/deployagent find " + get_packagename_from_apk(apkPath);
+ return !send_shell_command(findCommand);
+}
diff --git a/adb/client/fastdeploy.h b/adb/client/fastdeploy.h
index a6b10d3..7b7f2ec 100644
--- a/adb/client/fastdeploy.h
+++ b/adb/client/fastdeploy.h
@@ -32,3 +32,4 @@
void apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath);
void install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv);
std::string get_patch_path(const char* apkPath);
+bool find_package(const char* apkPath);
diff --git a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
index 17845e2..2d3b135 100644
--- a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
+++ b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
@@ -35,7 +35,7 @@
public final class DeployAgent {
private static final int BUFFER_SIZE = 128 * 1024;
- private static final int AGENT_VERSION = 0x00000001;
+ private static final int AGENT_VERSION = 0x00000002;
public static void main(String[] args) {
int exitCode = 0;
@@ -53,6 +53,15 @@
String packageName = args[1];
extractMetaData(packageName);
+ } else if (commandString.equals("find")) {
+ if (args.length != 2) {
+ showUsage(1);
+ }
+
+ String packageName = args[1];
+ if (getFilenameFromPackageName(packageName) == null) {
+ exitCode = 3;
+ }
} else if (commandString.equals("apply")) {
if (args.length < 4) {
showUsage(1);
@@ -112,6 +121,7 @@
"usage: deployagent <command> [<args>]\n\n" +
"commands:\n" +
"version get the version\n" +
+ "find PKGNAME return zero if package found, else non-zero\n" +
"extract PKGNAME extract an installed package's metadata\n" +
"apply PKGNAME PATCHFILE [-o|-pm] apply a patch from PATCHFILE (- for stdin) to an installed package\n" +
" -o <FILE> directs output to FILE, default or - for stdout\n" +
@@ -134,7 +144,7 @@
return null;
}
- private static File getFileFromPackageName(String packageName) throws IOException {
+ private static String getFilenameFromPackageName(String packageName) throws IOException {
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append("pm list packages -f " + packageName);
@@ -153,10 +163,19 @@
int equalsIndex = line.lastIndexOf(packageSuffix);
String fileName =
line.substring(packageIndex + packagePrefix.length(), equalsIndex);
- return new File(fileName);
+ return fileName;
}
}
- throw new IOException("package not found");
+ return null;
+ }
+
+ private static File getFileFromPackageName(String packageName) throws IOException {
+ String filename = getFilenameFromPackageName(packageName);
+ if (filename == null) {
+ // Should not happen (function is only called when we know the package exists)
+ throw new IOException("package not found");
+ }
+ return new File(filename);
}
private static void extractMetaData(String packageName) throws IOException {
diff --git a/base/Android.bp b/base/Android.bp
index 741664b..b0181aa 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -20,6 +20,7 @@
"-Wall",
"-Werror",
"-Wextra",
+ "-D_FILE_OFFSET_BITS=64",
],
}
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index d9fae52..5167481 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -116,14 +116,21 @@
"libdebuggerd",
"libbacktrace",
"libunwindstack",
- "libdexfile",
+ "libdexfile", // libunwindstack dependency
+ "libdexfile_external", // libunwindstack dependency
+ "libdexfile_support", // libunwindstack dependency
"liblzma",
"libcutils",
],
target: {
recovery: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- exclude_static_libs: ["libdexfile"],
+ exclude_static_libs: [
+ "libartbase",
+ "libdexfile",
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
},
},
@@ -170,12 +177,22 @@
static_libs: [
"libbacktrace",
+ "libdexfile_external", // libunwindstack dependency
+ "libdexfile_support", // libunwindstack dependency
"libunwindstack",
"liblzma",
"libbase",
"libcutils",
"liblog",
],
+ target: {
+ recovery: {
+ exclude_static_libs: [
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
+ },
+ },
}
cc_test {
@@ -216,6 +233,8 @@
static_libs: [
"libdebuggerd",
+ "libdexfile_external", // libunwindstack dependency
+ "libdexfile_support", // libunwindstack dependency
"libunwindstack",
],
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 421ce43..d24c887 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -15,6 +15,7 @@
*/
#include <stdlib.h>
+#include <time.h>
#include <memory>
#include <string>
@@ -494,3 +495,10 @@
expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}
+
+TEST_F(TombstoneTest, dump_timestamp) {
+ setenv("TZ", "UTC", 1);
+ tzset();
+ dump_timestamp(&log_, 0);
+ ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 1179263..b20014f 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -78,6 +78,15 @@
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
+static void dump_timestamp(log_t* log, time_t time) {
+ struct tm tm;
+ localtime_r(&time, &tm);
+
+ char buf[strlen("1970-01-01 00:00:00+0830") + 1];
+ strftime(buf, sizeof(buf), "%F %T%z", &tm);
+ _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
+}
+
static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
std::string cause;
if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
@@ -654,6 +663,7 @@
_LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_header_info(&log);
+ dump_timestamp(&log, time(nullptr));
auto it = threads.find(target_thread);
if (it == threads.end()) {
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 71d2a1d..e91598d 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -329,12 +329,14 @@
MetadataBuilder* operator->() const { return builder_.get(); }
private:
+ FastbootDevice* device_;
std::string super_device_;
uint32_t slot_number_;
std::unique_ptr<MetadataBuilder> builder_;
};
-PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name) {
+PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name)
+ : device_(device) {
std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
slot_number_ = SlotNumberForSlotSuffix(slot_suffix);
auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number_));
@@ -350,7 +352,7 @@
if (!metadata) {
return false;
}
- return UpdateAllPartitionMetadata(super_device_, *metadata.get());
+ return UpdateAllPartitionMetadata(device_, super_device_, *metadata.get());
}
bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index fbba631..f737405 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -143,6 +143,11 @@
return device->WriteFail("Data is not a valid logical partition metadata image");
}
+ if (!FindPhysicalPartition(super_name)) {
+ return device->WriteFail("Cannot find " + super_name +
+ ", build may be missing broken or missing boot_devices");
+ }
+
// If we are unable to read the existing metadata, then the super partition
// is corrupt. In this case we reflash the whole thing using the provided
// image.
@@ -184,7 +189,7 @@
}
// Write the new table to every metadata slot.
- if (!UpdateAllPartitionMetadata(super_name, *new_metadata.get())) {
+ if (!UpdateAllPartitionMetadata(device, super_name, *new_metadata.get())) {
return device->WriteFail("Unable to write new partition table");
}
fs_mgr_overlayfs_teardown();
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 2ae9ac5..2ebd57d 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -200,10 +200,16 @@
return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
}
-bool UpdateAllPartitionMetadata(const std::string& super_name,
+bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
const android::fs_mgr::LpMetadata& metadata) {
+ size_t num_slots = 1;
+ auto boot_control_hal = device->boot_control_hal();
+ if (boot_control_hal) {
+ num_slots = boot_control_hal->getNumberSlots();
+ }
+
bool ok = true;
- for (size_t i = 0; i < metadata.geometry.metadata_slot_count; i++) {
+ for (size_t i = 0; i < num_slots; i++) {
ok &= UpdatePartitionTable(super_name, metadata, i);
}
return ok;
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
index 4c6aa07..bfeeb74 100644
--- a/fastboot/device/utility.h
+++ b/fastboot/device/utility.h
@@ -68,5 +68,5 @@
bool GetDeviceLockStatus();
// Update all copies of metadata.
-bool UpdateAllPartitionMetadata(const std::string& super_name,
+bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
const android::fs_mgr::LpMetadata& metadata);
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index ac138a3..824511e 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -40,6 +40,7 @@
"fs_mgr_verity.cpp",
"fs_mgr_dm_linear.cpp",
"fs_mgr_overlayfs.cpp",
+ "fs_mgr_roots.cpp",
"fs_mgr_vendor_overlay.cpp",
],
shared_libs: [
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index fbb5f5d..960410c 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -83,18 +83,19 @@
-------
- Space used in the backing storage is on a file by file basis
- and will require more space than if updated in place.
+ and will require more space than if updated in place. As such
+ it is important to be mindful of any wasted space, for instance
+ **BOARD_<partition>IMAGE_PARTITION_RESERVED_SIZE** being defined
+ will have a negative impact on the overall right-sizing of images
+ and thus free dynamic partition space.
- Kernel must have CONFIG_OVERLAY_FS=y and will need to be patched
with "*overlayfs: override_creds=off option bypass creator_cred*"
if higher than 4.6.
- *adb enable-verity* will free up overlayfs and as a bonus the
device will be reverted pristine to before any content was updated.
Update engine does not take advantage of this, will perform a full OTA.
-- Update engine will not run if *fs_mgr_overlayfs_is_setup*() reports
- true as adb remount overrides are incompatable with an OTA for
- multiple reasons.
- NB: This is not a problem for fastbootd or recovery as overrides are
- disabled for those special boot scenarios.
+- Update engine may not run if *fs_mgr_overlayfs_is_setup*() reports
+ true as adb remount overrides are incompatable with an OTA resources.
- For implementation simplicity on retrofit dynamic partition devices,
take the whole alternate super (eg: if "*a*" slot, then the whole of
"*system_b*").
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8757689..943fe10 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -615,7 +615,7 @@
// Sets errno to match the 1st mount failure on failure.
static bool mount_with_alternatives(const Fstab& fstab, int start_idx, int* end_idx,
int* attempted_idx) {
- int i;
+ unsigned long i;
int mount_errno = 0;
bool mounted = false;
@@ -1179,11 +1179,12 @@
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
-int fs_mgr_do_mount_one(const FstabEntry& entry) {
+int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {
// Run fsck if needed
prepare_fs_for_mount(entry.blk_device, entry);
- int ret = __mount(entry.blk_device, entry.mount_point, entry);
+ int ret =
+ __mount(entry.blk_device, mount_point.empty() ? entry.mount_point : mount_point, entry);
if (ret) {
ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
}
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index 733ad55..abece4d 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -81,6 +81,9 @@
bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) {
std::string cmdline;
if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) return false;
+ if (!cmdline.empty() && cmdline.back() == '\n') {
+ cmdline.pop_back();
+ }
return fs_mgr_get_boot_config_from_kernel(cmdline, key, out_val);
}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index d3cd459..e0891eb 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -59,7 +59,7 @@
struct flag_list {
const char *name;
- unsigned int flag;
+ uint64_t flag;
};
static struct flag_list mount_flags[] = {
@@ -116,6 +116,7 @@
{"logical", MF_LOGICAL},
{"checkpoint=block", MF_CHECKPOINT_BLK},
{"checkpoint=fs", MF_CHECKPOINT_FS},
+ {"slotselect_other", MF_SLOTSELECT_OTHER},
{0, 0},
};
@@ -153,7 +154,7 @@
return 0;
}
-static const char* flag_to_encryption_mode(const struct flag_list* list, int flag) {
+static const char* flag_to_encryption_mode(const struct flag_list* list, uint64_t flag) {
const struct flag_list *j;
for (j = list; j->name; ++j) {
@@ -207,11 +208,9 @@
return false;
}
-static int parse_flags(char *flags, struct flag_list *fl,
- struct fs_mgr_flag_values *flag_vals,
- char *fs_options, int fs_options_len)
-{
- int f = 0;
+static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_flag_values* flag_vals,
+ char* fs_options, int fs_options_len) {
+ uint64_t f = 0;
int i;
char *p;
char *savep;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 072da97..7d1159b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -120,6 +120,8 @@
#define MF_CHECKPOINT_FS 0x40000000
#define MF_FIRST_STAGE_MOUNT \
0x80000000
+#define MF_SLOTSELECT_OTHER \
+ 0x100000000
// clang-format on
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_roots.cpp b/fs_mgr/fs_mgr_roots.cpp
new file mode 100644
index 0000000..f44ff41
--- /dev/null
+++ b/fs_mgr/fs_mgr_roots.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2018 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 "fs_mgr/roots.h"
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "fs_mgr.h"
+#include "fs_mgr_dm_linear.h"
+#include "fs_mgr_priv.h"
+
+namespace android {
+namespace fs_mgr {
+
+static constexpr const char* kSystemRoot = "/system";
+
+static bool gDidMapLogicalPartitions = false;
+
+FstabEntry* GetEntryForPath(Fstab* fstab, const std::string& path) {
+ if (path.empty()) return nullptr;
+ std::string str(path);
+ while (true) {
+ auto it = std::find_if(fstab->begin(), fstab->end(),
+ [&str](const auto& entry) { return entry.mount_point == str; });
+ if (it != fstab->end()) return &*it;
+ if (str == "/") break;
+ auto slash = str.find_last_of('/');
+ if (slash == std::string::npos) break;
+ if (slash == 0) {
+ str = "/";
+ } else {
+ str = str.substr(0, slash);
+ }
+ }
+ return nullptr;
+}
+
+enum class MountState {
+ ERROR = -1,
+ NOT_MOUNTED = 0,
+ MOUNTED = 1,
+};
+
+static MountState GetMountState(const std::string& mount_point) {
+ Fstab mounted_fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
+ LERROR << "Failed to scan mounted volumes";
+ return MountState::ERROR;
+ }
+
+ auto mv = std::find_if(
+ mounted_fstab.begin(), mounted_fstab.end(),
+ [&mount_point](const auto& entry) { return entry.mount_point == mount_point; });
+ if (mv != mounted_fstab.end()) {
+ return MountState::MOUNTED;
+ }
+ return MountState::NOT_MOUNTED;
+}
+
+bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_pt) {
+ auto rec = GetEntryForPath(fstab, path);
+ if (rec == nullptr) {
+ LERROR << "unknown volume for path [" << path << "]";
+ return false;
+ }
+ if (rec->fs_type == "ramdisk") {
+ // The ramdisk is always mounted.
+ return true;
+ }
+
+ // If we can't acquire the block device for a logical partition, it likely
+ // was never created. In that case we try to create it.
+ if (rec->fs_mgr_flags.logical && !fs_mgr_update_logical_partition(rec)) {
+ if (gDidMapLogicalPartitions) {
+ LERROR << "Failed to find block device for partition";
+ return false;
+ }
+ std::string super_name = fs_mgr_get_super_partition_name();
+ if (!android::fs_mgr::CreateLogicalPartitions("/dev/block/by-name/" + super_name)) {
+ LERROR << "Failed to create logical partitions";
+ return false;
+ }
+ gDidMapLogicalPartitions = true;
+ if (!fs_mgr_update_logical_partition(rec)) {
+ LERROR << "Failed to find block device for partition";
+ return false;
+ }
+ }
+
+ auto mounted = GetMountState(rec->mount_point);
+ if (mounted == MountState::ERROR) {
+ return false;
+ }
+ if (mounted == MountState::MOUNTED) {
+ return true;
+ }
+
+ const std::string mount_point = mount_pt.empty() ? rec->mount_point : mount_pt;
+
+ static const std::vector<std::string> supported_fs{"ext4", "squashfs", "vfat", "f2fs"};
+ if (std::find(supported_fs.begin(), supported_fs.end(), rec->fs_type) == supported_fs.end()) {
+ LERROR << "unknown fs_type \"" << rec->fs_type << "\" for " << mount_point;
+ return false;
+ }
+
+ int result = fs_mgr_do_mount_one(*rec, mount_point);
+ if (result == -1 && rec->fs_mgr_flags.formattable) {
+ PERROR << "Failed to mount " << mount_point << "; formatting";
+ bool crypt_footer = rec->is_encryptable() && rec->key_loc == "footer";
+ if (fs_mgr_do_format(*rec, crypt_footer) != 0) {
+ PERROR << "Failed to format " << mount_point;
+ return false;
+ }
+ result = fs_mgr_do_mount_one(*rec, mount_point);
+ }
+
+ if (result == -1) {
+ PERROR << "Failed to mount " << mount_point;
+ return false;
+ }
+ return true;
+}
+
+bool EnsurePathUnmounted(Fstab* fstab, const std::string& path) {
+ auto rec = GetEntryForPath(fstab, path);
+ if (rec == nullptr) {
+ LERROR << "unknown volume for path [" << path << "]";
+ return false;
+ }
+ if (rec->fs_type == "ramdisk") {
+ // The ramdisk is always mounted; you can't unmount it.
+ return false;
+ }
+
+ Fstab mounted_fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
+ LERROR << "Failed to scan mounted volumes";
+ return false;
+ }
+
+ auto mounted = GetMountState(rec->mount_point);
+ if (mounted == MountState::ERROR) {
+ return false;
+ }
+ if (mounted == MountState::NOT_MOUNTED) {
+ return true;
+ }
+
+ int result = umount(rec->mount_point.c_str());
+ if (result == -1) {
+ PWARNING << "Failed to umount " << rec->mount_point;
+ return false;
+ }
+ return true;
+}
+
+std::string GetSystemRoot() {
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ LERROR << "Failed to read default fstab";
+ return "";
+ }
+
+ auto it = std::find_if(fstab.begin(), fstab.end(),
+ [](const auto& entry) { return entry.mount_point == kSystemRoot; });
+ if (it == fstab.end()) {
+ return "/";
+ }
+
+ return kSystemRoot;
+}
+
+bool LogicalPartitionsMapped() {
+ return gDidMapLogicalPartitions;
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index efc29bd..3cb718c 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -21,6 +21,19 @@
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
+// https://source.android.com/devices/tech/ota/ab/ab_implement#partitions
+// All partitions that are A/B-ed should be named as follows (slots are always
+// named a, b, etc.): boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
+static std::string other_suffix(const std::string& slot_suffix) {
+ if (slot_suffix == "_a") {
+ return "_b";
+ }
+ if (slot_suffix == "_b") {
+ return "_a";
+ }
+ return "";
+}
+
// Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
// if that parameter does not exist.
std::string fs_mgr_get_slot_suffix() {
@@ -35,7 +48,7 @@
std::string ab_suffix;
for (auto& entry : *fstab) {
- if (!entry.fs_mgr_flags.slot_select) {
+ if (!entry.fs_mgr_flags.slot_select && !entry.fs_mgr_flags.slot_select_other) {
continue;
}
@@ -45,8 +58,10 @@
if (ab_suffix.empty()) return false;
}
- entry.blk_device = entry.blk_device + ab_suffix;
- entry.logical_partition_name = entry.logical_partition_name + ab_suffix;
+ const auto& update_suffix =
+ entry.fs_mgr_flags.slot_select ? ab_suffix : other_suffix(ab_suffix);
+ entry.blk_device = entry.blk_device + update_suffix;
+ entry.logical_partition_name = entry.logical_partition_name + update_suffix;
}
return true;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 814ba46..e87332f 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -69,7 +69,7 @@
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
bool need_cp);
-int fs_mgr_do_mount_one(const FstabEntry& entry);
+int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point = "");
int fs_mgr_do_mount_one(fstab_rec* rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
diff --git a/fs_mgr/include/fs_mgr/roots.h b/fs_mgr/include/fs_mgr/roots.h
new file mode 100644
index 0000000..65c59cf
--- /dev/null
+++ b/fs_mgr/include/fs_mgr/roots.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <fs_mgr.h>
+
+namespace android {
+namespace fs_mgr {
+
+// Finds the volume specified by the given path. fs_mgr_get_entry_for_mount_point() does exact match
+// only, so it attempts the prefixes recursively (e.g. "/cache/recovery/last_log",
+// "/cache/recovery", "/cache", "/" for a given path of "/cache/recovery/last_log") and returns the
+// first match or nullptr.
+FstabEntry* GetEntryForPath(Fstab* fstab, const std::string& path);
+
+// Make sure that the volume 'path' is on is mounted.
+// * If 'mount_point' is nullptr, use mount point in fstab. Caller can call
+// fs_mgr_ensure_path_unmounted() with the same 'path' argument to unmount.
+// * If 'mount_point' is not nullptr, the mount point is overridden. Caller can
+// call umount(mount_point) to unmount.
+// Returns true on success (volume is mounted).
+bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_point = "");
+
+// Make sure that the volume 'path' is on is unmounted. Returns true on
+// success (volume is unmounted).
+bool EnsurePathUnmounted(Fstab* fstab, const std::string& path);
+
+// Return "/system" if it is in default fstab, otherwise "/".
+std::string GetSystemRoot();
+
+// Return true iff logical partitions are mapped when partitions are mounted via ensure_path_mounted
+// functions.
+bool LogicalPartitionsMapped();
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index d9a5e0a..0997254 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -43,7 +43,7 @@
char* fs_type;
unsigned long flags;
char* fs_options;
- int fs_mgr_flags;
+ uint64_t fs_mgr_flags;
char* key_loc;
char* key_dir;
char* verity_loc;
@@ -123,8 +123,9 @@
// TODO: Remove this union once fstab_rec is deprecated. It only serves as a
// convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
union {
- int val;
+ uint64_t val;
struct {
+ // bit 0
bool wait : 1;
bool check : 1;
bool crypt : 1;
@@ -133,6 +134,8 @@
bool length : 1;
bool recovery_only : 1;
bool swap_prio : 1;
+
+ // bit 8
bool zram_size : 1;
bool verify : 1;
bool force_crypt : 1;
@@ -142,6 +145,8 @@
bool file_encryption : 1;
bool formattable : 1;
bool slot_select : 1;
+
+ // bit 16
bool force_fde_or_fbe : 1;
bool late_mount : 1;
bool no_fail : 1;
@@ -150,6 +155,8 @@
bool reserved_size : 1;
bool quota : 1;
bool erase_blk_size : 1;
+
+ // bit 24
bool logical_blk_size : 1;
bool avb : 1;
bool key_directory : 1;
@@ -158,6 +165,9 @@
bool checkpoint_blk : 1;
bool checkpoint_fs : 1;
bool first_stage_mount : 1;
+
+ // bit 32
+ bool slot_select_other : 1;
};
} fs_mgr_flags;
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 22af123..90bce51 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -20,10 +20,6 @@
recovery_available: true,
export_include_dirs: ["include"],
- cflags: [
- // TODO(b/110035986): Allows us to create a skeleton of required classes
- "-Wno-unused-private-field",
- ],
srcs: [
"dm_table.cpp",
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index aaee1a7..9e211e3 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -92,7 +92,7 @@
Returns: true if device is (likely) a debug build" ]
isDebuggable() {
- if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
+ if inAdb && [ 1 -ne "`get_property ro.debuggable`" ]; then
false
fi
}
@@ -290,6 +290,11 @@
fi
inAdb || die "specified device not in adb mode"
isDebuggable || die "device not a debug build"
+enforcing=true
+if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} device does not have sepolicy in enforcing mode"
+ enforcing=false
+fi
# Do something
@@ -384,16 +389,16 @@
die -t "${T}" "disable-verity"
fi
rebooted=false
-if [ X"${D}" != X"${H}" -a X"${D}" = X"${D##*using overlayfs}" ]; then
+if [ X"${D}" != X"${H}" ]; then
echo "${H}"
if [ X"${D}" != X"${D##*setup failed}" ]; then
echo "${ORANGE}[ WARNING ]${NORMAL} overlayfs setup whined" >&2
fi
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep "^overlay "` &&
- [ -n "${D}" ] &&
- ( echo "${H}" && echo "${D}" ) &&
+ D=`echo "${D}" | grep "^overlay " || true` &&
+ [ -z "${D}" ] ||
+ ( echo "${H}" && echo "${D}" && false ) ||
die -t ${T} "overlay takeover unexpected at this phase"
echo "${GREEN}[ INFO ]${NORMAL} rebooting as requested" >&2
L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
@@ -421,12 +426,12 @@
die -t "${T}" "setup for overlay"
fi
if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
- echo "${D}"
+ echo "${H}"
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep "^overlay " | true` &&
- [ -n "${D}" ] &&
- ( echo "${H}" && echo "${D}" ) &&
+ D=`echo "${D}" | grep "^overlay " || true` &&
+ [ -z "${D}" ] ||
+ ( echo "${H}" && echo "${D}" && false ) ||
( [ -n "${L}" ] && echo "${L}" && false ) ||
die -t "${T}" "overlay takeover unexpected"
[ -n "${L}" ] && echo "${L}"
@@ -499,17 +504,17 @@
# Check something
-echo "${GREEN}[ RUN ]${NORMAL} push content to system and vendor" >&2
+echo "${GREEN}[ RUN ]${NORMAL} push content to /system and /vendor" >&2
A="Hello World! $(date)"
echo "${A}" | adb_sh "cat - > /system/hello"
echo "${A}" | adb_sh "cat - > /vendor/hello"
B="`adb_cat /system/hello`" ||
die "sytem hello"
-check_eq "${A}" "${B}" system before reboot
+check_eq "${A}" "${B}" /system before reboot
B="`adb_cat /vendor/hello`" ||
die "vendor hello"
-check_eq "${A}" "${B}" vendor before reboot
+check_eq "${A}" "${B}" /vendor before reboot
echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2
@@ -532,16 +537,21 @@
fi
B="`adb_cat /system/hello`" ||
- die "re-read system hello after reboot"
-check_eq "${A}" "${B}" system after reboot
+ die "re-read /system/hello after reboot"
+check_eq "${A}" "${B}" /system after reboot
+echo "${GREEN}[ OK ]${NORMAL} /system content remains after reboot" >&2
# Only root can read vendor if sepolicy permissions are as expected
-B="`adb_cat /vendor/hello`" &&
- die "re-read vendor hello after reboot w/o root"
-check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
+if ${enforcing}; then
+ B="`adb_cat /vendor/hello`" &&
+ die "re-read /vendor/hello after reboot w/o root"
+ check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
+ echo "${GREEN}[ OK ]${NORMAL} /vendor content correct MAC after reboot" >&2
+fi
adb_root &&
B="`adb_cat /vendor/hello`" ||
- die "re-read vendor hello after reboot"
+ die "re-read /vendor/hello after reboot"
check_eq "${A}" "${B}" vendor after reboot
+echo "${GREEN}[ OK ]${NORMAL} /vendor content remains after reboot" >&2
echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
@@ -601,17 +611,17 @@
echo "${H}" &&
echo "${D}" &&
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
- die "overlay system takeover after flash vendor"
+ die "overlay /system takeover after flash vendor"
echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
- die "overlay minus vendor takeover after flash vendor"
+ die "overlay supposed to be minus /vendor takeover after flash vendor"
fi
B="`adb_cat /system/hello`" ||
- die "re-read system hello after flash vendor"
+ die "re-read /system/hello after flash vendor"
check_eq "${A}" "${B}" system after flash vendor
adb_root ||
die "adb root"
B="`adb_cat /vendor/hello`" &&
- die "re-read vendor hello after flash vendor"
+ die "re-read /vendor/hello after flash vendor"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
fi
@@ -623,10 +633,10 @@
adb_sh rm /system/hello </dev/null ||
die -t ${T} "cleanup hello"
B="`adb_cat /system/hello`" &&
- die "re-read system hello after rm"
+ die "re-read /system/hello after rm"
check_eq "cat: /system/hello: No such file or directory" "${B}" after flash rm
B="`adb_cat /vendor/hello`" &&
- die "re-read vendor hello after rm"
+ die "re-read /vendor/hello after rm"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
if [ -n "${scratch_partition}" ]; then
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index c96c381..b5ff658 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -42,6 +42,7 @@
#include "uevent_listener.h"
#include "util.h"
+using android::base::ReadFileToString;
using android::base::Split;
using android::base::Timer;
using android::fs_mgr::AvbHandle;
@@ -73,6 +74,8 @@
bool CreateLogicalPartitions();
bool MountPartition(FstabEntry* fstab_entry);
bool MountPartitions();
+ bool TrySwitchSystemAsRoot();
+ bool TrySkipMountingPartitions();
bool IsDmLinearEnabled();
bool GetDmLinearMetadataDevice();
bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
@@ -392,16 +395,21 @@
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;
+ }
PLOG(ERROR) << "Failed to mount '" << fstab_entry->mount_point << "'";
return false;
}
return true;
}
-bool FirstStageMount::MountPartitions() {
- // If system is in the fstab then we're not a system-as-root device, and in
- // this case, we mount system first then pivot to it. From that point on,
- // we are effectively identical to a system-as-root device.
+// If system is in the fstab then we're not a system-as-root device, and in
+// this case, we mount system first then pivot to it. From that point on,
+// we are effectively identical to a system-as-root device.
+bool FirstStageMount::TrySwitchSystemAsRoot() {
auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
return entry.mount_point == "/system";
});
@@ -416,6 +424,44 @@
fstab_.erase(system_partition);
}
+ return true;
+}
+
+// For GSI to skip mounting /product and /product_services, until there are
+// well-defined interfaces between them and /system. Otherwise, the GSI flashed
+// on /system might not be able to work with /product and /product_services.
+// When they're skipped here, /system/product and /system/product_services in
+// GSI will be used.
+bool FirstStageMount::TrySkipMountingPartitions() {
+ constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
+
+ std::string skip_config;
+ if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
+ return true;
+ }
+
+ for (const auto& skip_mount_point : Split(skip_config, "\n")) {
+ if (skip_mount_point.empty()) {
+ continue;
+ }
+ auto removing_entry =
+ std::find_if(fstab_.begin(), fstab_.end(), [&skip_mount_point](const auto& entry) {
+ return entry.mount_point == skip_mount_point;
+ });
+ if (removing_entry != fstab_.end()) {
+ fstab_.erase(removing_entry);
+ LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
+ }
+ }
+
+ return true;
+}
+
+bool FirstStageMount::MountPartitions() {
+ if (!TrySwitchSystemAsRoot()) return false;
+
+ if (!TrySkipMountingPartitions()) return false;
+
for (auto& fstab_entry : fstab_) {
if (!MountPartition(&fstab_entry) && !fstab_entry.fs_mgr_flags.no_fail) {
return false;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 3a09096..04ca207 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -306,6 +306,11 @@
}
std::string 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();
+ }
+
// 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");
@@ -342,6 +347,9 @@
};
// clang-format on
+ if (!product_policy_cil_file.empty()) {
+ compile_args.push_back(product_policy_cil_file.c_str());
+ }
if (!plat_pub_versioned_cil_file.empty()) {
compile_args.push_back(plat_pub_versioned_cil_file.c_str());
}
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 8b0c53e..ac94e69 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -311,7 +311,7 @@
};
FuseBridgeLoop::FuseBridgeLoop() : opened_(true) {
- base::unique_fd epoll_fd(epoll_create1(/* no flag */ 0));
+ base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC));
if (epoll_fd.get() == -1) {
PLOG(ERROR) << "Failed to open FD for epoll";
opened_ = false;
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 39cb995..038b59e 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -76,7 +76,7 @@
return UnwindFromContext(num_ignore_frames, ucontext);
}
- if (Tid() != android::base::GetThreadId()) {
+ if (Tid() != static_cast<pid_t>(android::base::GetThreadId())) {
return UnwindThread(num_ignore_frames);
}
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index fe28eba..f5f9b2a 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -117,7 +117,7 @@
back_frame->map.name = frame->map_name;
back_frame->map.start = frame->map_start;
back_frame->map.end = frame->map_end;
- back_frame->map.offset = frame->map_offset;
+ back_frame->map.offset = frame->map_elf_start_offset;
back_frame->map.load_bias = frame->map_load_bias;
back_frame->map.flags = frame->map_flags;
}
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 68bf898..0723612 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -133,6 +133,7 @@
#define AID_LLKD 1070 /* live lock daemon */
#define AID_IORAPD 1071 /* input/output readahead and pin daemon */
#define AID_GPU_SERVICE 1072 /* GPU service daemon */
+#define AID_NETWORK_STACK 1073 /* network stack service */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libmeminfo/tools/Android.bp b/libmeminfo/tools/Android.bp
index 715d63d..1f93494 100644
--- a/libmeminfo/tools/Android.bp
+++ b/libmeminfo/tools/Android.bp
@@ -13,11 +13,24 @@
// limitations under the License.
cc_binary {
+ name: "librank2",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ srcs: ["librank.cpp"],
+ shared_libs: [
+ "libbase",
+ "libmeminfo",
+ ],
+}
+
+cc_binary {
name: "procmem2",
cflags: [
"-Wall",
"-Werror",
- "-Wno-unused-parameter",
],
srcs: ["procmem.cpp"],
@@ -32,7 +45,6 @@
cflags: [
"-Wall",
"-Werror",
- "-Wno-unused-parameter",
],
srcs: ["procrank.cpp"],
diff --git a/libmeminfo/tools/librank.cpp b/libmeminfo/tools/librank.cpp
new file mode 100644
index 0000000..7668640
--- /dev/null
+++ b/libmeminfo/tools/librank.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2018 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 <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <inttypes.h>
+#include <linux/kernel-page-flags.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include <meminfo/procmeminfo.h>
+
+using ::android::meminfo::MemUsage;
+using ::android::meminfo::ProcMemInfo;
+using ::android::meminfo::Vma;
+
+[[noreturn]] static void usage(const char* myname, int exit_status) {
+ fprintf(stderr,
+ "Usage: %s [ -P | -L ] [ -v | -r | -p | -u | -s | -h ]\n"
+ "\n"
+ "Sort options:\n"
+ " -v Sort processes by VSS.\n"
+ " -r Sort processes by RSS.\n"
+ " -p Sort processes by PSS.\n"
+ " -u Sort processes by USS.\n"
+ " -s Sort processes by swap.\n"
+ " (Default sort order is PSS.)\n"
+ " -a Show all mappings, including stack, heap and anon.\n"
+ " -P /path Limit libraries displayed to those in path.\n"
+ " -R Reverse sort order (default is descending).\n"
+ " -m [r][w][x] Only list pages that exactly match permissions\n"
+ " -c Only show cached (storage backed) pages\n"
+ " -C Only show non-cached (ram/swap backed) pages\n"
+ " -k Only show pages collapsed by KSM\n"
+ " -h Display this help screen.\n",
+ myname);
+ exit(exit_status);
+}
+
+static void add_mem_usage(MemUsage* to, const MemUsage& from) {
+ to->vss += from.vss;
+ to->rss += from.rss;
+ to->pss += from.pss;
+ to->uss += from.uss;
+
+ to->swap += from.swap;
+
+ to->private_clean += from.private_clean;
+ to->private_dirty += from.private_dirty;
+
+ to->shared_clean += from.shared_clean;
+ to->shared_dirty += from.shared_dirty;
+}
+
+struct ProcessRecord {
+ public:
+ ProcessRecord(pid_t pid) : pid_(-1), cmdline_("") {
+ std::string fname = ::android::base::StringPrintf("/proc/%d/cmdline", pid);
+ std::string cmdline;
+ if (!::android::base::ReadFileToString(fname, &cmdline)) {
+ fprintf(stderr, "Failed to read cmdline from: %s\n", fname.c_str());
+ return;
+ }
+ // We deliberately don't read the proc/<pid>cmdline file directly into 'cmdline_'
+ // because of some processes showing up cmdlines that end with "0x00 0x0A 0x00"
+ // e.g. xtra-daemon, lowi-server
+ // The .c_str() assignment below then takes care of trimming the cmdline at the first
+ // 0x00. This is how original procrank worked (luckily)
+ cmdline_ = cmdline.c_str();
+ pid_ = pid;
+ usage_.clear();
+ }
+
+ ~ProcessRecord() = default;
+
+ bool valid() const { return pid_ != -1; }
+
+ // Getters
+ pid_t pid() const { return pid_; }
+ const std::string& cmdline() const { return cmdline_; }
+ const MemUsage& usage() const { return usage_; }
+
+ // Add to the usage
+ void AddUsage(const MemUsage& mem_usage) { add_mem_usage(&usage_, mem_usage); }
+
+ private:
+ pid_t pid_;
+ std::string cmdline_;
+ MemUsage usage_;
+};
+
+struct LibRecord {
+ public:
+ LibRecord(const std::string& name) : name_(name) {}
+ ~LibRecord() = default;
+
+ const std::string& name() const { return name_; }
+ const MemUsage& usage() const { return usage_; }
+ const std::vector<ProcessRecord>& processes() const { return procs_; }
+ uint64_t pss() const { return usage_.pss; }
+ void AddUsage(const ProcessRecord& proc, const MemUsage& mem_usage) {
+ auto process = std::find_if(procs_.begin(), procs_.end(),
+ [&](auto p) -> bool { return p.pid() == proc.pid(); });
+ if (process == procs_.end()) {
+ process = procs_.emplace(procs_.end(), proc.pid());
+ }
+ process->AddUsage(mem_usage);
+ add_mem_usage(&usage_, mem_usage);
+ }
+
+ void Sort(std::function<bool(const ProcessRecord&, const ProcessRecord&)>& sorter) {
+ std::sort(procs_.begin(), procs_.end(), sorter);
+ }
+
+ private:
+ std::string name_;
+ MemUsage usage_;
+ std::vector<ProcessRecord> procs_;
+};
+
+// List of every library / map
+static std::vector<LibRecord> g_libs;
+
+// List of library/map names that we don't want to show by default
+static const std::vector<std::string> g_blacklisted_libs = {"[heap]", "[stack]"};
+
+// Global flags affected by command line
+static uint64_t g_pgflags = 0;
+static uint64_t g_pgflags_mask = 0;
+static uint16_t g_mapflags_mask = 0;
+static bool g_all_libs = false;
+static bool g_has_swap = false;
+static bool g_reverse_sort = false;
+static std::string g_prefix_filter = "";
+
+static bool read_all_pids(std::function<bool(pid_t pid)> for_each_pid) {
+ std::unique_ptr<DIR, int (*)(DIR*)> procdir(opendir("/proc"), closedir);
+ if (!procdir) return false;
+
+ struct dirent* dir;
+ pid_t pid;
+ while ((dir = readdir(procdir.get()))) {
+ if (!::android::base::ParseInt(dir->d_name, &pid)) continue;
+ if (!for_each_pid(pid)) return false;
+ }
+
+ return true;
+}
+
+static bool scan_libs_per_process(pid_t pid) {
+ ProcMemInfo pmem(pid, false, g_pgflags, g_pgflags_mask);
+ const std::vector<Vma> maps = pmem.Maps();
+ if (maps.size() == 0) {
+ // nothing to do here, continue
+ return true;
+ }
+
+ ProcessRecord proc(pid);
+ if (!proc.valid()) {
+ fprintf(stderr, "Failed to create process record for process: %d\n", pid);
+ return false;
+ }
+
+ for (auto& map : maps) {
+ // skip library / map if prefix for the path doesn't match
+ if (!g_prefix_filter.empty() && !::android::base::StartsWith(map.name, g_prefix_filter)) {
+ continue;
+ }
+ // Skip maps based on map permissions
+ if (g_mapflags_mask &&
+ ((map.flags & (PROT_READ | PROT_WRITE | PROT_EXEC)) != g_mapflags_mask)) {
+ continue;
+ }
+
+ // skip blacklisted library / map names
+ if (!g_all_libs && (std::find(g_blacklisted_libs.begin(), g_blacklisted_libs.end(),
+ map.name) != g_blacklisted_libs.end())) {
+ continue;
+ }
+
+ auto lib = std::find_if(g_libs.begin(), g_libs.end(),
+ [&](auto l) -> bool { return map.name == l.name(); });
+ if (lib == g_libs.end()) {
+ lib = g_libs.emplace(g_libs.end(), map.name);
+ }
+
+ lib->AddUsage(proc, map.usage);
+ if (!g_has_swap && map.usage.swap) {
+ g_has_swap = true;
+ }
+ }
+
+ return true;
+}
+
+static uint16_t parse_mapflags(const char* mapflags) {
+ uint16_t ret = 0;
+ for (const char* p = mapflags; *p; p++) {
+ switch (*p) {
+ case 'r':
+ ret |= PROT_READ;
+ break;
+ case 'w':
+ ret |= PROT_WRITE;
+ break;
+ case 'x':
+ ret |= PROT_EXEC;
+ break;
+ default:
+ error(EXIT_FAILURE, 0, "Invalid permissions string: %s, %s", mapflags, p);
+ }
+ }
+
+ return ret;
+}
+
+int main(int argc, char* argv[]) {
+ int opt;
+
+ auto pss_sort = [](const ProcessRecord& a, const ProcessRecord& b) {
+ return g_reverse_sort ? a.usage().pss < b.usage().pss : a.usage().pss > b.usage().pss;
+ };
+
+ auto uss_sort = [](const ProcessRecord& a, const ProcessRecord& b) {
+ return g_reverse_sort ? a.usage().uss < b.usage().uss : a.usage().uss > b.usage().uss;
+ };
+
+ auto vss_sort = [](const ProcessRecord& a, const ProcessRecord& b) {
+ return g_reverse_sort ? a.usage().vss < b.usage().vss : a.usage().vss > b.usage().vss;
+ };
+
+ auto rss_sort = [](const ProcessRecord& a, const ProcessRecord& b) {
+ return g_reverse_sort ? a.usage().rss < b.usage().rss : a.usage().rss > b.usage().rss;
+ };
+
+ auto swap_sort = [](const ProcessRecord& a, const ProcessRecord& b) {
+ return g_reverse_sort ? a.usage().swap < b.usage().swap : a.usage().swap > b.usage().swap;
+ };
+
+ std::function<bool(const ProcessRecord&, const ProcessRecord&)> sort_func = pss_sort;
+
+ while ((opt = getopt(argc, argv, "acChkm:pP:uvrsR")) != -1) {
+ switch (opt) {
+ case 'a':
+ g_all_libs = true;
+ break;
+ case 'c':
+ g_pgflags = 0;
+ g_pgflags_mask = (1 << KPF_SWAPBACKED);
+ break;
+ case 'C':
+ g_pgflags = g_pgflags_mask = (1 << KPF_SWAPBACKED);
+ break;
+ case 'h':
+ usage(argv[0], EXIT_SUCCESS);
+ case 'k':
+ g_pgflags = g_pgflags_mask = (1 << KPF_KSM);
+ break;
+ case 'm':
+ g_mapflags_mask = parse_mapflags(optarg);
+ break;
+ case 'p':
+ sort_func = pss_sort;
+ break;
+ case 'P':
+ g_prefix_filter = optarg;
+ break;
+ case 'u':
+ sort_func = uss_sort;
+ break;
+ case 'v':
+ sort_func = vss_sort;
+ break;
+ case 'r':
+ sort_func = rss_sort;
+ break;
+ case 's':
+ sort_func = swap_sort;
+ break;
+ case 'R':
+ g_reverse_sort = true;
+ break;
+ default:
+ usage(argv[0], EXIT_FAILURE);
+ }
+ }
+
+ if (!read_all_pids(scan_libs_per_process)) {
+ error(EXIT_FAILURE, 0, "Failed to read all pids from the system");
+ }
+
+ printf(" %6s %7s %6s %6s %6s ", "RSStot", "VSS", "RSS", "PSS", "USS");
+ if (g_has_swap) {
+ printf(" %6s ", "Swap");
+ }
+ printf("Name/PID\n");
+
+ // sort the libraries by their pss
+ std::sort(g_libs.begin(), g_libs.end(),
+ [](const LibRecord& l1, const LibRecord& l2) { return l1.pss() > l2.pss(); });
+
+ for (auto& lib : g_libs) {
+ printf("%6" PRIu64 "K %7s %6s %6s %6s ", lib.pss() / 1024, "", "", "", "");
+ if (g_has_swap) {
+ printf(" %6s ", "");
+ }
+ printf("%s\n", lib.name().c_str());
+
+ // sort all mappings first
+ lib.Sort(sort_func);
+
+ for (auto& p : lib.processes()) {
+ const MemUsage& usage = p.usage();
+ printf(" %6s %7" PRIu64 "K %6" PRIu64 "K %6" PRIu64 "K %6" PRIu64 "K ", "",
+ usage.vss / 1024, usage.rss / 1024, usage.pss / 1024, usage.uss / 1024);
+ if (g_has_swap) {
+ printf("%6" PRIu64 "K ", usage.swap / 1024);
+ }
+ printf(" %s [%d]\n", p.cmdline().c_str(), p.pid());
+ }
+ }
+
+ return 0;
+}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index b3e2b97..de7ea08 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -639,7 +639,11 @@
UNUSED(target_sdk_version);
if (class_loader == nullptr) {
*needs_native_bridge = false;
- return dlopen(path, RTLD_NOW);
+ void* handle = dlopen(path, RTLD_NOW);
+ if (handle == nullptr) {
+ *error_msg = dlerror();
+ }
+ return handle;
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h
index 41ca79b..162d1cf 100644
--- a/libstats/include/stats_event_list.h
+++ b/libstats/include/stats_event_list.h
@@ -24,7 +24,7 @@
#endif
void reset_log_context(android_log_context ctx);
int write_to_logger(android_log_context context, log_id_t id);
-void note_log_drop();
+void note_log_drop(int error);
void stats_log_close();
int android_log_write_char_array(android_log_context ctx, const char* value, size_t len);
#ifdef __cplusplus
diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c
index f4a7e94..5b90361 100644
--- a/libstats/stats_event_list.c
+++ b/libstats/stats_event_list.c
@@ -120,8 +120,8 @@
return retValue;
}
-void note_log_drop() {
- statsdLoggerWrite.noteDrop();
+void note_log_drop(int error) {
+ statsdLoggerWrite.noteDrop(error);
}
void stats_log_close() {
diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c
index 88f7d44..f00fc2d 100644
--- a/libstats/statsd_writer.c
+++ b/libstats/statsd_writer.c
@@ -48,6 +48,7 @@
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
static atomic_int dropped = 0;
+static atomic_int log_error = 0;
void statsd_writer_init_lock() {
/*
@@ -150,8 +151,9 @@
return 1;
}
-static void statsdNoteDrop() {
+static void statsdNoteDrop(int error) {
atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+ atomic_exchange_explicit(&log_error, error, memory_order_relaxed);
}
static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
@@ -202,7 +204,8 @@
if (snapshot) {
android_log_event_int_t buffer;
header.id = LOG_ID_STATS;
- buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+ // store the last log error in the tag field. This tag field is not used by statsd.
+ buffer.header.tag = htole32(atomic_load(&log_error));
buffer.payload.type = EVENT_TYPE_INT;
buffer.payload.data = htole32(snapshot);
diff --git a/libstats/statsd_writer.h b/libstats/statsd_writer.h
index 7289441..4fc3f8b 100644
--- a/libstats/statsd_writer.h
+++ b/libstats/statsd_writer.h
@@ -39,7 +39,7 @@
/* write log to transport, returns number of bytes propagated, or -errno */
int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
/* note one log drop */
- void (*noteDrop)();
+ void (*noteDrop)(int error);
};
#endif // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 4e0470e..89d4fc0 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -94,7 +94,10 @@
"DexFile.cpp",
"DexFiles.cpp",
],
- exclude_shared_libs: ["libdexfile"],
+ exclude_shared_libs: [
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
},
recovery: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
@@ -102,7 +105,10 @@
"DexFile.cpp",
"DexFiles.cpp",
],
- exclude_shared_libs: ["libdexfile"],
+ exclude_shared_libs: [
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
},
},
@@ -127,7 +133,8 @@
shared_libs: [
"libbase",
- "libdexfile",
+ "libdexfile_external",
+ "libdexfile_support",
"liblog",
"liblzma",
],
@@ -215,6 +222,7 @@
"liblzma",
"libunwindstack",
"libdexfile",
+ "libdexfile_support",
],
static_libs: [
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index 8ec560c..9b0b232 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -23,13 +23,7 @@
#include <memory>
#include <android-base/unique_fd.h>
-
-#include <dex/class_accessor-inl.h>
-#include <dex/code_item_accessors-inl.h>
-#include <dex/compact_dex_file.h>
-#include <dex/dex_file-inl.h>
-#include <dex/dex_file_loader.h>
-#include <dex/standard_dex_file.h>
+#include <art_api/ext_dex_file.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
@@ -38,169 +32,71 @@
namespace unwindstack {
-DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
+std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
+ MapInfo* info) {
if (!info->name.empty()) {
- std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
- if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
- return dex_file.release();
+ std::unique_ptr<DexFile> dex_file =
+ DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
+ if (dex_file) {
+ return dex_file;
}
}
-
- std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
- if (dex_file->Open(dex_file_offset_in_memory, memory)) {
- return dex_file.release();
- }
- return nullptr;
-}
-
-DexFileFromFile::~DexFileFromFile() {
- if (size_ != 0) {
- munmap(mapped_memory_, size_);
- }
+ return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
}
bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
uint64_t* method_offset) {
- if (dex_file_ == nullptr) {
+ art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset);
+ if (method_info.offset == 0) {
return false;
}
-
- if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) {
- return false; // The DEX offset is not within the bytecode of this dex file.
- }
-
- if (dex_file_->IsCompactDexFile()) {
- // The data section of compact dex files might be shared.
- // Check the subrange unique to this compact dex.
- const auto& cdex_header = dex_file_->AsCompactDexFile()->GetHeader();
- uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin();
- uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd();
- if (dex_offset < begin || dex_offset >= end) {
- return false; // The DEX offset is not within the bytecode of this dex file.
- }
- }
-
- // The method data is cached in a std::map indexed by method end offset and
- // contains the start offset and the method member index.
- // Only cache the method data as it is searched. Do not read the entire
- // set of method data into the cache at once.
- // This is done because many unwinds only find a single frame with dex file
- // info, so reading the entire method data is wasteful. However, still cache
- // the data so that anything doing multiple unwinds will have this data
- // cached for future use.
-
- // First look in the method cache.
- auto entry = method_cache_.upper_bound(dex_offset);
- if (entry != method_cache_.end() && dex_offset >= entry->second.first) {
- *method_name = dex_file_->PrettyMethod(entry->second.second, false);
- *method_offset = dex_offset - entry->second.first;
- return true;
- }
-
- // Check the methods we haven't cached.
- for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) {
- art::ClassAccessor accessor(*dex_file_, dex_file_->GetClassDef(class_def_index_));
-
- for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
- art::CodeItemInstructionAccessor code = method.GetInstructions();
- if (!code.HasCodeItem()) {
- continue;
- }
- uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
- uint32_t offset_end = offset + code.InsnsSizeInBytes();
- uint32_t member_index = method.GetIndex();
- method_cache_[offset_end] = std::make_pair(offset, member_index);
- if (offset <= dex_offset && dex_offset < offset_end) {
- *method_name = dex_file_->PrettyMethod(member_index, false);
- *method_offset = dex_offset - offset;
- return true;
- }
- }
- }
- return false;
+ *method_name = method_info.name;
+ *method_offset = dex_offset - method_info.offset;
+ return true;
}
-bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+std::unique_ptr<DexFileFromFile> DexFileFromFile::Create(uint64_t dex_file_offset_in_file,
+ const std::string& file) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
- return false;
- }
- struct stat buf;
- if (fstat(fd, &buf) == -1) {
- return false;
- }
- uint64_t length;
- if (buf.st_size < 0 ||
- __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) ||
- static_cast<uint64_t>(buf.st_size) < length) {
- return false;
+ return nullptr;
}
- mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (mapped_memory_ == MAP_FAILED) {
- return false;
- }
- size_ = buf.st_size;
-
- uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_);
-
- art::DexFile::Header* header =
- reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]);
- if (!art::StandardDexFile::IsMagicValid(header->magic_) &&
- !art::CompactDexFile::IsMagicValid(header->magic_)) {
- return false;
- }
-
- if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) ||
- static_cast<uint64_t>(buf.st_size) < length) {
- return false;
- }
-
- art::DexFileLoader loader;
std::string error_msg;
- auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr,
- false, false, &error_msg);
- dex_file_.reset(dex.release());
- return dex_file_ != nullptr;
+ std::unique_ptr<art_api::dex::DexFile> art_dex_file =
+ OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg);
+ if (art_dex_file == nullptr) {
+ return nullptr;
+ }
+
+ return std::unique_ptr<DexFileFromFile>(new DexFileFromFile(std::move(*art_dex_file.release())));
}
-bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
- memory_.resize(sizeof(art::DexFile::Header));
- if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
- return false;
- }
+std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
+ Memory* memory,
+ const std::string& name) {
+ std::vector<uint8_t> backing_memory;
- art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
- uint32_t file_size = header->file_size_;
- if (art::CompactDexFile::IsMagicValid(header->magic_)) {
- // Compact dex file store data section separately so that it can be shared.
- // Therefore we need to extend the read memory range to include it.
- // TODO: This might be wasteful as we might read data in between as well.
- // In practice, this should be fine, as such sharing only happens on disk.
- uint32_t computed_file_size;
- if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
- return false;
+ for (size_t size = 0;;) {
+ std::string error_msg;
+ std::unique_ptr<art_api::dex::DexFile> art_dex_file =
+ OpenFromMemory(backing_memory.data(), &size, name, &error_msg);
+
+ if (art_dex_file != nullptr) {
+ return std::unique_ptr<DexFileFromMemory>(
+ new DexFileFromMemory(std::move(*art_dex_file.release()), std::move(backing_memory)));
}
- if (computed_file_size > file_size) {
- file_size = computed_file_size;
+
+ if (!error_msg.empty()) {
+ return nullptr;
}
- } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
- return false;
+
+ backing_memory.resize(size);
+ if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(),
+ backing_memory.size())) {
+ return nullptr;
+ }
}
-
- memory_.resize(file_size);
- if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
- return false;
- }
-
- header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
-
- art::DexFileLoader loader;
- std::string error_msg;
- auto dex =
- loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg);
- dex_file_.reset(dex.release());
- return dex_file_ != nullptr;
}
} // namespace unwindstack
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index c123158..5797dee 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -25,48 +25,41 @@
#include <utility>
#include <vector>
-#include <dex/dex_file-inl.h>
+#include <art_api/ext_dex_file.h>
namespace unwindstack {
-class DexFile {
+class DexFile : protected art_api::dex::DexFile {
public:
- DexFile() = default;
virtual ~DexFile() = default;
bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
- static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
+ static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory,
+ MapInfo* info);
protected:
- void Init();
-
- std::unique_ptr<const art::DexFile> dex_file_;
- std::map<uint32_t, std::pair<uint64_t, uint32_t>> method_cache_; // dex offset to method index.
-
- uint32_t class_def_index_ = 0;
+ DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {}
};
class DexFileFromFile : public DexFile {
public:
- DexFileFromFile() = default;
- virtual ~DexFileFromFile();
-
- bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
+ static std::unique_ptr<DexFileFromFile> Create(uint64_t dex_file_offset_in_file,
+ const std::string& file);
private:
- void* mapped_memory_ = nullptr;
- size_t size_ = 0;
+ DexFileFromFile(art_api::dex::DexFile&& art_dex_file) : DexFile(std::move(art_dex_file)) {}
};
class DexFileFromMemory : public DexFile {
public:
- DexFileFromMemory() = default;
- virtual ~DexFileFromMemory() = default;
-
- bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
+ static std::unique_ptr<DexFileFromMemory> Create(uint64_t dex_file_offset_in_memory,
+ Memory* memory, const std::string& name);
private:
+ DexFileFromMemory(art_api::dex::DexFile&& art_dex_file, std::vector<uint8_t>&& memory)
+ : DexFile(std::move(art_dex_file)), memory_(std::move(memory)) {}
+
std::vector<uint8_t> memory_;
};
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 451a0b9..63a77e5 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -48,11 +48,7 @@
DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
: Global(memory, search_libs) {}
-DexFiles::~DexFiles() {
- for (auto& entry : files_) {
- delete entry.second;
- }
-}
+DexFiles::~DexFiles() {}
void DexFiles::ProcessArch() {
switch (arch()) {
@@ -137,10 +133,11 @@
DexFile* dex_file;
auto entry = files_.find(dex_file_offset);
if (entry == files_.end()) {
- dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
- files_[dex_file_offset] = dex_file;
+ std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+ dex_file = new_dex_file.get();
+ files_[dex_file_offset] = std::move(new_dex_file);
} else {
- dex_file = entry->second;
+ dex_file = entry->second.get();
}
return dex_file;
}
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 44ec5c1..39a09cf 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -32,33 +32,27 @@
bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
// One last attempt, see if the previous map is read-only with the
// same name and stretches across this map.
- for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
- if (*iter == this) {
- if (iter == maps_->begin()) {
- return false;
- }
- --iter;
- MapInfo* prev_map = *iter;
- // Make sure this is a read-only map.
- if (prev_map->flags != PROT_READ) {
- return false;
- }
- uint64_t map_size = end - prev_map->end;
- if (!memory->Init(name, prev_map->offset, map_size)) {
- return false;
- }
- uint64_t max_size;
- if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
- return false;
- }
- if (!memory->Init(name, prev_map->offset, max_size)) {
- return false;
- }
- elf_offset = offset - prev_map->offset;
- return true;
- }
+ if (prev_map == nullptr || prev_map->flags != PROT_READ) {
+ return false;
}
- return false;
+
+ uint64_t map_size = end - prev_map->end;
+ if (!memory->Init(name, prev_map->offset, map_size)) {
+ return false;
+ }
+
+ uint64_t max_size;
+ if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
+ return false;
+ }
+
+ if (!memory->Init(name, prev_map->offset, max_size)) {
+ return false;
+ }
+
+ elf_offset = offset - prev_map->offset;
+ elf_start_offset = prev_map->offset;
+ return true;
}
Memory* MapInfo::GetFileMemory() {
@@ -91,14 +85,13 @@
// Check if the start of this map is an embedded elf.
uint64_t max_size = 0;
- uint64_t file_offset = offset;
if (Elf::GetInfo(memory.get(), &max_size)) {
if (max_size > map_size) {
- if (memory->Init(name, file_offset, max_size)) {
+ if (memory->Init(name, offset, max_size)) {
return memory.release();
}
// Try to reinit using the default map_size.
- if (memory->Init(name, file_offset, map_size)) {
+ if (memory->Init(name, offset, map_size)) {
return memory.release();
}
return nullptr;
@@ -109,6 +102,13 @@
// No elf at offset, try to init as if the whole file is an elf.
if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
elf_offset = offset;
+ // Need to check how to set the elf start offset. If this map is not
+ // the r-x map of a r-- map, then use the real offset value. Otherwise,
+ // use 0.
+ if (prev_map == nullptr || prev_map->offset != 0 || prev_map->flags != PROT_READ ||
+ prev_map->name != name) {
+ elf_start_offset = offset;
+ }
return memory.release();
}
@@ -156,35 +156,24 @@
return memory.release();
}
- if (name.empty() || maps_ == nullptr) {
- return nullptr;
- }
-
// Find the read-only map by looking at the previous map. The linker
// doesn't guarantee that this invariant will always be true. However,
// if that changes, there is likely something else that will change and
// break something.
- MapInfo* ro_map_info = nullptr;
- for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
- if (*iter == this) {
- if (iter != maps_->begin()) {
- --iter;
- ro_map_info = *iter;
- }
- break;
- }
- }
-
- if (ro_map_info == nullptr || ro_map_info->name != name || ro_map_info->offset >= offset) {
+ if (offset == 0 || name.empty() || prev_map == nullptr || prev_map->name != name ||
+ prev_map->offset >= offset) {
return nullptr;
}
// Make sure that relative pc values are corrected properly.
- elf_offset = offset - ro_map_info->offset;
+ elf_offset = offset - prev_map->offset;
+ // Use this as the elf start offset, otherwise, you always get offsets into
+ // the r-x section, which is not quite the right information.
+ elf_start_offset = prev_map->offset;
MemoryRanges* ranges = new MemoryRanges;
- ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
- ro_map_info->end - ro_map_info->start, 0));
+ ranges->Insert(
+ new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
return ranges;
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index a9fb859..c90e383 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -67,13 +67,15 @@
if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
}
- maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
+ maps_.push_back(
+ new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name));
});
}
void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
const std::string& name, uint64_t load_bias) {
- MapInfo* map_info = new MapInfo(this, start, end, offset, flags, name);
+ MapInfo* map_info =
+ new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, offset, flags, name);
map_info->load_bias = load_bias;
maps_.push_back(map_info);
}
@@ -81,6 +83,13 @@
void Maps::Sort() {
std::sort(maps_.begin(), maps_.end(),
[](const MapInfo* a, const MapInfo* b) { return a->start < b->start; });
+
+ // Set the prev_map values on the info objects.
+ MapInfo* prev_map = nullptr;
+ for (MapInfo* map_info : maps_) {
+ map_info->prev_map = prev_map;
+ prev_map = map_info;
+ }
}
Maps::~Maps() {
@@ -98,7 +107,8 @@
if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
}
- maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
+ maps_.push_back(
+ new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name));
});
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 792cd0b..8133639 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -59,7 +59,8 @@
if (info != nullptr) {
frame->map_start = info->start;
frame->map_end = info->end;
- frame->map_offset = info->offset;
+ frame->map_elf_start_offset = info->elf_start_offset;
+ frame->map_exact_offset = info->offset;
frame->map_load_bias = info->load_bias;
frame->map_flags = info->flags;
if (resolve_names_) {
@@ -102,7 +103,8 @@
if (resolve_names_) {
frame->map_name = map_info->name;
}
- frame->map_offset = map_info->offset;
+ frame->map_elf_start_offset = map_info->elf_start_offset;
+ frame->map_exact_offset = map_info->offset;
frame->map_start = map_info->start;
frame->map_end = map_info->end;
frame->map_flags = map_info->flags;
@@ -290,10 +292,6 @@
data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
}
- if (frame.map_offset != 0) {
- data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_offset);
- }
-
if (frame.map_start == frame.map_end) {
// No valid map associated with this frame.
data += " <unknown>";
@@ -302,6 +300,11 @@
} else {
data += android::base::StringPrintf(" <anonymous:%" PRIx64 ">", frame.map_start);
}
+
+ if (frame.map_elf_start_offset != 0) {
+ data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_elf_start_offset);
+ }
+
if (!frame.function_name.empty()) {
data += " (" + frame.function_name;
if (frame.function_offset != 0) {
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index c202a33..0336173 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -66,7 +66,7 @@
std::mutex lock_;
bool initialized_ = false;
- std::unordered_map<uint64_t, DexFile*> files_;
+ std::unordered_map<uint64_t, std::unique_ptr<DexFile>> files_;
uint64_t entry_addr_ = 0;
uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr;
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index cfdefd0..5e3d6f6 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -25,38 +25,31 @@
#include <string>
#include <unwindstack/Elf.h>
+#include <unwindstack/Memory.h>
namespace unwindstack {
-// Forward declarations.
-class Maps;
-class Memory;
-
struct MapInfo {
- MapInfo(Maps* maps) : maps_(maps) {}
- MapInfo(Maps* maps, uint64_t start, uint64_t end) : maps_(maps), start(start), end(end) {}
- MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+ MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
const char* name)
- : maps_(maps),
- start(start),
+ : start(start),
end(end),
offset(offset),
flags(flags),
name(name),
+ prev_map(map_info),
load_bias(static_cast<uint64_t>(-1)) {}
- MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+ MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
const std::string& name)
- : maps_(maps),
- start(start),
+ : start(start),
end(end),
offset(offset),
flags(flags),
name(name),
+ prev_map(map_info),
load_bias(static_cast<uint64_t>(-1)) {}
~MapInfo() = default;
- Maps* maps_ = nullptr;
-
uint64_t start = 0;
uint64_t end = 0;
uint64_t offset = 0;
@@ -64,10 +57,14 @@
std::string name;
std::shared_ptr<Elf> elf;
// This value is only non-zero if the offset is non-zero but there is
- // no elf signature found at that offset. This indicates that the
- // entire file is represented by the Memory object returned by CreateMemory,
- // instead of a portion of the file.
+ // no elf signature found at that offset.
uint64_t elf_offset = 0;
+ // This value is the offset from the map in memory that is the start
+ // of the elf. This is not equal to offset when the linker splits
+ // shared libraries into a read-only and read-execute map.
+ uint64_t elf_start_offset = 0;
+
+ MapInfo* prev_map = nullptr;
std::atomic_uint64_t load_bias;
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 56b0581..d7bbd9d 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -48,7 +48,13 @@
uint64_t function_offset = 0;
std::string map_name;
- uint64_t map_offset = 0;
+ // The offset from the first map representing the frame. When there are
+ // two maps (read-only and read-execute) this will be the offset from
+ // the read-only map. When there is only one map, this will be the
+ // same as the actual offset of the map and match map_exact_offset.
+ uint64_t map_elf_start_offset = 0;
+ // The actual offset from the map where the pc lies.
+ uint64_t map_exact_offset = 0;
uint64_t map_start = 0;
uint64_t map_end = 0;
uint64_t map_load_bias = 0;
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 95d2176..21ca47b 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -21,44 +21,37 @@
#include <unordered_map>
#include <android-base/file.h>
-
+#include <dex/dex_file.h>
+#include <gtest/gtest.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
-#include <dex/code_item_accessors-inl.h>
-#include <dex/standard_dex_file.h>
-
-#include <gtest/gtest.h>
-
#include "DexFile.h"
-
#include "DexFileData.h"
#include "MemoryFake.h"
namespace unwindstack {
TEST(DexFileTest, from_file_open_non_exist) {
- DexFileFromFile dex_file;
- ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
+ EXPECT_TRUE(DexFileFromFile::Create(0, "/file/does/not/exist") == nullptr);
}
TEST(DexFileTest, from_file_open_too_small) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
- ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
+ ASSERT_EQ(sizeof(art::DexFile::Header) - 1,
static_cast<size_t>(
- TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
+ TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1))));
// Header too small.
- DexFileFromFile dex_file;
- ASSERT_FALSE(dex_file.Open(0, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
// Header correct, file too small.
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
tf.fd, kDexData, sizeof(art::DexFile::Header)))));
- ASSERT_FALSE(dex_file.Open(0, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
}
TEST(DexFileTest, from_file_open) {
@@ -68,8 +61,7 @@
ASSERT_EQ(sizeof(kDexData),
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
- DexFileFromFile dex_file;
- ASSERT_TRUE(dex_file.Open(0, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr);
}
TEST(DexFileTest, from_file_open_non_zero_offset) {
@@ -80,35 +72,31 @@
ASSERT_EQ(sizeof(kDexData),
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
- DexFileFromFile dex_file;
- ASSERT_TRUE(dex_file.Open(0x100, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0x100, tf.path) != nullptr);
}
TEST(DexFileTest, from_memory_fail_too_small_for_header) {
MemoryFake memory;
memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
- DexFileFromMemory dex_file;
- ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+ EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr);
}
TEST(DexFileTest, from_memory_fail_too_small_for_data) {
MemoryFake memory;
memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
- DexFileFromMemory dex_file;
- ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+ EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr);
}
TEST(DexFileTest, from_memory_open) {
MemoryFake memory;
memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
- DexFileFromMemory dex_file;
- ASSERT_TRUE(dex_file.Open(0x1000, &memory));
+ EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr);
}
TEST(DexFileTest, create_using_file) {
@@ -121,8 +109,7 @@
MemoryFake memory;
MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path);
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_file_non_zero_start) {
@@ -135,8 +122,7 @@
MemoryFake memory;
MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path);
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_file_non_zero_offset) {
@@ -149,24 +135,21 @@
MemoryFake memory;
MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path);
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_empty_file) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_file_does_not_exist) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_file_is_malformed) {
@@ -179,22 +162,13 @@
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ std::unique_ptr<DexFile> dex_file = DexFile::Create(0x4000, &memory, &info);
ASSERT_TRUE(dex_file != nullptr);
// Check it came from memory by clearing memory and verifying it fails.
memory.Clear();
- dex_file.reset(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file == nullptr);
-}
-
-TEST(DexFileTest, get_method_not_opened) {
- std::string method("something");
- uint64_t method_offset = 100;
- DexFile dex_file;
- dex_file.GetMethodInformation(0x100, &method, &method_offset);
- EXPECT_EQ("something", method);
- EXPECT_EQ(100U, method_offset);
+ dex_file = DexFile::Create(0x4000, &memory, &info);
+ EXPECT_TRUE(dex_file == nullptr);
}
TEST(DexFileTest, get_method) {
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 7766218..f7689ce 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -269,7 +269,7 @@
elf.FakeSetInterface(interface);
elf.FakeSetValid(true);
- MapInfo map_info(nullptr, 0x1000, 0x2000);
+ MapInfo map_info(nullptr, 0x1000, 0x2000, 0, 0, "");
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 943b3c9..a66685a 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -118,6 +118,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0x100U, info.elf_offset);
+ EXPECT_EQ(0x100U, info.elf_start_offset);
// Read the entire file.
std::vector<uint8_t> buffer(1024);
@@ -129,6 +130,44 @@
}
ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1));
+
+ // Now verify the elf start offset is set correctly based on the previous
+ // info.
+ MapInfo prev_info(nullptr, 0, 0x100, 0x10, 0, "");
+ info.prev_map = &prev_info;
+
+ // No preconditions met, change each one until it should set the elf start
+ // offset to zero.
+ info.elf_offset = 0;
+ info.elf_start_offset = 0;
+ memory.reset(info.CreateMemory(process_memory_));
+ ASSERT_TRUE(memory.get() != nullptr);
+ ASSERT_EQ(0x100U, info.elf_offset);
+ EXPECT_EQ(0x100U, info.elf_start_offset);
+
+ prev_info.offset = 0;
+ info.elf_offset = 0;
+ info.elf_start_offset = 0;
+ memory.reset(info.CreateMemory(process_memory_));
+ ASSERT_TRUE(memory.get() != nullptr);
+ ASSERT_EQ(0x100U, info.elf_offset);
+ EXPECT_EQ(0x100U, info.elf_start_offset);
+
+ prev_info.flags = PROT_READ;
+ info.elf_offset = 0;
+ info.elf_start_offset = 0;
+ memory.reset(info.CreateMemory(process_memory_));
+ ASSERT_TRUE(memory.get() != nullptr);
+ ASSERT_EQ(0x100U, info.elf_offset);
+ EXPECT_EQ(0x100U, info.elf_start_offset);
+
+ prev_info.name = info.name;
+ info.elf_offset = 0;
+ info.elf_start_offset = 0;
+ memory.reset(info.CreateMemory(process_memory_));
+ ASSERT_TRUE(memory.get() != nullptr);
+ ASSERT_EQ(0x100U, info.elf_offset);
+ EXPECT_EQ(0U, info.elf_start_offset);
}
// Verify that if the offset is non-zero and there is an elf at that
@@ -139,6 +178,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
+ EXPECT_EQ(0U, info.elf_start_offset);
// Read the valid part of the file.
std::vector<uint8_t> buffer(0x100);
@@ -162,6 +202,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
+ EXPECT_EQ(0U, info.elf_start_offset);
// Verify the memory is a valid elf.
uint8_t e_ident[SELFMAG + 1];
@@ -178,6 +219,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
+ EXPECT_EQ(0U, info.elf_start_offset);
// Verify the memory is a valid elf.
uint8_t e_ident[SELFMAG + 1];
@@ -250,6 +292,7 @@
ASSERT_TRUE(mem.get() != nullptr);
EXPECT_EQ(0x4000UL, map_info->elf_offset);
EXPECT_EQ(0x4000UL, map_info->offset);
+ EXPECT_EQ(0U, map_info->elf_start_offset);
// Verify that reading values from this memory works properly.
std::vector<uint8_t> buffer(0x4000);
@@ -295,6 +338,7 @@
ASSERT_TRUE(mem.get() != nullptr);
EXPECT_EQ(0x1000UL, map_info->elf_offset);
EXPECT_EQ(0xb000UL, map_info->offset);
+ EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
// Verify that reading values from this memory works properly.
std::vector<uint8_t> buffer(0x4000);
@@ -333,6 +377,7 @@
std::vector<uint8_t> buffer(0x100);
EXPECT_EQ(0x2000U, map_info->offset);
EXPECT_EQ(0U, map_info->elf_offset);
+ EXPECT_EQ(0U, map_info->elf_start_offset);
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
EXPECT_EQ(0xffU, buffer[0]);
@@ -346,6 +391,7 @@
memory.reset(map_info->CreateMemory(process_memory_));
EXPECT_EQ(0x2000U, map_info->offset);
EXPECT_EQ(0x1000U, map_info->elf_offset);
+ EXPECT_EQ(0x1000U, map_info->elf_start_offset);
Elf64_Ehdr ehdr_mem;
ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem)));
EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0);
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 80e292a..b4197f2 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -62,7 +62,7 @@
}
TEST(MapsTest, verify_parse_line) {
- MapInfo info(nullptr);
+ MapInfo info(nullptr, 0, 0, 0, 0, "");
VerifyLine("01-02 rwxp 03 04:05 06\n", &info);
EXPECT_EQ(1U, info.start);
@@ -135,7 +135,7 @@
}
TEST(MapsTest, verify_large_values) {
- MapInfo info(nullptr);
+ MapInfo info(nullptr, 0, 0, 0, 0, "");
#if defined(__LP64__)
VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info);
EXPECT_EQ(0xfabcdef012345678UL, info.start);
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 00264c2..472d1cf 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -182,7 +182,7 @@
RegsX86_64 regs_x86_64;
RegsMips regs_mips;
RegsMips64 regs_mips64;
- MapInfo map_info(nullptr, 0x1000, 0x2000);
+ MapInfo map_info(nullptr, 0x1000, 0x2000, 0, 0, "");
Elf* invalid_elf = new Elf(nullptr);
map_info.elf.reset(invalid_elf);
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index dc015b4..aab9ec2 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -298,7 +298,7 @@
EXPECT_EQ(
" #00 pc 00068fb8 libarttestd.so (_ZN3artL13CauseSegfaultEv+72)\n"
" #01 pc 00067f00 libarttestd.so (Java_Main_unwindInProcess+10032)\n"
- " #02 pc 000021a8 (offset 0x2000) 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
+ " #02 pc 000021a8 137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, "
"boolean)+136)\n"
" #03 pc 0000fe80 anonymous:ee74c000 (boolean Main.bar(boolean)+64)\n"
" #04 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
@@ -591,7 +591,7 @@
ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
" #00 pc 00018a5e libarttestd.so (Java_Main_unwindInProcess+866)\n"
- " #01 pc 0000212d (offset 0x2000) 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
+ " #01 pc 0000212d 137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, "
"boolean)+92)\n"
" #02 pc 00011cb1 anonymous:e2796000 (boolean Main.bar(boolean)+72)\n"
" #03 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
@@ -1135,29 +1135,29 @@
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
- " #00 pc 0032bfa0 (offset 0x42000) libunwindstack_test (SignalInnerFunction+40)\n"
- " #01 pc 0032bfeb (offset 0x42000) libunwindstack_test (SignalMiddleFunction+2)\n"
- " #02 pc 0032bff3 (offset 0x42000) libunwindstack_test (SignalOuterFunction+2)\n"
- " #03 pc 0032fed3 (offset 0x42000) libunwindstack_test "
+ " #00 pc 0032bfa0 libunwindstack_test (SignalInnerFunction+40)\n"
+ " #01 pc 0032bfeb libunwindstack_test (SignalMiddleFunction+2)\n"
+ " #02 pc 0032bff3 libunwindstack_test (SignalOuterFunction+2)\n"
+ " #03 pc 0032fed3 libunwindstack_test "
"(_ZN11unwindstackL19SignalCallerHandlerEiP7siginfoPv+26)\n"
- " #04 pc 00026528 (offset 0x25000) libc.so\n"
+ " #04 pc 00026528 libc.so\n"
" #05 pc 00000000 <unknown>\n"
- " #06 pc 0032c2d9 (offset 0x42000) libunwindstack_test (InnerFunction+736)\n"
- " #07 pc 0032cc4f (offset 0x42000) libunwindstack_test (MiddleFunction+42)\n"
- " #08 pc 0032cc81 (offset 0x42000) libunwindstack_test (OuterFunction+42)\n"
- " #09 pc 0032e547 (offset 0x42000) libunwindstack_test "
+ " #06 pc 0032c2d9 libunwindstack_test (InnerFunction+736)\n"
+ " #07 pc 0032cc4f libunwindstack_test (MiddleFunction+42)\n"
+ " #08 pc 0032cc81 libunwindstack_test (OuterFunction+42)\n"
+ " #09 pc 0032e547 libunwindstack_test "
"(_ZN11unwindstackL19RemoteThroughSignalEij+270)\n"
- " #10 pc 0032ed99 (offset 0x42000) libunwindstack_test "
+ " #10 pc 0032ed99 libunwindstack_test "
"(_ZN11unwindstack55UnwindTest_remote_through_signal_with_invalid_func_Test8TestBodyEv+16)\n"
- " #11 pc 00354453 (offset 0x42000) libunwindstack_test (_ZN7testing4Test3RunEv+154)\n"
- " #12 pc 00354de7 (offset 0x42000) libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n"
- " #13 pc 00355105 (offset 0x42000) libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n"
- " #14 pc 0035a215 (offset 0x42000) libunwindstack_test "
+ " #11 pc 00354453 libunwindstack_test (_ZN7testing4Test3RunEv+154)\n"
+ " #12 pc 00354de7 libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n"
+ " #13 pc 00355105 libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n"
+ " #14 pc 0035a215 libunwindstack_test "
"(_ZN7testing8internal12UnitTestImpl11RunAllTestsEv+664)\n"
- " #15 pc 00359f4f (offset 0x42000) libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n"
- " #16 pc 0034d3db (offset 0x42000) libunwindstack_test (main+38)\n"
- " #17 pc 00092c0d (offset 0x25000) libc.so (__libc_init+48)\n"
- " #18 pc 0004202f (offset 0x42000) libunwindstack_test (_start_main+38)\n",
+ " #15 pc 00359f4f libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n"
+ " #16 pc 0034d3db libunwindstack_test (main+38)\n"
+ " #17 pc 00092c0d libc.so (__libc_init+48)\n"
+ " #18 pc 0004202f libunwindstack_test (_start_main+38)\n",
frame_info);
EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc);
@@ -1248,14 +1248,14 @@
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
- " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n"
- " #01 pc 000000000005426c (offset 0x39000) linker64 "
+ " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
+ " #01 pc 000000000005426c linker64 "
"(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
" #02 pc 00000000000008bc vdso.so\n"
- " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n"
- " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n"
- " #05 pc 000000000003d5b4 (offset 0x40000) ANGLEPrebuilt.apk (ANGLEGetUtilityAPI+56)\n"
- " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n",
+ " #03 pc 00000000000846f4 libc.so (abort+172)\n"
+ " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
+ " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x4000) (ANGLEGetUtilityAPI+56)\n"
+ " #06 pc 000000000007fe68 libc.so (__libc_init)\n",
frame_info);
EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
@@ -1287,14 +1287,14 @@
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
- " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n"
- " #01 pc 000000000005426c (offset 0x39000) linker64 "
+ " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
+ " #01 pc 000000000005426c linker64 "
"(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
" #02 pc 00000000000008bc vdso.so\n"
- " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n"
- " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n"
- " #05 pc 000000000003d5b4 (offset 0x2211000) ANGLEPrebuilt.apk\n"
- " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n",
+ " #03 pc 00000000000846f4 libc.so (abort+172)\n"
+ " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
+ " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x21d5000)\n"
+ " #06 pc 000000000007fe68 libc.so (__libc_init)\n",
frame_info);
EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index c4b8763..1fdeee5 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -42,84 +42,64 @@
namespace unwindstack {
-class MapsFake : public Maps {
- public:
- MapsFake() = default;
- virtual ~MapsFake() = default;
-
- bool Parse() { return true; }
-
- void FakeClear() { maps_.clear(); }
-
- void FakeAddMapInfo(MapInfo* map_info) { maps_.push_back(map_info); }
-};
-
class UnwinderTest : public ::testing::Test {
protected:
+ static void AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+ const char* name, Elf* elf = nullptr) {
+ std::string str_name(name);
+ maps_->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
+ if (elf != nullptr) {
+ MapInfo* map_info = *--maps_->end();
+ map_info->elf.reset(elf);
+ }
+ }
+
static void SetUpTestCase() {
- maps_.FakeClear();
- MapInfo* info =
- new MapInfo(&maps_, 0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
+ maps_.reset(new Maps);
+
ElfFake* elf = new ElfFake(new MemoryFake);
- info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
- info = new MapInfo(&maps_, 0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
- info = new MapInfo(&maps_, 0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
- "/dev/fake_device");
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
+ "/dev/fake_device");
- info = new MapInfo(&maps_, 0x20000, 0x22000, 0, PROT_READ | PROT_WRITE,
- "/system/fake/libunwind.so");
elf = new ElfFake(new MemoryFake);
- info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so", elf);
- info = new MapInfo(&maps_, 0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
elf = new ElfFake(new MemoryFake);
- info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so", elf);
- info = new MapInfo(&maps_, 0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
elf = new ElfFake(new MemoryFake);
- info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);
- info = new MapInfo(&maps_, 0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
elf = new ElfFake(new MemoryFake);
- info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
- info = new MapInfo(&maps_, 0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
- info = new MapInfo(&maps_, 0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
- "/fake/fake.vdex");
+ AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+ MapInfo* info = *--maps_->end();
info->load_bias = 0;
- maps_.FakeAddMapInfo(info);
- info = new MapInfo(&maps_, 0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
- "/fake/fake_load_bias.so");
elf = new ElfFake(new MemoryFake);
- info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
elf->FakeSetLoadBias(0x5000);
- maps_.FakeAddMapInfo(info);
+ AddMapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_load_bias.so",
+ elf);
- info = new MapInfo(&maps_, 0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
- "/fake/fake_offset.oat");
elf = new ElfFake(new MemoryFake);
- info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_offset.oat",
+ elf);
+ info = *--maps_->end();
info->elf_offset = 0x8000;
- maps_.FakeAddMapInfo(info);
process_memory_.reset(new MemoryFake);
}
@@ -130,12 +110,12 @@
regs_.FakeSetReturnAddressValid(false);
}
- static MapsFake maps_;
+ static std::unique_ptr<Maps> maps_;
static RegsFake regs_;
static std::shared_ptr<Memory> process_memory_;
};
-MapsFake UnwinderTest::maps_;
+std::unique_ptr<Maps> UnwinderTest::maps_;
RegsFake UnwinderTest::regs_(5);
std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr);
@@ -150,7 +130,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -164,7 +144,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -178,7 +159,8 @@
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -192,7 +174,8 @@
EXPECT_EQ("Frame2", frame->function_name);
EXPECT_EQ(2U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -210,7 +193,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.SetResolveNames(false);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -225,7 +208,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -239,7 +223,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -253,7 +238,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -267,7 +253,7 @@
regs_.set_sp(0x10000);
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -281,7 +267,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xa5000U, frame->map_start);
EXPECT_EQ(0xa6000U, frame->map_end);
EXPECT_EQ(0x5000U, frame->map_load_bias);
@@ -295,7 +282,7 @@
regs_.set_sp(0x10000);
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -309,7 +296,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/fake/fake_offset.oat", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xa7000U, frame->map_start);
EXPECT_EQ(0xa8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -323,7 +311,7 @@
regs_.set_sp(0x10000);
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -337,7 +325,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/fake/fake.apk", frame->map_name);
- EXPECT_EQ(0x1d000U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0x1d000U, frame->map_exact_offset);
EXPECT_EQ(0x43000U, frame->map_start);
EXPECT_EQ(0x44000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -358,7 +347,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -372,7 +361,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -389,7 +379,7 @@
regs_.set_pc(0x1000);
regs_.set_sp(0x10000);
- Unwinder unwinder(20, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(20, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
@@ -404,7 +394,8 @@
EXPECT_EQ("Frame" + std::to_string(i), frame->function_name) << "Failed at frame " << i;
EXPECT_EQ(i, frame->function_offset) << "Failed at frame " << i;
EXPECT_EQ("/system/fake/libc.so", frame->map_name) << "Failed at frame " << i;
- EXPECT_EQ(0U, frame->map_offset) << "Failed at frame " << i;
+ EXPECT_EQ(0U, frame->map_elf_start_offset) << "Failed at frame " << i;
+ EXPECT_EQ(0U, frame->map_exact_offset) << "Failed at frame " << i;
EXPECT_EQ(0x1000U, frame->map_start) << "Failed at frame " << i;
EXPECT_EQ(0x8000U, frame->map_end) << "Failed at frame " << i;
EXPECT_EQ(0U, frame->map_load_bias) << "Failed at frame " << i;
@@ -429,7 +420,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10070, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
unwinder.Unwind(&skip_libs);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -444,7 +435,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -458,7 +450,8 @@
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x20000U, frame->map_start);
EXPECT_EQ(0x22000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -472,7 +465,7 @@
EXPECT_EQ("Frame2", frame->function_name);
EXPECT_EQ(2U, frame->function_offset);
EXPECT_EQ("/fake/libanother.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x23000U, frame->map_start);
EXPECT_EQ(0x24000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -489,7 +482,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -503,7 +496,7 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -517,7 +510,7 @@
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x20000U, frame->map_start);
EXPECT_EQ(0x22000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -536,7 +529,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -555,7 +548,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -569,7 +562,7 @@
regs_.set_pc(0x41000);
regs_.set_sp(0x13000);
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
@@ -583,7 +576,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0U, frame->map_start);
EXPECT_EQ(0U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -604,7 +598,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -618,7 +612,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0U, frame->map_start);
EXPECT_EQ(0U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -632,7 +627,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -646,7 +642,8 @@
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
EXPECT_EQ("/fake/libanother.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x23000U, frame->map_start);
EXPECT_EQ(0x24000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -666,7 +663,7 @@
regs_.FakeSetReturnAddress(0x12);
regs_.FakeSetReturnAddressValid(true);
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
@@ -680,7 +677,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x20000U, frame->map_start);
EXPECT_EQ(0x22000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -694,7 +692,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0U, frame->map_start);
EXPECT_EQ(0U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -713,7 +712,7 @@
regs_.FakeSetReturnAddress(0x1202);
regs_.FakeSetReturnAddressValid(true);
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -727,7 +726,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0U, frame->map_start);
EXPECT_EQ(0U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -741,7 +741,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -762,14 +763,14 @@
ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
std::vector<std::string> suffixes{"oat"};
unwinder.Unwind(nullptr, &suffixes);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(2U, unwinder.NumFrames());
// Make sure the elf was not initialized.
- MapInfo* map_info = maps_.Find(0x53000);
+ MapInfo* map_info = maps_->Find(0x53000);
ASSERT_TRUE(map_info != nullptr);
EXPECT_TRUE(map_info->elf == nullptr);
@@ -781,7 +782,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -795,7 +797,8 @@
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
EXPECT_EQ("/fake/fake.apk", frame->map_name);
- EXPECT_EQ(0x1d000U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0x1d000U, frame->map_exact_offset);
EXPECT_EQ(0x43000U, frame->map_start);
EXPECT_EQ(0x44000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -819,7 +822,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
@@ -833,7 +836,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -847,7 +851,8 @@
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
EXPECT_EQ("/fake/compressed.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x33000U, frame->map_start);
EXPECT_EQ(0x34000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -861,7 +866,8 @@
EXPECT_EQ("Frame2", frame->function_name);
EXPECT_EQ(2U, frame->function_offset);
EXPECT_EQ("/fake/compressed.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x33000U, frame->map_start);
EXPECT_EQ(0x34000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -874,7 +880,7 @@
regs_.set_sp(0x10000);
regs_.FakeSetDexPc(0xa3400);
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -888,7 +894,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/fake/fake.vdex", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xa3000U, frame->map_start);
EXPECT_EQ(0xa4000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -902,7 +909,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -915,7 +923,7 @@
regs_.set_sp(0x10000);
regs_.FakeSetDexPc(0x50000);
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -929,7 +937,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0U, frame->map_start);
EXPECT_EQ(0U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -943,7 +952,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -959,7 +969,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
- Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -973,7 +983,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/fake/fake.vdex", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xa3000U, frame->map_start);
EXPECT_EQ(0xa4000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -987,7 +998,8 @@
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x1000U, frame->map_start);
EXPECT_EQ(0x8000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -1001,7 +1013,8 @@
EXPECT_EQ("Frame1", frame->function_name);
EXPECT_EQ(1U, frame->function_offset);
EXPECT_EQ("/fake/compressed.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0x33000U, frame->map_start);
EXPECT_EQ(0x34000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -1014,7 +1027,7 @@
regs_.set_sp(0x10000);
regs_.FakeSetDexPc(0xa3400);
- Unwinder unwinder(1, &maps_, ®s_, process_memory_);
+ Unwinder unwinder(1, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
@@ -1028,7 +1041,8 @@
EXPECT_EQ("", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/fake/fake.vdex", frame->map_name);
- EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xa3000U, frame->map_start);
EXPECT_EQ(0xa4000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
@@ -1045,17 +1059,17 @@
frame.function_name = "function";
frame.function_offset = 100;
frame.map_name = "/fake/libfake.so";
- frame.map_offset = 0x2000;
+ frame.map_elf_start_offset = 0x2000;
frame.map_start = 0x3000;
frame.map_end = 0x6000;
frame.map_flags = PROT_READ;
- EXPECT_EQ(" #01 pc 0000000000001000 (offset 0x2000) /fake/libfake.so (function+100)",
+ EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)",
Unwinder::FormatFrame(frame, false));
- EXPECT_EQ(" #01 pc 00001000 (offset 0x2000) /fake/libfake.so (function+100)",
+ EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)",
Unwinder::FormatFrame(frame, true));
- frame.map_offset = 0;
+ frame.map_elf_start_offset = 0;
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
Unwinder::FormatFrame(frame, false));
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)",
@@ -1130,7 +1144,7 @@
for (auto regs : reg_list) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
- Unwinder unwinder(64, &maps_, regs, process_memory_);
+ Unwinder unwinder(64, maps_.get(), regs, process_memory_);
unwinder.Unwind();
ASSERT_EQ(1U, unwinder.NumFrames());
diff --git a/libunwindstack/tests/files/offline/offset_arm/maps.txt b/libunwindstack/tests/files/offline/offset_arm/maps.txt
index 6224464..768dd9f 100644
--- a/libunwindstack/tests/files/offline/offset_arm/maps.txt
+++ b/libunwindstack/tests/files/offline/offset_arm/maps.txt
@@ -1,2 +1,4 @@
+2b2a000-2b6c000 r--p 0 00:00 0 libunwindstack_test
2b6c000-2e92000 r-xp 42000 00:00 0 libunwindstack_test
+f4110000-f4135000 r--p 0 00:00 0 libc.so
f4135000-f41a9000 r-xp 25000 00:00 0 libc.so
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 652dbd1..5ae8874 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
@@ -46,6 +47,7 @@
uint64_t start;
uint64_t end;
uint64_t offset;
+ uint64_t flags;
std::string name;
};
@@ -163,14 +165,19 @@
return true;
}
-bool CopyElfFromFile(map_info_t* info) {
+bool CopyElfFromFile(map_info_t* info, bool* file_copied) {
+ std::string cur_name = basename(info->name.c_str());
+ if (*file_copied) {
+ info->name = cur_name;
+ return true;
+ }
+
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(info->name.c_str(), "r"), &fclose);
if (fp == nullptr) {
perror((std::string("Cannot open ") + info->name).c_str());
return false;
}
- std::string cur_name = basename(info->name.c_str());
std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
if (output == nullptr) {
perror((std::string("Cannot create file " + cur_name)).c_str());
@@ -193,6 +200,39 @@
return true;
}
+map_info_t* FillInAndGetMapInfo(std::unordered_map<uint64_t, map_info_t>& maps_by_start,
+ unwindstack::MapInfo* map_info) {
+ auto info = &maps_by_start[map_info->start];
+ info->start = map_info->start;
+ info->end = map_info->end;
+ info->offset = map_info->offset;
+ info->name = map_info->name;
+ info->flags = map_info->flags;
+
+ return info;
+}
+
+void SaveMapInformation(std::shared_ptr<unwindstack::Memory>& process_memory, map_info_t* info,
+ bool* file_copied) {
+ if (CopyElfFromFile(info, file_copied)) {
+ return;
+ }
+ *file_copied = false;
+
+ // Try to create the elf from memory, this will handle cases where
+ // the data only exists in memory such as vdso data on x86.
+ if (CreateElfFromMemory(process_memory, info)) {
+ return;
+ }
+
+ printf("Cannot save memory or file for map ");
+ if (!info->name.empty()) {
+ printf("%s\n", info->name.c_str());
+ } else {
+ printf("anonymous:%" PRIx64 "\n", info->start);
+ }
+}
+
int SaveData(pid_t pid) {
unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
if (regs == nullptr) {
@@ -237,22 +277,21 @@
}
if (maps_by_start.count(frame.map_start) == 0) {
- auto info = &maps_by_start[frame.map_start];
- info->start = frame.map_start;
- info->end = frame.map_end;
- info->offset = frame.map_offset;
- info->name = frame.map_name;
- if (!CopyElfFromFile(info)) {
- // Try to create the elf from memory, this will handle cases where
- // the data only exists in memory such as vdso data on x86.
- if (!CreateElfFromMemory(process_memory, info)) {
- printf("Ignoring map ");
- if (!info->name.empty()) {
- printf("%s\n", info->name.c_str());
- } else {
- printf("anonymous:%" PRIx64 "\n", info->start);
- }
- }
+ map_info = maps.Find(frame.map_start);
+
+ auto info = FillInAndGetMapInfo(maps_by_start, map_info);
+ bool file_copied = false;
+ SaveMapInformation(process_memory, info, &file_copied);
+
+ // If you are using a a linker that creates two maps (one read-only, one
+ // read-executable), it's necessary to capture the previous map
+ // information if needed.
+ unwindstack::MapInfo* prev_map = map_info->prev_map;
+ if (prev_map != nullptr && map_info->offset != 0 && prev_map->offset == 0 &&
+ prev_map->flags == PROT_READ && map_info->name == prev_map->name &&
+ maps_by_start.count(prev_map->start) == 0) {
+ info = FillInAndGetMapInfo(maps_by_start, prev_map);
+ SaveMapInformation(process_memory, info, &file_copied);
}
}
}
@@ -277,8 +316,18 @@
}
for (auto& element : sorted_maps) {
+ char perms[5] = {"---p"};
map_info_t& map = element.second;
- fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " r-xp %" PRIx64 " 00:00 0", map.start, map.end,
+ if (map.flags & PROT_READ) {
+ perms[0] = 'r';
+ }
+ if (map.flags & PROT_WRITE) {
+ perms[1] = 'w';
+ }
+ if (map.flags & PROT_EXEC) {
+ perms[2] = 'x';
+ }
+ fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " 00:00 0", map.start, map.end, perms,
map.offset);
if (!map.name.empty()) {
fprintf(fp.get(), " %s", map.name.c_str());
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 102fdf0..b3f943d 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -51,9 +51,6 @@
// --- Looper ---
-// Hint for number of file descriptors to be associated with the epoll instance.
-static const int EPOLL_SIZE_HINT = 8;
-
// Maximum number of file descriptors for which to retrieve poll events each iteration.
static const int EPOLL_MAX_EVENTS = 16;
@@ -139,7 +136,7 @@
}
// Allocate the new epoll instance and register the wake pipe.
- mEpollFd.reset(epoll_create(EPOLL_SIZE_HINT));
+ mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
struct epoll_event eventItem;
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 9eb7f2c..6b9f6e1 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -491,7 +491,7 @@
}
int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
- const int fd = ::android::base::utf8::open(fileName, O_RDONLY | O_BINARY, 0);
+ const int fd = ::android::base::utf8::open(fileName, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
ZipArchive* archive = new ZipArchive(fd, true);
*handle = archive;
diff --git a/llkd/README.md b/llkd/README.md
index 3da7a2f..224e184 100644
--- a/llkd/README.md
+++ b/llkd/README.md
@@ -160,7 +160,7 @@
NB: false is a very very very unlikely process to want to blacklist.
#### ro.llk.blacklist.parent
-default 0,2 (kernel and [kthreadd]).
+default 0,2,adbd (kernel, [kthreadd] and adbd).
The string "*false*" is the equivalent to an *empty* list.
Do not watch processes that have this parent.
A parent process can be comm, cmdline or pid reference.
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index b16b1d8..1efa32b 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -55,7 +55,11 @@
#define LLK_BLACKLIST_PROCESS_DEFAULT \
"0,1,2,init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
#define LLK_BLACKLIST_PARENT_PROPERTY "ro.llk.blacklist.parent"
+#ifdef __PTRACE_ENABLED__ // defined if userdebug build
+#define LLK_BLACKLIST_PARENT_DEFAULT "0,2,[kthreadd],adbd"
+#else
#define LLK_BLACKLIST_PARENT_DEFAULT "0,2,[kthreadd]"
+#endif
#define LLK_BLACKLIST_UID_PROPERTY "ro.llk.blacklist.uid"
#define LLK_BLACKLIST_UID_DEFAULT ""
#define LLK_BLACKLIST_STACK_PROPERTY "ro.llk.blacklist.process.stack"
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 969f26b..267da4a 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -510,9 +510,7 @@
return android::base::Trim(content) == string;
}
-void llkPanicKernel(bool dump, pid_t tid, const char* state,
- const std::string& message = "") __noreturn;
-void llkPanicKernel(bool dump, pid_t tid, const char* state, const std::string& message) {
+void llkPanicKernel(bool dump, pid_t tid, const char* state, const std::string& message = "") {
if (!message.empty()) LOG(ERROR) << message;
auto sysrqTriggerFd = llkFileToWriteFd("/proc/sysrq-trigger");
if (sysrqTriggerFd < 0) {
@@ -521,6 +519,7 @@
// The answer to life, the universe and everything
::exit(42);
// NOTREACHED
+ return;
}
::sync();
if (dump) {
@@ -544,6 +543,13 @@
llkWriteStringToFile(message + (message.empty() ? "" : "\n") +
"SysRq : Trigger a crash : 'livelock,"s + state + "'\n",
"/dev/kmsg");
+ // Because panic is such a serious thing to do, let us
+ // make sure that the tid being inspected still exists!
+ auto piddir = procdir + std::to_string(tid) + "/stat";
+ if (access(piddir.c_str(), F_OK) != 0) {
+ PLOG(WARNING) << piddir;
+ return;
+ }
android::base::WriteStringToFd("c", sysrqTriggerFd);
// NOTREACHED
// DYB
@@ -909,6 +915,7 @@
ms -= llkCycle;
auto myPid = ::getpid();
auto myTid = ::gettid();
+ auto dump = true;
for (auto dp = llkTopDirectory.read(); dp != nullptr; dp = llkTopDirectory.read()) {
std::string piddir;
@@ -1109,9 +1116,10 @@
const auto message = state + " "s + llkFormat(procp->count) + " " +
std::to_string(ppid) + "->" + std::to_string(pid) + "->" +
std::to_string(tid) + " " + procp->getComm() + " [panic]";
- llkPanicKernel(true, tid,
+ llkPanicKernel(dump, tid,
(state == 'Z') ? "zombie" : (state == 'D') ? "driver" : "sleeping",
message);
+ dump = false;
}
LOG(VERBOSE) << "+closedir()";
}
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 19e6d68..2fd9f95 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -55,8 +55,19 @@
mMsgLen(elem.mMsgLen),
mLogId(elem.mLogId),
mDropped(elem.mDropped) {
- mMsg = new char[mMsgLen];
- memcpy(mMsg, elem.mMsg, mMsgLen);
+ if (mDropped) {
+ if (elem.isBinary() && elem.mMsg != nullptr) {
+ // for the following "len" value, refer to : setDropped(uint16_t value), getTag()
+ const int len = sizeof(android_event_header_t);
+ mMsg = new char[len];
+ memcpy(mMsg, elem.mMsg, len);
+ } else {
+ mMsg = nullptr;
+ }
+ } else {
+ mMsg = new char[mMsgLen];
+ memcpy(mMsg, elem.mMsg, mMsgLen);
+ }
}
LogBufferElement::~LogBufferElement() {
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 264c612..e510c3c 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 = sphal,vndk,rs
###############################################################################
# "default" namespace
@@ -73,6 +73,7 @@
namespace.default.permitted.paths += /%PRODUCT_SERVICES%/priv-app
namespace.default.permitted.paths += /data
namespace.default.permitted.paths += /mnt/expand
+namespace.default.permitted.paths += /apex/com.android.resolv/${LIB}
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
@@ -105,28 +106,6 @@
namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
namespace.default.asan.permitted.paths += /mnt/expand
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
-namespace.default.links = runtime
-namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-namespace.default.link.runtime.shared_libs += libart.so:libartd.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
-
-###############################################################################
-# "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
-
###############################################################################
# "sphal" namespace
#
@@ -161,12 +140,8 @@
# Once in this namespace, access to libraries in /system/lib is restricted. Only
# libs listed here can be used.
-namespace.sphal.links = runtime,default,vndk,rs
+namespace.sphal.links = default,vndk,rs
-namespace.sphal.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
-# LLNDK_LIBRARIES includes the runtime libs above, but the order here ensures
-# that they are loaded from the runtime namespace.
namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -213,11 +188,9 @@
namespace.rs.asan.permitted.paths += /vendor/${LIB}
namespace.rs.asan.permitted.paths += /data
-namespace.rs.links = runtime,default,vndk
+namespace.rs.links = default,vndk
-namespace.rs.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
-namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
# namespace because RS framework libs are using them.
@@ -263,13 +236,10 @@
namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-# The "vndk" namespace links to "runtime" for Bionic libs, "default" namespace
-# for LLNDK libs, and links to "sphal" namespace for vendor libs. The ordering
-# matters. The "default" namespace has higher priority than the "sphal"
-# namespace.
-namespace.vndk.links = runtime,default,sphal
-
-namespace.vndk.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+# The "vndk" namespace links to "default" namespace for LLNDK libs and links to
+# "sphal" namespace for vendor libs. The ordering matters. The "default"
+# namespace has higher priority than the "sphal" namespace.
+namespace.vndk.links = default,sphal
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
@@ -280,7 +250,6 @@
# Allow VNDK-SP extensions to use vendor libraries
namespace.vndk.link.sphal.allow_all_shared_libs = true
-
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
@@ -288,7 +257,7 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-additional.namespaces = runtime,system,vndk
+additional.namespaces = system,vndk
###############################################################################
# "default" namespace
@@ -319,24 +288,12 @@
namespace.default.asan.permitted.paths += /data/asan/vendor
namespace.default.asan.permitted.paths += /vendor
-namespace.default.links = runtime,system,vndk
-namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+namespace.default.links = system,vndk
namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace pulls in externally accessible libs from the Runtime APEX.
-###############################################################################
-namespace.runtime.isolated = true
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
-namespace.runtime.link.default.allow_all_shared_libs = true
-
-###############################################################################
# "vndk" namespace
#
# This namespace is where VNDK and VNDK-SP libraries are loaded for
@@ -367,10 +324,7 @@
# When these NDK libs are required inside this namespace, then it is redirected
# to the system namespace. This is possible since their ABI is stable across
# Android releases.
-namespace.vndk.links = runtime,system,default
-
-namespace.vndk.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
+namespace.vndk.links = system,default
namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -395,36 +349,16 @@
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 = libc.so:libdl.so:libm.so
-
-
###############################################################################
# Namespace config for binaries under /postinstall.
-# Only default and runtime namespaces are defined and default has no directories
-# other than /system/lib in the search paths. This is because linker calls
-# realpath on the search paths and this causes selinux denial if the paths
-# (/vendor, /odm) are not allowed to the postinstall binaries. There is no
-# reason to allow the binaries to access the paths.
+# Only one default namespace is defined and it has no directories other than
+# /system/lib in the search paths. This is because linker calls realpath on the
+# search paths and this causes selinux denial if the paths (/vendor, /odm) are
+# not allowed to the poinstall binaries. There is no reason to allow the
+# binaries to access the paths.
###############################################################################
[postinstall]
-additional.namespaces = runtime
-
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
-
-namespace.default.links = runtime
-namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace pulls in externally accessible libs from the Runtime APEX.
-###############################################################################
-namespace.runtime.isolated = true
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
-namespace.runtime.link.default.allow_all_shared_libs = true
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 7ca45ff..7e354ac 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 = sphal,vndk,rs
###############################################################################
# "default" namespace
@@ -55,27 +55,6 @@
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.
-namespace.default.links = runtime
-namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-namespace.default.link.runtime.shared_libs += libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libnativehelper.so
-namespace.default.link.runtime.shared_libs += libnativeloader.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace pulls in externally accessible libs 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
-
###############################################################################
# "sphal" namespace
#
@@ -110,12 +89,8 @@
# Once in this namespace, access to libraries in /system/lib is restricted. Only
# libs listed here can be used.
-namespace.sphal.links = runtime,default,vndk,rs
+namespace.sphal.links = default,vndk,rs
-namespace.sphal.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
-# LLNDK_LIBRARIES includes the runtime libs above, but the order here ensures
-# that they are loaded from the runtime namespace.
namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -162,11 +137,9 @@
namespace.rs.asan.permitted.paths += /vendor/${LIB}
namespace.rs.asan.permitted.paths += /data
-namespace.rs.links = runtime,default,vndk
+namespace.rs.links = default,vndk
-namespace.rs.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
-namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
# namespace because RS framework libs are using them.
@@ -215,14 +188,10 @@
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
# Android releases.
-namespace.vndk.links = runtime,default
-
-namespace.vndk.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
+namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
@@ -230,7 +199,6 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-additional.namespaces = runtime
namespace.default.isolated = false
namespace.default.search.paths = /odm/${LIB}
@@ -240,7 +208,7 @@
namespace.default.search.paths += /vendor/${LIB}/vndk
namespace.default.search.paths += /vendor/${LIB}/vndk-sp
-# Access to system libraries is allowed
+# Access to system libraries are allowed
namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.default.search.paths += /system/${LIB}
@@ -270,47 +238,16 @@
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 = libc.so:libdl.so:libm.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace pulls in externally accessible libs from the Runtime APEX.
-###############################################################################
-namespace.runtime.isolated = true
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
-namespace.runtime.link.default.allow_all_shared_libs = true
-
-
###############################################################################
# Namespace config for binaries under /postinstall.
-# Only default and runtime namespaces are defined and default has no directories
-# other than /system/lib in the search paths. This is because linker calls
-# realpath on the search paths and this causes selinux denial if the paths
-# (/vendor, /odm) are not allowed to the postinstall binaries. There is no
-# reason to allow the binaries to access the paths.
+# Only one default namespace is defined and it has no directories other than
+# /system/lib in the search paths. This is because linker calls realpath on the
+# search paths and this causes selinux denial if the paths (/vendor, /odm) are
+# not allowed to the poinstall binaries. There is no reason to allow the
+# binaries to access the paths.
###############################################################################
[postinstall]
-additional.namespaces = runtime
-
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
-
-namespace.default.links = runtime
-namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace pulls in externally accessible libs from the Runtime APEX.
-###############################################################################
-namespace.runtime.isolated = true
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
-namespace.runtime.link.default.allow_all_shared_libs = true
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 349168e..483fc51 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -545,6 +545,7 @@
mkdir /data/anr 0775 system system
mkdir /data/apex 0770 root root
+ mkdir /data/staging 0750 system system
# NFC: create data/nfc for nv storage
mkdir /data/nfc 0770 nfc nfc
@@ -583,8 +584,8 @@
# Set SELinux security contexts on upgrade or policy update.
restorecon --recursive --skip-ce /data
- # Check any timezone data in /data is newer than the copy in /system, delete if not.
- exec - system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
+ # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
+ exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
# If there is no post-fs-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index a9658a4..35f469a 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -1,9 +1,6 @@
firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/
uevent_socket_rcvbuf_size 16M
-subsystem adf
- devname uevent_devname
-
subsystem graphics
devname uevent_devpath
dirname /dev/graphics
@@ -12,26 +9,10 @@
devname uevent_devpath
dirname /dev/dri
-subsystem oncrpc
- devname uevent_devpath
- dirname /dev/oncrpc
-
-subsystem adsp
- devname uevent_devpath
- dirname /dev/adsp
-
-subsystem msm_camera
- devname uevent_devpath
- dirname /dev/msm_camera
-
subsystem input
devname uevent_devpath
dirname /dev/input
-subsystem mtd
- devname uevent_devpath
- dirname /dev/mtd
-
subsystem sound
devname uevent_devpath
dirname /dev/snd
@@ -59,73 +40,27 @@
/dev/pmsg0 0222 root log
-# the msm hw3d client device node is world writable/readable.
-/dev/msm_hw3dc 0666 root root
-
-# gpu driver for adreno200 is globally accessible
-/dev/kgsl 0666 root root
-
# kms driver for drm based gpu
/dev/dri/* 0666 root graphics
# these should not be world writable
/dev/diag 0660 radio radio
-/dev/diag_arm9 0660 radio radio
/dev/ttyMSM0 0600 bluetooth bluetooth
/dev/uhid 0660 uhid uhid
/dev/uinput 0660 uhid uhid
-/dev/alarm 0664 system radio
/dev/rtc0 0640 system system
/dev/tty0 0660 root system
/dev/graphics/* 0660 root graphics
-/dev/msm_hw3dm 0660 system graphics
/dev/input/* 0660 root input
/dev/v4l-touch* 0660 root input
-/dev/eac 0660 root audio
-/dev/cam 0660 root camera
-/dev/pmem 0660 system graphics
-/dev/pmem_adsp* 0660 system audio
-/dev/pmem_camera* 0660 system camera
-/dev/oncrpc/* 0660 root system
-/dev/adsp/* 0660 system audio
/dev/snd/* 0660 system audio
-/dev/mt9t013 0660 system system
-/dev/msm_camera/* 0660 system system
-/dev/akm8976_daemon 0640 compass system
-/dev/akm8976_aot 0640 compass system
-/dev/akm8973_daemon 0640 compass system
-/dev/akm8973_aot 0640 compass system
-/dev/bma150 0640 compass system
-/dev/cm3602 0640 compass system
-/dev/akm8976_pffd 0640 compass system
-/dev/lightsensor 0640 system system
-/dev/msm_pcm_out* 0660 system audio
-/dev/msm_pcm_in* 0660 system audio
-/dev/msm_pcm_ctl* 0660 system audio
-/dev/msm_snd* 0660 system audio
/dev/msm_mp3* 0660 system audio
-/dev/audience_a1026* 0660 system audio
-/dev/tpa2018d1* 0660 system audio
-/dev/msm_audpre 0660 system audio
-/dev/msm_audio_ctl 0660 system audio
-/dev/htc-acoustic 0660 system audio
-/dev/vdec 0660 system audio
-/dev/q6venc 0660 system audio
-/dev/snd/dsp 0660 system audio
-/dev/snd/dsp1 0660 system audio
-/dev/snd/mixer 0660 system audio
-/dev/smd0 0640 radio radio
-/dev/qmi 0640 radio radio
-/dev/qmi0 0640 radio radio
-/dev/qmi1 0640 radio radio
-/dev/qmi2 0640 radio radio
/dev/bus/usb/* 0660 root usb
/dev/mtp_usb 0660 root mtp
/dev/usb_accessory 0660 root usb
/dev/tun 0660 system vpn
# CDMA radio interface MUX
-/dev/ts0710mux* 0640 radio radio
/dev/ppp 0660 radio vpn
# sysfs properties
@@ -135,6 +70,3 @@
/sys/devices/virtual/usb_composite/* enable 0664 root system
/sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system
/sys/devices/system/cpu/cpu* cpufreq/scaling_min_freq 0664 system system
-
-# DVB API device nodes
-/dev/dvb* 0660 root system