Merge "Export ion_4.12.h and ion_4.19.h"
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index ed6a9a8..e8be784 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -173,7 +173,8 @@
RSA* key = RSA_new();
if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
- LOG(ERROR) << "Failed to read key";
+ LOG(ERROR) << "Failed to read key from '" << file << "'";
+ ERR_print_errors_fp(stderr);
RSA_free(key);
return nullptr;
}
@@ -249,7 +250,7 @@
return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
}
-static bool generate_userkey() {
+static bool load_userkey() {
std::string path = get_user_key_path();
if (path.empty()) {
PLOG(ERROR) << "Error getting user key filename";
@@ -435,8 +436,8 @@
void adb_auth_init() {
LOG(INFO) << "adb_auth_init...";
- if (!generate_userkey()) {
- LOG(ERROR) << "Failed to generate user key";
+ if (!load_userkey()) {
+ LOG(ERROR) << "Failed to load (or generate) user key";
return;
}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index e50f7c3..c1a8dae 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -112,13 +112,16 @@
};
void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
- // The fileencryption flag is followed by an = and the mode of contents encryption, then
- // optionally a and the mode of filenames encryption (defaults to aes-256-cts). Get it and
- // return it.
+ // The fileencryption flag is followed by an = and 1 to 3 colon-separated fields:
+ //
+ // 1. Contents encryption mode
+ // 2. Filenames encryption mode (defaults to "aes-256-cts" or "adiantum"
+ // depending on the contents encryption mode)
+ // 3. Encryption policy version (defaults to "v1". Use "v2" on new devices.)
entry->fs_mgr_flags.file_encryption = true;
auto parts = Split(arg, ":");
- if (parts.empty() || parts.size() > 2) {
+ if (parts.empty() || parts.size() > 3) {
LWARNING << "Warning: fileencryption= flag malformed: " << arg;
return;
}
@@ -137,7 +140,7 @@
entry->file_contents_mode = parts[0];
- if (parts.size() == 2) {
+ if (parts.size() >= 2) {
if (std::find(kFileNamesEncryptionMode.begin(), kFileNamesEncryptionMode.end(), parts[1]) ==
kFileNamesEncryptionMode.end()) {
LWARNING << "fileencryption= flag malformed, file names encryption mode not found: "
@@ -151,6 +154,16 @@
} else {
entry->file_names_mode = "aes-256-cts";
}
+
+ if (parts.size() >= 3) {
+ if (!android::base::StartsWith(parts[2], 'v') ||
+ !android::base::ParseInt(&parts[2][1], &entry->file_policy_version)) {
+ LWARNING << "fileencryption= flag malformed, unknown options: " << arg;
+ return;
+ }
+ } else {
+ entry->file_policy_version = 1;
+ }
}
bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
@@ -288,6 +301,7 @@
entry->key_loc = arg;
entry->file_contents_mode = "aes-256-xts";
entry->file_names_mode = "aes-256-cts";
+ entry->file_policy_version = 1;
} else if (StartsWith(flag, "max_comp_streams=")) {
if (!ParseInt(arg, &entry->max_comp_streams)) {
LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 358c980..0579a3d 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -782,6 +782,7 @@
} else {
fs_mgr_set_blk_ro(device_path, false);
}
+ entry.fs_mgr_flags.check = true;
auto save_errno = errno;
auto mounted = fs_mgr_do_mount_one(entry) == 0;
if (!mounted) {
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index d999ae1..3c517dc 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -47,6 +47,7 @@
off64_t reserved_size = 0;
std::string file_contents_mode;
std::string file_names_mode;
+ int file_policy_version = 0;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
std::string sysfs_path;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 834bf3b..8cf0f3b 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -49,11 +49,17 @@
"libfiemap_headers",
],
export_include_dirs: ["include"],
+ proto: {
+ type: "lite",
+ export_proto_headers: true,
+ canonical_path_from_root: false,
+ },
}
filegroup {
name: "libsnapshot_sources",
srcs: [
+ "android/snapshot/snapshot.proto",
"snapshot.cpp",
"snapshot_metadata_updater.cpp",
"partition_cow_creator.cpp",
@@ -132,9 +138,10 @@
"libbinder",
"libext4_utils",
"libfs_mgr",
- "libutils",
"liblog",
"liblp",
+ "libprotobuf-cpp-lite",
+ "libutils",
],
init_rc: [
"snapshotctl.rc",
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
new file mode 100644
index 0000000..629c3a4
--- /dev/null
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -0,0 +1,87 @@
+// Copyright (C) 2019 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.
+
+syntax = "proto3";
+package android.snapshot;
+
+option optimize_for = LITE_RUNTIME;
+
+// Next: 4
+enum SnapshotState {
+ // No snapshot is found.
+ NONE = 0;
+
+ // The snapshot has been created and possibly written to. Rollbacks are
+ // possible by destroying the snapshot.
+ CREATED = 1;
+
+ // Changes are being merged. No rollbacks are possible beyond this point.
+ MERGING = 2;
+
+ // Changes have been merged, Future reboots may map the base device
+ // directly.
+ MERGE_COMPLETED = 3;
+}
+
+// Next: 9
+message SnapshotStatus {
+ // Name of the snapshot. This is usually the name of the snapshotted
+ // logical partition; for example, "system_b".
+ string name = 1;
+
+ SnapshotState state = 2;
+
+ // Size of the full (base) device.
+ uint64 device_size = 3;
+
+ // Size of the snapshot. This is the sum of lengths of ranges in the base
+ // device that needs to be snapshotted during the update.
+ // This must be less than or equal to |device_size|.
+ // This value is 0 if no snapshot is needed for this device because
+ // no changes
+ uint64 snapshot_size = 4;
+
+ // Size of the "COW partition". A COW partition is a special logical
+ // partition represented in the super partition metadata. This partition and
+ // the "COW image" form the "COW device" that supports the snapshot device.
+ //
+ // When SnapshotManager creates a COW device, it first searches for unused
+ // blocks in the super partition, and use those before creating the COW
+ // image if the COW partition is not big enough.
+ //
+ // This value is 0 if no space in super is left for the COW partition.
+ // |cow_partition_size + cow_file_size| must not be zero if |snapshot_size|
+ // is non-zero.
+ uint64 cow_partition_size = 5;
+
+ // Size of the "COW file", or "COW image". A COW file / image is created
+ // when the "COW partition" is not big enough to store changes to the
+ // snapshot device.
+ //
+ // This value is 0 if |cow_partition_size| is big enough to hold all changes
+ // to the snapshot device.
+ uint64 cow_file_size = 6;
+
+ // Sectors allocated for the COW device. Recording this value right after
+ // the update and before the merge allows us to infer the progress of the
+ // merge process.
+ // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
+ uint64 sectors_allocated = 7;
+
+ // Metadata sectors allocated for the COW device. Recording this value right
+ // before the update and before the merge allows us to infer the progress of
+ // the merge process.
+ // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
+ uint64 metadata_sectors = 8;
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 0d6aa2c..69f2895 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -53,8 +53,9 @@
struct AutoDeleteCowImage;
struct AutoDeleteSnapshot;
-struct PartitionCowCreator;
struct AutoDeviceList;
+struct PartitionCowCreator;
+class SnapshotStatus;
static constexpr const std::string_view kCowGroupName = "cow";
@@ -250,22 +251,6 @@
std::unique_ptr<LockedFile> OpenFile(const std::string& file, int open_flags, int lock_flags);
bool Truncate(LockedFile* file);
- enum class SnapshotState : int { None, Created, Merging, MergeCompleted };
- static std::string to_string(SnapshotState state);
-
- // This state is persisted per-snapshot in /metadata/ota/snapshots/.
- struct SnapshotStatus {
- SnapshotState state = SnapshotState::None;
- uint64_t device_size = 0;
- uint64_t snapshot_size = 0;
- uint64_t cow_partition_size = 0;
- uint64_t cow_file_size = 0;
-
- // These are non-zero when merging.
- uint64_t sectors_allocated = 0;
- uint64_t metadata_sectors = 0;
- };
-
// Create a new snapshot record. This creates the backing COW store and
// persists information needed to map the device. The device can be mapped
// with MapSnapshot().
@@ -282,7 +267,7 @@
//
// All sizes are specified in bytes, and the device, snapshot, COW partition and COW file sizes
// must be a multiple of the sector size (512 bytes).
- bool CreateSnapshot(LockedFile* lock, const std::string& name, SnapshotStatus status);
+ bool CreateSnapshot(LockedFile* lock, SnapshotStatus* status);
// |name| should be the base partition name (e.g. "system_a"). Create the
// backing COW image using the size previously passed to CreateSnapshot().
@@ -363,8 +348,7 @@
UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name);
// Interact with status files under /metadata/ota/snapshots.
- bool WriteSnapshotStatus(LockedFile* lock, const std::string& name,
- const SnapshotStatus& status);
+ bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status);
std::string GetSnapshotStatusFilePath(const std::string& name);
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 404ef27..eedc1cd 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
+#include <android/snapshot/snapshot.pb.h>
#include "utility.h"
using android::dm::kSectorSize;
@@ -84,13 +85,14 @@
<< "logical_block_size is not power of 2";
Return ret;
- ret.snapshot_status.device_size = target_partition->size();
+ ret.snapshot_status.set_name(target_partition->name());
+ ret.snapshot_status.set_device_size(target_partition->size());
// TODO(b/141889746): Optimize by using a smaller snapshot. Some ranges in target_partition
// may be written directly.
- ret.snapshot_status.snapshot_size = target_partition->size();
+ ret.snapshot_status.set_snapshot_size(target_partition->size());
- auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size);
+ auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size());
if (!cow_size.has_value()) return std::nullopt;
// Compute regions that are free in both current and target metadata. These are the regions
@@ -106,18 +108,20 @@
LOG(INFO) << "Remaining free space for COW: " << free_region_length << " bytes";
// Compute the COW partition size.
- ret.snapshot_status.cow_partition_size = std::min(*cow_size, free_region_length);
+ uint64_t cow_partition_size = std::min(*cow_size, free_region_length);
// Round it down to the nearest logical block. Logical partitions must be a multiple
// of logical blocks.
- ret.snapshot_status.cow_partition_size &= ~(logical_block_size - 1);
+ cow_partition_size &= ~(logical_block_size - 1);
+ ret.snapshot_status.set_cow_partition_size(cow_partition_size);
// Assign cow_partition_usable_regions to indicate what regions should the COW partition uses.
ret.cow_partition_usable_regions = std::move(free_regions);
// The rest of the COW space is allocated on ImageManager.
- ret.snapshot_status.cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size;
+ uint64_t cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size();
// Round it up to the nearest sector.
- ret.snapshot_status.cow_file_size += kSectorSize - 1;
- ret.snapshot_status.cow_file_size &= ~(kSectorSize - 1);
+ cow_file_size += kSectorSize - 1;
+ cow_file_size &= ~(kSectorSize - 1);
+ ret.snapshot_status.set_cow_file_size(cow_file_size);
return ret;
}
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.h b/fs_mgr/libsnapshot/partition_cow_creator.h
index 0e645c6..8888f78 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.h
+++ b/fs_mgr/libsnapshot/partition_cow_creator.h
@@ -20,8 +20,9 @@
#include <string>
#include <liblp/builder.h>
+#include <update_engine/update_metadata.pb.h>
-#include <libsnapshot/snapshot.h>
+#include <android/snapshot/snapshot.pb.h>
namespace android {
namespace snapshot {
@@ -51,7 +52,7 @@
const RepeatedPtrField<InstallOperation>* operations = nullptr;
struct Return {
- SnapshotManager::SnapshotStatus snapshot_status;
+ SnapshotStatus snapshot_status;
std::vector<Interval> cow_partition_usable_regions;
};
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index ccd087e..feb3c2d 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -51,8 +51,8 @@
.current_suffix = "_a"};
auto ret = creator.Run();
ASSERT_TRUE(ret.has_value());
- ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size);
- ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size);
+ ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size());
+ ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size());
}
TEST_F(PartitionCowCreatorTest, Holes) {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 02c7de6..5b758c9 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -38,6 +38,7 @@
#include <libfiemap/image_manager.h>
#include <liblp/liblp.h>
+#include <android/snapshot/snapshot.pb.h>
#include "partition_cow_creator.h"
#include "snapshot_metadata_updater.h"
#include "utility.h"
@@ -234,42 +235,50 @@
return WriteUpdateState(lock.get(), UpdateState::Unverified);
}
-bool SnapshotManager::CreateSnapshot(LockedFile* lock, const std::string& name,
- SnapshotManager::SnapshotStatus status) {
+bool SnapshotManager::CreateSnapshot(LockedFile* lock, SnapshotStatus* status) {
CHECK(lock);
CHECK(lock->lock_mode() == LOCK_EX);
+ CHECK(status);
+
+ if (status->name().empty()) {
+ LOG(ERROR) << "SnapshotStatus has no name.";
+ return false;
+ }
// Sanity check these sizes. Like liblp, we guarantee the partition size
// is respected, which means it has to be sector-aligned. (This guarantee
// is useful for locating avb footers correctly). The COW file size, however,
// can be arbitrarily larger than specified, so we can safely round it up.
- if (status.device_size % kSectorSize != 0) {
- LOG(ERROR) << "Snapshot " << name
- << " device size is not a multiple of the sector size: " << status.device_size;
+ if (status->device_size() % kSectorSize != 0) {
+ LOG(ERROR) << "Snapshot " << status->name()
+ << " device size is not a multiple of the sector size: "
+ << status->device_size();
return false;
}
- if (status.snapshot_size % kSectorSize != 0) {
- LOG(ERROR) << "Snapshot " << name << " snapshot size is not a multiple of the sector size: "
- << status.snapshot_size;
+ if (status->snapshot_size() % kSectorSize != 0) {
+ LOG(ERROR) << "Snapshot " << status->name()
+ << " snapshot size is not a multiple of the sector size: "
+ << status->snapshot_size();
return false;
}
- if (status.cow_partition_size % kSectorSize != 0) {
- LOG(ERROR) << "Snapshot " << name
+ if (status->cow_partition_size() % kSectorSize != 0) {
+ LOG(ERROR) << "Snapshot " << status->name()
<< " cow partition size is not a multiple of the sector size: "
- << status.cow_partition_size;
+ << status->cow_partition_size();
return false;
}
- if (status.cow_file_size % kSectorSize != 0) {
- LOG(ERROR) << "Snapshot " << name << " cow file size is not a multiple of the sector size: "
- << status.cow_partition_size;
+ if (status->cow_file_size() % kSectorSize != 0) {
+ LOG(ERROR) << "Snapshot " << status->name()
+ << " cow file size is not a multiple of the sector size: "
+ << status->cow_file_size();
return false;
}
- status.state = SnapshotState::Created;
- status.sectors_allocated = 0;
- status.metadata_sectors = 0;
+ status->set_state(SnapshotState::CREATED);
+ status->set_sectors_allocated(0);
+ status->set_metadata_sectors(0);
- if (!WriteSnapshotStatus(lock, name, status)) {
- PLOG(ERROR) << "Could not write snapshot status: " << name;
+ if (!WriteSnapshotStatus(lock, *status)) {
+ PLOG(ERROR) << "Could not write snapshot status: " << status->name();
return false;
}
return true;
@@ -287,15 +296,15 @@
// The COW file size should have been rounded up to the nearest sector in CreateSnapshot.
// Sanity check this.
- if (status.cow_file_size % kSectorSize != 0) {
+ if (status.cow_file_size() % kSectorSize != 0) {
LOG(ERROR) << "Snapshot " << name << " COW file size is not a multiple of the sector size: "
- << status.cow_file_size;
+ << status.cow_file_size();
return false;
}
std::string cow_image_name = GetCowImageDeviceName(name);
int cow_flags = IImageManager::CREATE_IMAGE_DEFAULT;
- return images_->CreateBackingImage(cow_image_name, status.cow_file_size, cow_flags);
+ return images_->CreateBackingImage(cow_image_name, status.cow_file_size(), cow_flags);
}
bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
@@ -309,7 +318,7 @@
if (!ReadSnapshotStatus(lock, name, &status)) {
return false;
}
- if (status.state == SnapshotState::MergeCompleted) {
+ if (status.state() == SnapshotState::MERGE_COMPLETED) {
LOG(ERROR) << "Should not create a snapshot device for " << name
<< " after merging has completed.";
return false;
@@ -328,24 +337,23 @@
PLOG(ERROR) << "Could not determine block device size: " << base_device;
return false;
}
- if (status.device_size != dev_size) {
+ if (status.device_size() != dev_size) {
LOG(ERROR) << "Block device size for " << base_device << " does not match"
- << "(expected " << status.device_size << ", got " << dev_size << ")";
+ << "(expected " << status.device_size() << ", got " << dev_size << ")";
return false;
}
}
- if (status.device_size % kSectorSize != 0) {
- LOG(ERROR) << "invalid blockdev size for " << base_device << ": " << status.device_size;
+ if (status.device_size() % kSectorSize != 0) {
+ LOG(ERROR) << "invalid blockdev size for " << base_device << ": " << status.device_size();
return false;
}
- if (status.snapshot_size % kSectorSize != 0 || status.snapshot_size > status.device_size) {
- LOG(ERROR) << "Invalid snapshot size for " << base_device << ": " << status.snapshot_size;
+ if (status.snapshot_size() % kSectorSize != 0 ||
+ status.snapshot_size() > status.device_size()) {
+ LOG(ERROR) << "Invalid snapshot size for " << base_device << ": " << status.snapshot_size();
return false;
}
- uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
- uint64_t linear_sectors = (status.device_size - status.snapshot_size) / kSectorSize;
-
-
+ uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
+ uint64_t linear_sectors = (status.device_size() - status.snapshot_size()) / kSectorSize;
auto& dm = DeviceMapper::Instance();
@@ -557,8 +565,9 @@
if (!ReadSnapshotStatus(lock, name, &status)) {
return false;
}
- if (status.state != SnapshotState::Created) {
- LOG(WARNING) << "Snapshot " << name << " has unexpected state: " << to_string(status.state);
+ if (status.state() != SnapshotState::CREATED) {
+ LOG(WARNING) << "Snapshot " << name
+ << " has unexpected state: " << SnapshotState_Name(status.state());
}
// After this, we return true because we technically did switch to a merge
@@ -568,15 +577,15 @@
return false;
}
- status.state = SnapshotState::Merging;
+ status.set_state(SnapshotState::MERGING);
DmTargetSnapshot::Status dm_status;
if (!QuerySnapshotStatus(dm_name, nullptr, &dm_status)) {
LOG(ERROR) << "Could not query merge status for snapshot: " << dm_name;
}
- status.sectors_allocated = dm_status.sectors_allocated;
- status.metadata_sectors = dm_status.metadata_sectors;
- if (!WriteSnapshotStatus(lock, name, status)) {
+ status.set_sectors_allocated(dm_status.sectors_allocated);
+ status.set_metadata_sectors(dm_status.metadata_sectors);
+ if (!WriteSnapshotStatus(lock, status)) {
LOG(ERROR) << "Could not update status file for snapshot: " << name;
}
return true;
@@ -821,7 +830,7 @@
// rebooted after this check, the device will still be a snapshot-merge
// target. If the have rebooted, the device will now be a linear target,
// and we can try cleanup again.
- if (snapshot_status.state == SnapshotState::MergeCompleted) {
+ if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
// NB: It's okay if this fails now, we gave cleanup our best effort.
OnSnapshotMergeComplete(lock, name, snapshot_status);
return UpdateState::MergeCompleted;
@@ -849,7 +858,7 @@
// These two values are equal when merging is complete.
if (status.sectors_allocated != status.metadata_sectors) {
- if (snapshot_status.state == SnapshotState::MergeCompleted) {
+ if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
LOG(ERROR) << "Snapshot " << name << " is merging after being marked merge-complete.";
return UpdateState::MergeFailed;
}
@@ -864,8 +873,8 @@
// This makes it simpler to reason about the next reboot: no matter what
// part of cleanup failed, first-stage init won't try to create another
// snapshot device for this partition.
- snapshot_status.state = SnapshotState::MergeCompleted;
- if (!WriteSnapshotStatus(lock, name, snapshot_status)) {
+ snapshot_status.set_state(SnapshotState::MERGE_COMPLETED);
+ if (!WriteSnapshotStatus(lock, snapshot_status)) {
return UpdateState::MergeFailed;
}
if (!OnSnapshotMergeComplete(lock, name, snapshot_status)) {
@@ -969,10 +978,10 @@
return false;
}
- uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
- if (snapshot_sectors * kSectorSize != status.snapshot_size) {
+ uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
+ if (snapshot_sectors * kSectorSize != status.snapshot_size()) {
LOG(ERROR) << "Snapshot " << name
- << " size is not sector aligned: " << status.snapshot_size;
+ << " size is not sector aligned: " << status.snapshot_size();
return false;
}
@@ -1003,7 +1012,7 @@
<< " sectors, got: " << outer_table[0].spec.length;
return false;
}
- uint64_t expected_device_sectors = status.device_size / kSectorSize;
+ uint64_t expected_device_sectors = status.device_size() / kSectorSize;
uint64_t actual_device_sectors = outer_table[0].spec.length + outer_table[1].spec.length;
if (expected_device_sectors != actual_device_sectors) {
LOG(ERROR) << "Outer device " << name << " should have " << expected_device_sectors
@@ -1289,7 +1298,7 @@
return false;
}
// No live snapshot if merge is completed.
- if (live_snapshot_status->state == SnapshotState::MergeCompleted) {
+ if (live_snapshot_status->state() == SnapshotState::MERGE_COMPLETED) {
live_snapshot_status.reset();
}
} while (0);
@@ -1390,7 +1399,7 @@
AutoDeviceList* created_devices, std::string* cow_name) {
CHECK(lock);
if (!EnsureImageManager()) return false;
- CHECK(snapshot_status.cow_partition_size + snapshot_status.cow_file_size > 0);
+ CHECK(snapshot_status.cow_partition_size() + snapshot_status.cow_file_size() > 0);
auto begin = std::chrono::steady_clock::now();
std::string partition_name = params.GetPartitionName();
@@ -1400,7 +1409,7 @@
auto& dm = DeviceMapper::Instance();
// Map COW image if necessary.
- if (snapshot_status.cow_file_size > 0) {
+ if (snapshot_status.cow_file_size() > 0) {
auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
@@ -1411,7 +1420,7 @@
created_devices->EmplaceBack<AutoUnmapImage>(images_.get(), cow_image_name);
// If no COW partition exists, just return the image alone.
- if (snapshot_status.cow_partition_size == 0) {
+ if (snapshot_status.cow_partition_size() == 0) {
*cow_name = std::move(cow_image_name);
LOG(INFO) << "Mapped COW image for " << partition_name << " at " << *cow_name;
return true;
@@ -1421,7 +1430,7 @@
auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
- CHECK(snapshot_status.cow_partition_size > 0);
+ CHECK(snapshot_status.cow_partition_size() > 0);
// Create the DmTable for the COW device. It is the DmTable of the COW partition plus
// COW image device as the last extent.
@@ -1434,14 +1443,14 @@
return false;
}
// If the COW image exists, append it as the last extent.
- if (snapshot_status.cow_file_size > 0) {
+ if (snapshot_status.cow_file_size() > 0) {
std::string cow_image_device;
if (!dm.GetDeviceString(cow_image_name, &cow_image_device)) {
LOG(ERROR) << "Cannot determine major/minor for: " << cow_image_name;
return false;
}
- auto cow_partition_sectors = snapshot_status.cow_partition_size / kSectorSize;
- auto cow_image_sectors = snapshot_status.cow_file_size / kSectorSize;
+ auto cow_partition_sectors = snapshot_status.cow_partition_size() / kSectorSize;
+ auto cow_image_sectors = snapshot_status.cow_file_size() / kSectorSize;
table.Emplace<DmTargetLinear>(cow_partition_sectors, cow_image_sectors, cow_image_device,
0);
}
@@ -1602,101 +1611,38 @@
return false;
}
- std::string contents;
- if (!android::base::ReadFdToString(fd, &contents)) {
- PLOG(ERROR) << "read failed: " << path;
- return false;
- }
- auto pieces = android::base::Split(contents, " ");
- if (pieces.size() != 7) {
- LOG(ERROR) << "Invalid status line for snapshot: " << path;
+ if (!status->ParseFromFileDescriptor(fd.get())) {
+ PLOG(ERROR) << "Unable to parse " << path << " as SnapshotStatus";
return false;
}
- if (pieces[0] == "none") {
- status->state = SnapshotState::None;
- } else if (pieces[0] == "created") {
- status->state = SnapshotState::Created;
- } else if (pieces[0] == "merging") {
- status->state = SnapshotState::Merging;
- } else if (pieces[0] == "merge-completed") {
- status->state = SnapshotState::MergeCompleted;
- } else {
- LOG(ERROR) << "Unrecognized state " << pieces[0] << " for snapshot: " << name;
- return false;
+ if (status->name() != name) {
+ LOG(WARNING) << "Found snapshot status named " << status->name() << " in " << path;
+ status->set_name(name);
}
- if (!android::base::ParseUint(pieces[1], &status->device_size)) {
- LOG(ERROR) << "Invalid device size in status line for: " << path;
- return false;
- }
- if (!android::base::ParseUint(pieces[2], &status->snapshot_size)) {
- LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
- return false;
- }
- if (!android::base::ParseUint(pieces[3], &status->cow_partition_size)) {
- LOG(ERROR) << "Invalid cow linear size in status line for: " << path;
- return false;
- }
- if (!android::base::ParseUint(pieces[4], &status->cow_file_size)) {
- LOG(ERROR) << "Invalid cow file size in status line for: " << path;
- return false;
- }
- if (!android::base::ParseUint(pieces[5], &status->sectors_allocated)) {
- LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
- return false;
- }
- if (!android::base::ParseUint(pieces[6], &status->metadata_sectors)) {
- LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
- return false;
- }
return true;
}
-std::string SnapshotManager::to_string(SnapshotState state) {
- switch (state) {
- case SnapshotState::None:
- return "none";
- case SnapshotState::Created:
- return "created";
- case SnapshotState::Merging:
- return "merging";
- case SnapshotState::MergeCompleted:
- return "merge-completed";
- default:
- LOG(ERROR) << "Unknown snapshot state: " << (int)state;
- return "unknown";
- }
-}
-
-bool SnapshotManager::WriteSnapshotStatus(LockedFile* lock, const std::string& name,
- const SnapshotStatus& status) {
+bool SnapshotManager::WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status) {
// The caller must take an exclusive lock to modify snapshots.
CHECK(lock);
CHECK(lock->lock_mode() == LOCK_EX);
+ CHECK(!status.name().empty());
- auto path = GetSnapshotStatusFilePath(name);
- unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_SYNC, 0660));
+ auto path = GetSnapshotStatusFilePath(status.name());
+ unique_fd fd(
+ open(path.c_str(), O_RDWR | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_SYNC | O_TRUNC, 0660));
if (fd < 0) {
PLOG(ERROR) << "Open failed: " << path;
return false;
}
- std::vector<std::string> pieces = {
- to_string(status.state),
- std::to_string(status.device_size),
- std::to_string(status.snapshot_size),
- std::to_string(status.cow_partition_size),
- std::to_string(status.cow_file_size),
- std::to_string(status.sectors_allocated),
- std::to_string(status.metadata_sectors),
- };
- auto contents = android::base::Join(pieces, " ");
-
- if (!android::base::WriteStringToFd(contents, fd)) {
- PLOG(ERROR) << "write failed: " << path;
+ if (!status.SerializeToFileDescriptor(fd.get())) {
+ PLOG(ERROR) << "Unable to write SnapshotStatus to " << path;
return false;
}
+
return true;
}
@@ -1714,7 +1660,7 @@
std::string SnapshotManager::GetSnapshotDeviceName(const std::string& snapshot_name,
const SnapshotStatus& status) {
- if (status.device_size != status.snapshot_size) {
+ if (status.device_size() != status.snapshot_size()) {
return GetSnapshotExtraDeviceName(snapshot_name);
}
return snapshot_name;
@@ -1884,11 +1830,11 @@
}
LOG(INFO) << "For partition " << target_partition->name()
- << ", device size = " << cow_creator_ret->snapshot_status.device_size
- << ", snapshot size = " << cow_creator_ret->snapshot_status.snapshot_size
+ << ", device size = " << cow_creator_ret->snapshot_status.device_size()
+ << ", snapshot size = " << cow_creator_ret->snapshot_status.snapshot_size()
<< ", cow partition size = "
- << cow_creator_ret->snapshot_status.cow_partition_size
- << ", cow file size = " << cow_creator_ret->snapshot_status.cow_file_size;
+ << cow_creator_ret->snapshot_status.cow_partition_size()
+ << ", cow file size = " << cow_creator_ret->snapshot_status.cow_file_size();
// Delete any existing snapshot before re-creating one.
if (!DeleteSnapshot(lock, target_partition->name())) {
@@ -1899,9 +1845,9 @@
// It is possible that the whole partition uses free space in super, and snapshot / COW
// would not be needed. In this case, skip the partition.
- bool needs_snapshot = cow_creator_ret->snapshot_status.snapshot_size > 0;
- bool needs_cow = (cow_creator_ret->snapshot_status.cow_partition_size +
- cow_creator_ret->snapshot_status.cow_file_size) > 0;
+ bool needs_snapshot = cow_creator_ret->snapshot_status.snapshot_size() > 0;
+ bool needs_cow = (cow_creator_ret->snapshot_status.cow_partition_size() +
+ cow_creator_ret->snapshot_status.cow_file_size()) > 0;
CHECK(needs_snapshot == needs_cow);
if (!needs_snapshot) {
@@ -1911,17 +1857,17 @@
}
// Store these device sizes to snapshot status file.
- if (!CreateSnapshot(lock, target_partition->name(), cow_creator_ret->snapshot_status)) {
+ if (!CreateSnapshot(lock, &cow_creator_ret->snapshot_status)) {
return false;
}
created_devices->EmplaceBack<AutoDeleteSnapshot>(this, lock, target_partition->name());
// Create the COW partition. That is, use any remaining free space in super partition before
// creating the COW images.
- if (cow_creator_ret->snapshot_status.cow_partition_size > 0) {
- CHECK(cow_creator_ret->snapshot_status.cow_partition_size % kSectorSize == 0)
+ if (cow_creator_ret->snapshot_status.cow_partition_size() > 0) {
+ CHECK(cow_creator_ret->snapshot_status.cow_partition_size() % kSectorSize == 0)
<< "cow_partition_size == "
- << cow_creator_ret->snapshot_status.cow_partition_size
+ << cow_creator_ret->snapshot_status.cow_partition_size()
<< " is not a multiple of sector size " << kSectorSize;
auto cow_partition = target_metadata->AddPartition(GetCowName(target_partition->name()),
kCowGroupName, 0 /* flags */);
@@ -1930,10 +1876,10 @@
}
if (!target_metadata->ResizePartition(
- cow_partition, cow_creator_ret->snapshot_status.cow_partition_size,
+ cow_partition, cow_creator_ret->snapshot_status.cow_partition_size(),
cow_creator_ret->cow_partition_usable_regions)) {
LOG(ERROR) << "Cannot create COW partition on metadata with size "
- << cow_creator_ret->snapshot_status.cow_partition_size;
+ << cow_creator_ret->snapshot_status.cow_partition_size();
return false;
}
// Only the in-memory target_metadata is modified; nothing to clean up if there is an
@@ -1941,7 +1887,7 @@
}
// Create the backing COW image if necessary.
- if (cow_creator_ret->snapshot_status.cow_file_size > 0) {
+ if (cow_creator_ret->snapshot_status.cow_file_size() > 0) {
if (!CreateCowImage(lock, target_partition->name())) {
return false;
}
@@ -2049,13 +1995,13 @@
ok = false;
continue;
}
- ss << " state: " << to_string(status.state) << std::endl;
- ss << " device size (bytes): " << status.device_size << std::endl;
- ss << " snapshot size (bytes): " << status.snapshot_size << std::endl;
- ss << " cow partition size (bytes): " << status.cow_partition_size << std::endl;
- ss << " cow file size (bytes): " << status.cow_file_size << std::endl;
- ss << " allocated sectors: " << status.sectors_allocated << std::endl;
- ss << " metadata sectors: " << status.metadata_sectors << std::endl;
+ ss << " state: " << SnapshotState_Name(status.state()) << std::endl;
+ ss << " device size (bytes): " << status.device_size() << std::endl;
+ ss << " snapshot size (bytes): " << status.snapshot_size() << std::endl;
+ ss << " cow partition size (bytes): " << status.cow_partition_size() << std::endl;
+ ss << " cow file size (bytes): " << status.cow_file_size() << std::endl;
+ ss << " allocated sectors: " << status.sectors_allocated() << std::endl;
+ ss << " metadata sectors: " << status.metadata_sectors() << std::endl;
}
os << ss.rdbuf();
return ok;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f3994c1..fd7754e 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -33,6 +33,7 @@
#include <liblp/builder.h>
#include <storage_literals/storage_literals.h>
+#include <android/snapshot/snapshot.pb.h>
#include "test_helpers.h"
#include "utility.h"
@@ -272,10 +273,12 @@
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
- {.device_size = kDeviceSize,
- .snapshot_size = kDeviceSize,
- .cow_file_size = kDeviceSize}));
+ SnapshotStatus status;
+ status.set_name("test-snapshot");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kDeviceSize);
+ status.set_cow_file_size(kDeviceSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test-snapshot"));
std::vector<std::string> snapshots;
@@ -285,11 +288,11 @@
// Scope so delete can re-acquire the snapshot file lock.
{
- SnapshotManager::SnapshotStatus status;
+ SnapshotStatus status;
ASSERT_TRUE(sm->ReadSnapshotStatus(lock_.get(), "test-snapshot", &status));
- ASSERT_EQ(status.state, SnapshotManager::SnapshotState::Created);
- ASSERT_EQ(status.device_size, kDeviceSize);
- ASSERT_EQ(status.snapshot_size, kDeviceSize);
+ ASSERT_EQ(status.state(), SnapshotState::CREATED);
+ ASSERT_EQ(status.device_size(), kDeviceSize);
+ ASSERT_EQ(status.snapshot_size(), kDeviceSize);
}
ASSERT_TRUE(sm->UnmapSnapshot(lock_.get(), "test-snapshot"));
@@ -301,10 +304,12 @@
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
- {.device_size = kDeviceSize,
- .snapshot_size = kDeviceSize,
- .cow_file_size = kDeviceSize}));
+ SnapshotStatus status;
+ status.set_name("test-snapshot");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kDeviceSize);
+ status.set_cow_file_size(kDeviceSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test-snapshot"));
std::string base_device;
@@ -324,10 +329,12 @@
static const uint64_t kSnapshotSize = 1024 * 1024;
static const uint64_t kDeviceSize = 1024 * 1024 * 2;
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
- {.device_size = kDeviceSize,
- .snapshot_size = kSnapshotSize,
- .cow_file_size = kSnapshotSize}));
+ SnapshotStatus status;
+ status.set_name("test-snapshot");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kSnapshotSize);
+ status.set_cow_file_size(kSnapshotSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test-snapshot"));
std::string base_device;
@@ -377,10 +384,12 @@
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
ASSERT_TRUE(MapUpdatePartitions());
ASSERT_TRUE(dm_.GetDmDevicePathByName("test_partition_b-base", &base_device));
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
- {.device_size = kDeviceSize,
- .snapshot_size = kDeviceSize,
- .cow_file_size = kDeviceSize}));
+ SnapshotStatus status;
+ status.set_name("test_partition_b");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kDeviceSize);
+ status.set_cow_file_size(kDeviceSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test_partition_b"));
ASSERT_TRUE(MapCowImage("test_partition_b", 10s, &cow_device));
ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test_partition_b", base_device, cow_device, 10s,
@@ -436,10 +445,12 @@
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
- {.device_size = kDeviceSize,
- .snapshot_size = kDeviceSize,
- .cow_file_size = kDeviceSize}));
+ SnapshotStatus status;
+ status.set_name("test-snapshot");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kDeviceSize);
+ status.set_cow_file_size(kDeviceSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test-snapshot"));
std::string base_device, cow_device, snap_device;
@@ -492,10 +503,12 @@
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
ASSERT_TRUE(MapUpdatePartitions());
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
- {.device_size = kDeviceSize,
- .snapshot_size = kDeviceSize,
- .cow_file_size = kDeviceSize}));
+ SnapshotStatus status;
+ status.set_name("test_partition_b");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kDeviceSize);
+ status.set_cow_file_size(kDeviceSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test_partition_b"));
// Simulate a reboot into the new slot.
@@ -511,9 +524,8 @@
ASSERT_TRUE(AcquireLock());
// Validate that we have a snapshot device.
- SnapshotManager::SnapshotStatus status;
ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
- ASSERT_EQ(status.state, SnapshotManager::SnapshotState::Created);
+ ASSERT_EQ(status.state(), SnapshotState::CREATED);
DeviceMapper::TargetInfo target;
auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
@@ -528,10 +540,12 @@
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
ASSERT_TRUE(MapUpdatePartitions());
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
- {.device_size = kDeviceSize,
- .snapshot_size = kDeviceSize,
- .cow_file_size = kDeviceSize}));
+ SnapshotStatus status;
+ status.set_name("test_partition_b");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kDeviceSize);
+ status.set_cow_file_size(kDeviceSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test_partition_b"));
// Simulate a reboot into the new slot.
@@ -550,7 +564,6 @@
ASSERT_TRUE(AcquireLock());
- SnapshotManager::SnapshotStatus status;
ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
// We should not get a snapshot device now.
@@ -570,10 +583,12 @@
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
ASSERT_TRUE(MapUpdatePartitions());
- ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
- {.device_size = kDeviceSize,
- .snapshot_size = kDeviceSize,
- .cow_file_size = kDeviceSize}));
+ SnapshotStatus status;
+ status.set_name("test_partition_b");
+ status.set_device_size(kDeviceSize);
+ status.set_snapshot_size(kDeviceSize);
+ status.set_cow_file_size(kDeviceSize);
+ ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
ASSERT_TRUE(CreateCowImage("test_partition_b"));
// Simulate a reboot into the new slot.
@@ -699,11 +714,11 @@
}
auto local_lock = std::move(lock_);
- SnapshotManager::SnapshotStatus status;
+ SnapshotStatus status;
if (!sm->ReadSnapshotStatus(local_lock.get(), name, &status)) {
return std::nullopt;
}
- return status.snapshot_size;
+ return status.snapshot_size();
}
AssertionResult UnmapAll() {
@@ -869,8 +884,9 @@
{
ASSERT_TRUE(AcquireLock());
auto local_lock = std::move(lock_);
- ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), "sys_b",
- SnapshotManager::SnapshotStatus{}));
+ SnapshotStatus status;
+ status.set_name("sys_b");
+ ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), status));
ASSERT_TRUE(image_manager_->CreateBackingImage("sys_b-cow-img", 1_MiB,
IImageManager::CREATE_IMAGE_DEFAULT));
}
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index f445703..4226e95 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -38,6 +38,8 @@
EMPTY=""
SPACE=" "
+# Line up wrap to [ XXXXXXX ] messages.
+INDENT=" "
# A _real_ embedded tab character
TAB="`echo | tr '\n' '\t'`"
# A _real_ embedded escape character
@@ -159,8 +161,7 @@
return
fi
echo "${ORANGE}[ WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2
- echo "${L}" |
- sed 's/^/ /' >&2
+ echo "${L}" | sed "s/^/${INDENT}/" >&2
}
[ "USAGE: get_property <prop>
@@ -639,10 +640,10 @@
*}" ]; then
echo "${prefix} expected \"${lval}\""
echo "${prefix} got \"${rval}\"" |
- sed ': again
+ sed ": again
N
- s/\(\n\)\([^ ]\)/\1 \2/
- t again'
+ s/\(\n\)\([^ ]\)/\1${INDENT}\2/
+ t again"
if [ -n "${*}" ] ; then
echo "${prefix} ${*}"
fi
@@ -657,10 +658,10 @@
if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
echo "${prefix} ok \"${lval}\""
echo " = \"${rval}\"" |
- sed ': again
+ sed ": again
N
- s/\(\n\)\([^ ]\)/\1 \2/
- t again'
+ s/\(\n\)\([^ ]\)/\1${INDENT}\2/
+ t again"
if [ -n "${*}" ] ; then
echo "${prefix} ${*}"
fi
@@ -955,13 +956,24 @@
echo "${GREEN}[ RUN ]${NORMAL} Testing adb shell su root remount -R command" >&2
avc_check
- adb_su remount -R system </dev/null || true
+ T=`adb_date`
+ adb_su remount -R system </dev/null
+ err=${?}
+ if [ "${err}" != 0 ]; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2
+ T="-t ${T}"
+ else
+ # Rebooted, logcat will be meaningless, and last logcat will likely be clear
+ T=""
+ fi
sleep 2
adb_wait ${ADB_WAIT} ||
- die "waiting for device after remount -R `usb_status`"
+ die "waiting for device after adb shell su root remount -R system `usb_status`"
if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
"2" = "`get_property partition.system.verified`" ]; then
- die "remount -R command failed"
+ die ${T} "remount -R command failed
+${INDENT}ro.boot.verifiedbootstate=\"`get_property ro.boot.verifiedbootstate`\"
+${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
fi
echo "${GREEN}[ OK ]${NORMAL} adb shell su root remount -R command" >&2
@@ -1643,15 +1655,24 @@
if ${overlayfs_supported}; then
echo "${GREEN}[ RUN ]${NORMAL} test 'adb remount -R'" >&2
avc_check
- adb_root &&
- adb remount -R &&
- adb_wait ${ADB_WAIT} ||
- die "adb remount -R"
+ adb_root ||
+ die "adb root in preparation for adb remount -R"
+ T=`adb_date`
+ adb remount -R
+ err=${?}
+ if [ "${err}" != 0 ]; then
+ die -t ${T} "adb remount -R = ${err}"
+ fi
+ sleep 2
+ adb_wait ${ADB_WAIT} ||
+ die "waiting for device after adb remount -R `usb_status`"
if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
"2" = "`get_property partition.system.verified`" ] &&
[ -n "`get_property ro.boot.verifiedbootstate`" -o \
-n "`get_property partition.system.verified`" ]; then
- die "remount -R command failed to disable verity"
+ die "remount -R command failed to disable verity
+${INDENT}ro.boot.verifiedbootstate=\"`get_property ro.boot.verifiedbootstate`\"
+${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
fi
echo "${GREEN}[ OK ]${NORMAL} 'adb remount -R' command" >&2
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 6d87594..a7ea817 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -467,6 +467,7 @@
}
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
EXPECT_EQ("", entry->key_loc);
}
@@ -682,6 +683,7 @@
EXPECT_EQ("/dir/key", entry->key_loc);
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) {
@@ -698,14 +700,18 @@
source none7 swap defaults fileencryption=ice:aes-256-cts
source none8 swap defaults fileencryption=ice:aes-256-heh
source none9 swap defaults fileencryption=ice:adiantum
-source none10 swap defaults fileencryption=ice:adiantum:
+source none10 swap defaults fileencryption=aes-256-xts:aes-256-cts:v1
+source none11 swap defaults fileencryption=aes-256-xts:aes-256-cts:v2
+source none12 swap defaults fileencryption=aes-256-xts:aes-256-cts:v2:
+source none13 swap defaults fileencryption=aes-256-xts:aes-256-cts:blah
+source none14 swap defaults fileencryption=aes-256-xts:aes-256-cts:vblah
)fs";
ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
Fstab fstab;
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
- ASSERT_EQ(11U, fstab.size());
+ ASSERT_EQ(15U, fstab.size());
FstabEntry::FsMgrFlags flags = {};
flags.file_encryption = true;
@@ -715,66 +721,105 @@
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("", entry->file_contents_mode);
EXPECT_EQ("", entry->file_names_mode);
+ EXPECT_EQ(0, entry->file_policy_version);
entry++;
EXPECT_EQ("none1", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none2", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none3", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("adiantum", entry->file_contents_mode);
EXPECT_EQ("adiantum", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none4", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("adiantum", entry->file_contents_mode);
EXPECT_EQ("aes-256-heh", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none5", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none6", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("", entry->file_names_mode);
+ EXPECT_EQ(0, entry->file_policy_version);
entry++;
EXPECT_EQ("none7", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none8", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("aes-256-heh", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none9", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("adiantum", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
entry++;
EXPECT_EQ("none10", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+ EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(1, entry->file_policy_version);
+
+ entry++;
+ EXPECT_EQ("none11", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+ EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(2, entry->file_policy_version);
+
+ entry++;
+ EXPECT_EQ("none12", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("", entry->file_contents_mode);
EXPECT_EQ("", entry->file_names_mode);
+ EXPECT_EQ(0, entry->file_policy_version);
+
+ entry++;
+ EXPECT_EQ("none13", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+ EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(0, entry->file_policy_version);
+
+ entry++;
+ EXPECT_EQ("none14", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+ EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+ EXPECT_EQ(0, entry->file_policy_version);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MaxCompStreams) {
diff --git a/init/Android.bp b/init/Android.bp
index b601075..9b2ddc0 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -76,7 +76,6 @@
"libbase",
"libbootloader_message",
"libcutils",
- "libcrypto",
"libdl",
"libext4_utils",
"libfs_mgr",
diff --git a/init/Android.mk b/init/Android.mk
index 62e452f..8fc44da 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -113,6 +113,7 @@
libbacktrace \
libmodprobe \
libext2_uuid \
+ libprotobuf-cpp-lite \
libsnapshot_nobinder \
LOCAL_SANITIZE := signed-integer-overflow
diff --git a/init/fscrypt_init_extensions.cpp b/init/fscrypt_init_extensions.cpp
index bd23e31..bbebbe8 100644
--- a/init/fscrypt_init_extensions.cpp
+++ b/init/fscrypt_init_extensions.cpp
@@ -28,6 +28,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
@@ -163,33 +164,59 @@
return err;
}
+static int parse_encryption_options_string(const std::string& options_string,
+ std::string* contents_mode_ret,
+ std::string* filenames_mode_ret,
+ int* policy_version_ret) {
+ auto parts = android::base::Split(options_string, ":");
+
+ if (parts.size() != 3) {
+ return -1;
+ }
+
+ *contents_mode_ret = parts[0];
+ *filenames_mode_ret = parts[1];
+ if (!android::base::StartsWith(parts[2], 'v') ||
+ !android::base::ParseInt(&parts[2][1], policy_version_ret)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+// Set an encryption policy on the given directory. The policy (key reference
+// and encryption options) to use is read from files that were written by vold.
static int set_policy_on(const std::string& ref_basename, const std::string& dir) {
std::string ref_filename = std::string("/data") + ref_basename;
- std::string policy;
- if (!android::base::ReadFileToString(ref_filename, &policy)) {
+ std::string key_ref;
+ if (!android::base::ReadFileToString(ref_filename, &key_ref)) {
LOG(ERROR) << "Unable to read system policy to set on " << dir;
return -1;
}
- auto type_filename = std::string("/data") + fscrypt_key_mode;
- std::string modestring;
- if (!android::base::ReadFileToString(type_filename, &modestring)) {
- LOG(ERROR) << "Cannot read mode";
+ auto options_filename = std::string("/data") + fscrypt_key_mode;
+ std::string options_string;
+ if (!android::base::ReadFileToString(options_filename, &options_string)) {
+ LOG(ERROR) << "Cannot read encryption options string";
+ return -1;
}
- std::vector<std::string> modes = android::base::Split(modestring, ":");
+ std::string contents_mode;
+ std::string filenames_mode;
+ int policy_version = 0;
- if (modes.size() < 1 || modes.size() > 2) {
- LOG(ERROR) << "Invalid encryption mode string: " << modestring;
+ if (parse_encryption_options_string(options_string, &contents_mode, &filenames_mode,
+ &policy_version)) {
+ LOG(ERROR) << "Invalid encryption options string: " << options_string;
return -1;
}
int result =
- fscrypt_policy_ensure(dir.c_str(), policy.c_str(), policy.length(), modes[0].c_str(),
- modes.size() >= 2 ? modes[1].c_str() : "aes-256-cts");
+ fscrypt_policy_ensure(dir.c_str(), key_ref.c_str(), key_ref.length(),
+ contents_mode.c_str(), filenames_mode.c_str(), policy_version);
if (result) {
LOG(ERROR) << android::base::StringPrintf("Setting %02x%02x%02x%02x policy on %s failed!",
- policy[0], policy[1], policy[2], policy[3],
+ key_ref[0], key_ref[1], key_ref[2], key_ref[3],
dir.c_str());
return -1;
}
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index e3068b2..71f78a5 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -55,7 +55,7 @@
// reboot_utils.h
inline void SetFatalRebootTarget() {}
-inline void __attribute__((noreturn)) InitFatalReboot() {
+inline void __attribute__((noreturn)) InitFatalReboot(int signal_number) {
abort();
}
diff --git a/init/init.cpp b/init/init.cpp
index ad31fa0..ab6dbcf 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -98,7 +98,6 @@
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
static std::string wait_prop_value;
-static bool shutting_down;
static std::string shutdown_command;
static bool do_shutdown = false;
static bool load_debug_prop = false;
@@ -624,7 +623,15 @@
auto init_message = InitMessage{};
init_message.set_stop_sending_messages(true);
if (auto result = SendMessage(property_fd, init_message); !result) {
- LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
+ LOG(ERROR) << "Failed to send 'stop sending messages' message: " << result.error();
+ }
+}
+
+void SendStartSendingMessagesMessage() {
+ auto init_message = InitMessage{};
+ init_message.set_start_sending_messages(true);
+ if (auto result = SendMessage(property_fd, init_message); !result) {
+ LOG(ERROR) << "Failed to send 'start sending messages' message: " << result.error();
}
}
@@ -811,18 +818,16 @@
// By default, sleep until something happens.
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
- if (do_shutdown && !shutting_down) {
+ if (do_shutdown && !IsShuttingDown()) {
do_shutdown = false;
- if (HandlePowerctlMessage(shutdown_command)) {
- shutting_down = true;
- }
+ HandlePowerctlMessage(shutdown_command);
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
- if (!shutting_down) {
+ if (!IsShuttingDown()) {
auto next_process_action_time = HandleProcessActions();
// If there's a process that needs restarting, wake up in time for that.
diff --git a/init/init.h b/init/init.h
index 61fb110..c7918e7 100644
--- a/init/init.h
+++ b/init/init.h
@@ -41,6 +41,7 @@
void SendLoadPersistentPropertiesMessage();
void SendStopSendingMessagesMessage();
+void SendStartSendingMessagesMessage();
int SecondStageMain(int argc, char** argv);
diff --git a/init/property_service.cpp b/init/property_service.cpp
index d7e4021..c6bbc14 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -93,6 +93,7 @@
static int property_set_fd = -1;
static int init_socket = -1;
+static bool accept_messages = false;
static PropertyInfoAreaFile property_info_area;
@@ -211,7 +212,7 @@
}
// If init hasn't started its main loop, then it won't be handling property changed messages
// anyway, so there's no need to try to send them.
- if (init_socket != -1) {
+ if (accept_messages) {
SendPropertyChanged(name, value);
}
return PROP_SUCCESS;
@@ -389,7 +390,7 @@
static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
SocketConnection* socket, std::string* error) {
- if (init_socket == -1) {
+ if (!accept_messages) {
*error = "Received control message after shutdown, ignoring";
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
}
@@ -1035,7 +1036,11 @@
break;
}
case InitMessage::kStopSendingMessages: {
- init_socket = -1;
+ accept_messages = false;
+ break;
+ }
+ case InitMessage::kStartSendingMessages: {
+ accept_messages = true;
break;
}
default:
@@ -1078,6 +1083,7 @@
}
*epoll_socket = sockets[0];
init_socket = sockets[1];
+ accept_messages = true;
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
false, 0666, 0, 0, {})) {
diff --git a/init/property_service.proto b/init/property_service.proto
index ea454d4..08268d9 100644
--- a/init/property_service.proto
+++ b/init/property_service.proto
@@ -40,5 +40,6 @@
oneof msg {
bool load_persistent_properties = 1;
bool stop_sending_messages = 2;
+ bool start_sending_messages = 3;
};
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 30836d2..41965a1 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -50,7 +50,9 @@
#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
+#include "action.h"
#include "action_manager.h"
+#include "builtin_arguments.h"
#include "init.h"
#include "property_service.h"
#include "reboot_utils.h"
@@ -71,6 +73,8 @@
namespace android {
namespace init {
+static bool shutting_down = false;
+
// represents umount status during reboot / shutdown.
enum UmountStat {
/* umount succeeded. */
@@ -655,12 +659,58 @@
abort();
}
-bool HandlePowerctlMessage(const std::string& command) {
+static void EnterShutdown() {
+ shutting_down = true;
+ // Skip wait for prop if it is in progress
+ ResetWaitForProp();
+ // Clear EXEC flag if there is one pending
+ for (const auto& s : ServiceList::GetInstance()) {
+ s->UnSetExec();
+ }
+ // We no longer process messages about properties changing coming from property service, so we
+ // need to tell property service to stop sending us these messages, otherwise it'll fill the
+ // buffers and block indefinitely, causing future property sets, including those that init makes
+ // during shutdown in Service::NotifyStateChange() to also block indefinitely.
+ SendStopSendingMessagesMessage();
+}
+
+static void LeaveShutdown() {
+ shutting_down = false;
+ SendStartSendingMessagesMessage();
+}
+
+static void DoUserspaceReboot() {
+ // Triggering userspace-reboot-requested will result in a bunch of set_prop
+ // actions. We should make sure, that all of them are propagated before
+ // proceeding with userspace reboot.
+ // TODO(b/135984674): implement proper synchronization logic.
+ std::this_thread::sleep_for(500ms);
+ EnterShutdown();
+ // TODO(b/135984674): tear down post-data services
+ LeaveShutdown();
+ // TODO(b/135984674): remount userdata
+ ActionManager::GetInstance().QueueEventTrigger("userspace-reboot-resume");
+}
+
+static void HandleUserspaceReboot() {
+ LOG(INFO) << "Clearing queue and starting userspace-reboot-requested trigger";
+ auto& am = ActionManager::GetInstance();
+ am.ClearQueue();
+ am.QueueEventTrigger("userspace-reboot-requested");
+ auto handler = [](const BuiltinArguments&) {
+ DoUserspaceReboot();
+ return Result<void>{};
+ };
+ am.QueueBuiltinAction(handler, "userspace-reboot");
+}
+
+void HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
std::vector<std::string> cmd_params = Split(command, ",");
std::string reboot_target = "";
bool run_fsck = false;
bool command_invalid = false;
+ bool userspace_reboot = false;
if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
@@ -680,6 +730,10 @@
cmd = ANDROID_RB_RESTART2;
if (cmd_params.size() >= 2) {
reboot_target = cmd_params[1];
+ if (reboot_target == "userspace") {
+ LOG(INFO) << "Userspace reboot requested";
+ userspace_reboot = true;
+ }
// adb reboot fastboot should boot into bootloader for devices not
// supporting logical partitions.
if (reboot_target == "fastboot" &&
@@ -706,7 +760,7 @@
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
if (std::string err; !write_bootloader_message(boot, &err)) {
LOG(ERROR) << "Failed to set bootloader message: " << err;
- return false;
+ return;
}
}
} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
@@ -719,7 +773,7 @@
std::string err;
if (!write_bootloader_message(options, &err)) {
LOG(ERROR) << "Failed to set bootloader message: " << err;
- return false;
+ return;
}
reboot_target = "recovery";
}
@@ -734,7 +788,12 @@
}
if (command_invalid) {
LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
- return false;
+ return;
+ }
+
+ if (userspace_reboot) {
+ HandleUserspaceReboot();
+ return;
}
LOG(INFO) << "Clear action queue and start shutdown trigger";
@@ -748,21 +807,11 @@
};
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
- // Skip wait for prop if it is in progress
- ResetWaitForProp();
+ EnterShutdown();
+}
- // Clear EXEC flag if there is one pending
- for (const auto& s : ServiceList::GetInstance()) {
- s->UnSetExec();
- }
-
- // We no longer process messages about properties changing coming from property service, so we
- // need to tell property service to stop sending us these messages, otherwise it'll fill the
- // buffers and block indefinitely, causing future property sets, including those that init makes
- // during shutdown in Service::NotifyStateChange() to also block indefinitely.
- SendStopSendingMessagesMessage();
-
- return true;
+bool IsShuttingDown() {
+ return shutting_down;
}
} // namespace init
diff --git a/init/reboot.h b/init/reboot.h
index 07dcb6e..81c3edc 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -23,8 +23,9 @@
namespace init {
// Parses and handles a setprop sys.powerctl message.
-bool HandlePowerctlMessage(const std::string& command);
+void HandlePowerctlMessage(const std::string& command);
+bool IsShuttingDown();
} // namespace init
} // namespace android
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index de085cc..dac0cf4 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -109,7 +109,7 @@
abort();
}
-void __attribute__((noreturn)) InitFatalReboot() {
+void __attribute__((noreturn)) InitFatalReboot(int signal_number) {
auto pid = fork();
if (pid == -1) {
@@ -124,6 +124,7 @@
}
// In the parent, let's try to get a backtrace then shutdown.
+ LOG(ERROR) << __FUNCTION__ << ": signal " << signal_number;
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
if (!backtrace->Unwind(0)) {
@@ -154,7 +155,7 @@
// RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
// and probably good enough given this is already an error case and only enabled for
// development builds.
- InitFatalReboot();
+ InitFatalReboot(signal);
};
action.sa_flags = SA_RESTART;
sigaction(SIGABRT, &action, nullptr);
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index 3fd969e..878ad96 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -27,7 +27,7 @@
bool IsRebootCapable();
// This is a wrapper around the actual reboot calls.
void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target);
-void __attribute__((noreturn)) InitFatalReboot();
+void __attribute__((noreturn)) InitFatalReboot(int signal_number);
void InstallRebootSignalHandlers();
} // namespace init
diff --git a/init/service.cpp b/init/service.cpp
index 0b73dc5..a2db070 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -300,7 +300,7 @@
LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times "
<< (boot_completed ? "in 4 minutes" : "before boot completed");
// Notifies update_verifier and apexd
- property_set("ro.init.updatable_crashing", "1");
+ property_set("sys.init.updatable_crashing", "1");
}
}
} else {
diff --git a/init/util.cpp b/init/util.cpp
index 0532375..40db838 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -481,7 +482,7 @@
return;
}
- InitFatalReboot();
+ InitFatalReboot(SIGABRT);
}
// The kernel opens /dev/console and uses that fd for stdin/stdout/stderr if there is a serial
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index d0d83de..5fb11a5 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -161,7 +161,6 @@
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" },
- { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00550, AID_LOGD, AID_LOGD, 0, "system/bin/logd" },
{ 00700, AID_ROOT, AID_ROOT, 0, "system/bin/secilc" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
@@ -173,9 +172,10 @@
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" },
- { 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" },
+ { 00750, AID_ROOT, AID_ROOT, 0, "vendor/bin/install-recovery.sh" },
{ 00600, AID_ROOT, AID_ROOT, 0, "vendor/build.prop" },
{ 00600, AID_ROOT, AID_ROOT, 0, "vendor/default.prop" },
+ { 00440, AID_ROOT, AID_ROOT, 0, "vendor/etc/recovery.img" },
{ 00444, AID_ROOT, AID_ROOT, 0, ven_conf_dir + 1 },
{ 00444, AID_ROOT, AID_ROOT, 0, ven_conf_file + 1 },
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 916a428..619cf8c 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -67,12 +67,12 @@
.name = "logd",
.available = logdAvailable,
.version = logdVersion,
+ .close = logdClose,
.read = logdRead,
.poll = logdPoll,
- .close = logdClose,
.clear = logdClear,
- .getSize = logdGetSize,
.setSize = logdSetSize,
+ .getSize = logdGetSize,
.getReadableSize = logdGetReadableSize,
.getPrune = logdGetPrune,
.setPrune = logdSetPrune,
@@ -107,7 +107,7 @@
strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
int fd = socket(AF_LOCAL, type | SOCK_CLOEXEC, 0);
- if (fd == 0) {
+ if (fd == -1) {
return -1;
}
@@ -316,16 +316,11 @@
return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
}
-static void caught_signal(int signum __unused) {}
-
static int logdOpen(struct android_log_logger_list* logger_list,
struct android_log_transport_context* transp) {
struct android_log_logger* logger;
- struct sigaction ignore;
- struct sigaction old_sigaction;
- unsigned int old_alarm = 0;
char buffer[256], *cp, c;
- int e, ret, remaining, sock;
+ int ret, remaining, sock;
if (!logger_list) {
return -EINVAL;
@@ -337,12 +332,6 @@
}
sock = socket_local_client("logdr", SOCK_SEQPACKET);
- if (sock == 0) {
- /* Guarantee not file descriptor zero */
- int newsock = socket_local_client("logdr", SOCK_SEQPACKET);
- close(sock);
- sock = newsock;
- }
if (sock <= 0) {
if ((sock == -1) && errno) {
return -errno;
@@ -393,29 +382,13 @@
cp += ret;
}
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- /* Deal with an unresponsive logd */
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- /* particularily useful if tombstone is reporting for logd */
- sigaction(SIGALRM, &ignore, &old_sigaction);
- old_alarm = alarm(30);
- }
- ret = write(sock, buffer, cp - buffer);
- e = errno;
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- if (e == EINTR) {
- e = ETIMEDOUT;
- }
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
- }
+ ret = TEMP_FAILURE_RETRY(write(sock, buffer, cp - buffer));
+ int write_errno = errno;
if (ret <= 0) {
close(sock);
- if ((ret == -1) && e) {
- return -e;
+ if (ret == -1) {
+ return -write_errno;
}
if (ret == 0) {
return -EIO;
@@ -433,52 +406,21 @@
/* Read from the selected logs */
static int logdRead(struct android_log_logger_list* logger_list,
struct android_log_transport_context* transp, struct log_msg* log_msg) {
- int ret, e;
- struct sigaction ignore;
- struct sigaction old_sigaction;
- unsigned int old_alarm = 0;
-
- ret = logdOpen(logger_list, transp);
+ int ret = logdOpen(logger_list, transp);
if (ret < 0) {
return ret;
}
memset(log_msg, 0, sizeof(*log_msg));
- unsigned int new_alarm = 0;
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- if ((logger_list->mode & ANDROID_LOG_WRAP) &&
- (logger_list->start.tv_sec || logger_list->start.tv_nsec)) {
- /* b/64143705 */
- new_alarm = (ANDROID_LOG_WRAP_DEFAULT_TIMEOUT * 11) / 10 + 10;
- logger_list->mode &= ~ANDROID_LOG_WRAP;
- } else {
- new_alarm = 30;
- }
-
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- /* particularily useful if tombstone is reporting for logd */
- sigaction(SIGALRM, &ignore, &old_sigaction);
- old_alarm = alarm(new_alarm);
- }
-
/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
- ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
- e = errno;
-
- if (new_alarm) {
- if ((ret == 0) || (e == EINTR)) {
- e = EAGAIN;
- ret = -1;
- }
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
+ ret = TEMP_FAILURE_RETRY(recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0));
+ if ((logger_list->mode & ANDROID_LOG_NONBLOCK) && ret == 0) {
+ return -EAGAIN;
}
- if ((ret == -1) && e) {
- return -e;
+ if (ret == -1) {
+ return -errno;
}
return ret;
}
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index 2db45a1..9c5bc95 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -40,9 +40,9 @@
.name = "pmsg",
.available = pmsgAvailable,
.version = pmsgVersion,
+ .close = pmsgClose,
.read = pmsgRead,
.poll = NULL,
- .close = pmsgClose,
.clear = pmsgClear,
.setSize = NULL,
.getSize = NULL,
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index 45f09f2..394fa93 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -68,6 +68,7 @@
"libbase",
],
static_libs: ["liblog"],
+ isolated: true,
}
// Build tests for the device (with .so). Run with:
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d8b0ced..9780b28 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -42,6 +42,8 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+// #define ENABLE_FLAKY_TESTS
+
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
// non-syscall libs. Since we are only using this in the emergency of
// a signal to stuff a terminating code into the logs, we will spin rather
@@ -70,6 +72,7 @@
usleep(1000);
}
+#ifdef ENABLE_FLAKY_TESTS
#if defined(__ANDROID__)
static std::string popenToString(const std::string& command) {
std::string ret;
@@ -138,6 +141,7 @@
static bool tested__android_log_close;
#endif
+#endif // ENABLE_FLAKY_TESTS
TEST(liblog, __android_log_btwrite__android_logger_list_read) {
#ifdef __ANDROID__
@@ -152,6 +156,7 @@
log_time ts(CLOCK_MONOTONIC);
EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+#ifdef ENABLE_FLAKY_TESTS
// Check that we can close and reopen the logger
bool logdwActiveAfter__android_log_btwrite;
if (getuid() == AID_ROOT) {
@@ -174,9 +179,11 @@
bool logdwActiveAfter__android_log_close = isLogdwActive();
EXPECT_FALSE(logdwActiveAfter__android_log_close);
}
+#endif // ENABLE_FLAKY_TESTS
log_time ts1(CLOCK_MONOTONIC);
EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+#ifdef ENABLE_FLAKY_TESTS
if (getuid() == AID_ROOT) {
#ifndef NO_PSTORE
bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
@@ -185,6 +192,7 @@
logdwActiveAfter__android_log_btwrite = isLogdwActive();
EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
}
+#endif // ENABLE_FLAKY_TESTS
usleep(1000000);
int count = 0;
@@ -440,6 +448,7 @@
buf_write_test("\n Hello World \n");
}
+#ifdef ENABLE_FLAKY_TESTS
#ifdef __ANDROID__
static unsigned signaled;
static log_time signal_time;
@@ -749,12 +758,8 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // ENABLE_FLAKY_TESTS
-#ifdef __ANDROID__
-static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
-#define SIZEOF_MAX_PAYLOAD_BUF \
- (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(max_payload_tag) - 1)
-#endif
static const char max_payload_buf[] =
"LEONATO\n\
I learn in this letter that Don Peter of Arragon\n\
@@ -887,8 +892,12 @@
when you depart from me, sorrow abides and happiness\n\
takes his leave.";
+#ifdef ENABLE_FLAKY_TESTS
TEST(liblog, max_payload) {
#ifdef __ANDROID__
+ static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
+#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(max_payload_tag) - 1)
+
pid_t pid = getpid();
char tag[sizeof(max_payload_tag)];
memcpy(tag, max_payload_tag, sizeof(tag));
@@ -950,6 +959,7 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // ENABLE_FLAKY_TESTS
TEST(liblog, __android_log_buf_print__maxtag) {
#ifdef __ANDROID__
@@ -1081,6 +1091,7 @@
#endif
}
+#ifdef ENABLE_FLAKY_TESTS
TEST(liblog, dual_reader) {
#ifdef __ANDROID__
@@ -1143,7 +1154,9 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // ENABLE_FLAKY_TESTS
+#ifdef ENABLE_FLAKY_TESTS
static bool checkPriForTag(AndroidLogFormat* p_format, const char* tag,
android_LogPriority pri) {
return android_log_shouldPrintLine(p_format, tag, pri) &&
@@ -1219,7 +1232,9 @@
android_log_format_free(p_format);
}
+#endif // ENABLE_FLAKY_TESTS
+#ifdef ENABLE_FLAKY_TESTS
TEST(liblog, is_loggable) {
#ifdef __ANDROID__
static const char tag[] = "is_loggable";
@@ -1507,7 +1522,9 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // ENABLE_FLAKY_TESTS
+#ifdef ENABLE_FLAKY_TESTS
// Following tests the specific issues surrounding error handling wrt logd.
// Kills logd and toss all collected data, equivalent to logcat -b all -c,
// except we also return errors to the logging callers.
@@ -1604,9 +1621,11 @@
#endif
}
#endif // __ANDROID__
+#endif // ENABLE_FLAKY_TESTS
// Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
+#ifdef ENABLE_FLAKY_TESTS
// Do not retest properties, and cannot log into LOG_ID_SECURITY
TEST(liblog, __security) {
#ifdef __ANDROID__
@@ -1864,6 +1883,7 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // ENABLE_FLAKY_TESTS
#ifdef __ANDROID__
static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG,
@@ -2753,6 +2773,7 @@
#endif
}
+#ifdef ENABLE_FLAKY_TESTS
TEST(liblog, create_android_logger_overflow) {
android_log_context ctx;
@@ -2779,7 +2800,9 @@
EXPECT_LE(0, android_log_destroy(&ctx));
ASSERT_TRUE(NULL == ctx);
}
+#endif // ENABLE_FLAKY_TESTS
+#ifdef ENABLE_FLAKY_TESTS
#ifdef __ANDROID__
#ifndef NO_PSTORE
static const char __pmsg_file[] =
@@ -2916,7 +2939,9 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // ENABLE_FLAKY_TESTS
+#ifdef ENABLE_FLAKY_TESTS
TEST(liblog, android_lookupEventTagNum) {
#ifdef __ANDROID__
EventTagMap* map = android_openEventTagMap(NULL);
@@ -2933,3 +2958,4 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // ENABLE_FLAKY_TESTS
diff --git a/liblog/tests/log_wrap_test.cpp b/liblog/tests/log_wrap_test.cpp
index c7dd8e8..e06964f 100644
--- a/liblog/tests/log_wrap_test.cpp
+++ b/liblog/tests/log_wrap_test.cpp
@@ -58,60 +58,27 @@
android_logger_list_close(logger_list);
}
-
-static void caught_signal(int /* signum */) {
-}
#endif
// b/64143705 confirm fixed
TEST(liblog, wrap_mode_blocks) {
#ifdef __ANDROID__
+ // The read call is expected to take up to 2 hours in the happy case. There was a previous bug
+ // where it would take only 30 seconds due to an alarm() in logd_reader.cpp. That alarm has been
+ // removed, so we check here that the read call blocks for a reasonable amount of time (5s).
+
+ struct sigaction ignore = {.sa_handler = [](int) { _exit(0); }};
+ struct sigaction old_sigaction;
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ alarm(5);
android::base::Timer timer;
+ read_with_wrap();
- // The read call is expected to take up to 2 hours in the happy case.
- // We only want to make sure it waits for longer than 30s, but we can't
- // use an alarm as the implementation uses it. So we run the test in
- // a separate process.
- pid_t pid = fork();
-
- if (pid == 0) {
- // child
- read_with_wrap();
- _exit(0);
- }
-
- struct sigaction ignore, old_sigaction;
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- sigaction(SIGALRM, &ignore, &old_sigaction);
- alarm(45);
-
- bool killed = false;
- for (;;) {
- siginfo_t info = {};
- // This wait will succeed if the child exits, or fail with EINTR if the
- // alarm goes off first - a loose approximation to a timed wait.
- int ret = waitid(P_PID, pid, &info, WEXITED);
- if (ret >= 0 || errno != EINTR) {
- EXPECT_EQ(ret, 0);
- if (!killed) {
- EXPECT_EQ(info.si_status, 0);
- }
- break;
- }
- unsigned int alarm_left = alarm(0);
- if (alarm_left > 0) {
- alarm(alarm_left);
- } else {
- kill(pid, SIGTERM);
- killed = true;
- }
- }
+ FAIL() << "read_with_wrap() should not return before the alarm is triggered.";
alarm(0);
- EXPECT_GT(timer.duration(), std::chrono::seconds(40));
+ sigaction(SIGALRM, &old_sigaction, nullptr);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 10d42e4..c97845d 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -21,6 +21,8 @@
cc_library {
name: "libnativebridge",
defaults: ["libnativebridge-defaults"],
+ // TODO(oth): remove after moving under art/ (b/137364733)
+ visibility: ["//visibility:public"],
host_supported: true,
srcs: ["native_bridge.cc"],
@@ -52,6 +54,8 @@
cc_library {
name: "libnativebridge_lazy",
defaults: ["libnativebridge-defaults"],
+ // TODO(oth): remove after moving under art/ (b/137364733)
+ visibility: ["//visibility:public"],
host_supported: false,
srcs: ["native_bridge_lazy.cc"],
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 939bdd7..2ee9d28 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -16,6 +16,8 @@
cc_library {
name: "libnativeloader",
defaults: ["libnativeloader-defaults"],
+ // TODO(oth): remove after moving under art/ (b/137364733)
+ visibility: ["//visibility:public"],
host_supported: true,
srcs: [
"native_loader.cpp",
@@ -52,6 +54,8 @@
cc_library {
name: "libnativeloader_lazy",
defaults: ["libnativeloader-defaults"],
+ // TODO(oth): remove after moving under art/ (b/137364733)
+ visibility: ["//visibility:public"],
host_supported: false,
srcs: ["native_loader_lazy.cpp"],
required: ["libnativeloader"],
@@ -59,6 +63,8 @@
cc_library_headers {
name: "libnativeloader-headers",
+ // TODO(oth): remove after moving under art/ (b/137364733)
+ visibility: ["//visibility:public"],
host_supported: true,
export_include_dirs: ["include"],
}
@@ -83,6 +89,9 @@
"libnativebridge-headers",
"libnativeloader-headers",
],
- system_shared_libs: ["libc", "libm"],
+ system_shared_libs: [
+ "libc",
+ "libm",
+ ],
test_suites: ["device-tests"],
}
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index 9a33b55..7246b97 100644
--- a/libnativeloader/library_namespaces.cpp
+++ b/libnativeloader/library_namespaces.cpp
@@ -44,7 +44,7 @@
// vendor and system namespaces.
constexpr const char* kVendorNamespaceName = "sphal";
constexpr const char* kVndkNamespaceName = "vndk";
-constexpr const char* kRuntimeNamespaceName = "runtime";
+constexpr const char* kArtNamespaceName = "art";
constexpr const char* kNeuralNetworksNamespaceName = "neuralnetworks";
// classloader-namespace is a linker namespace that is created for the loaded
@@ -237,10 +237,10 @@
return linked.error();
}
- auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged);
- // Runtime apex does not exist in host, and under certain build conditions.
- if (runtime_ns) {
- linked = app_ns->Link(*runtime_ns, runtime_public_libraries());
+ auto art_ns = NativeLoaderNamespace::GetExportedNamespace(kArtNamespaceName, is_bridged);
+ // ART APEX does not exist on host, and under certain build conditions.
+ if (art_ns) {
+ linked = app_ns->Link(*art_ns, art_public_libraries());
if (!linked) {
return linked.error();
}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 60d462f..6d3c057 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -63,10 +63,6 @@
LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
"Error finding namespace of apex: no dot in apex name %s", caller_location);
std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
- // TODO(b/139408016): Rename the runtime namespace to "art".
- if (name == "art") {
- name = "runtime";
- }
android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
"Error finding namespace of apex: no namespace called %s", name.c_str());
diff --git a/libnativeloader/native_loader_test.cpp b/libnativeloader/native_loader_test.cpp
index 75255b6..8bd7386 100644
--- a/libnativeloader/native_loader_test.cpp
+++ b/libnativeloader/native_loader_test.cpp
@@ -83,7 +83,7 @@
static std::unordered_map<std::string, Platform::mock_namespace_handle> namespaces = {
{"platform", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("platform"))},
{"default", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("default"))},
- {"runtime", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("runtime"))},
+ {"art", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("art"))},
{"sphal", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("sphal"))},
{"vndk", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk"))},
{"neuralnetworks", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("neuralnetworks"))},
@@ -92,7 +92,7 @@
// The actual gmock object
class MockPlatform : public Platform {
public:
- MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
+ explicit MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
ON_CALL(*this, NativeBridgeIsSupported(_)).WillByDefault(Return(is_bridged_));
ON_CALL(*this, NativeBridgeIsPathSupported(_)).WillByDefault(Return(is_bridged_));
ON_CALL(*this, mock_get_exported_namespace(_, _))
@@ -338,13 +338,13 @@
std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
std::string expected_parent_namespace = "platform";
bool expected_link_with_platform_ns = true;
- bool expected_link_with_runtime_ns = true;
+ bool expected_link_with_art_ns = true;
bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
bool expected_link_with_vndk_ns = false;
bool expected_link_with_default_ns = false;
bool expected_link_with_neuralnetworks_ns = true;
std::string expected_shared_libs_to_platform_ns = default_public_libraries();
- std::string expected_shared_libs_to_runtime_ns = runtime_public_libraries();
+ std::string expected_shared_libs_to_art_ns = art_public_libraries();
std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
std::string expected_shared_libs_to_vndk_ns = vndksp_libraries();
std::string expected_shared_libs_to_default_ns = default_public_libraries();
@@ -368,9 +368,9 @@
StrEq(expected_shared_libs_to_platform_ns)))
.WillOnce(Return(true));
}
- if (expected_link_with_runtime_ns) {
- EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("runtime"),
- StrEq(expected_shared_libs_to_runtime_ns)))
+ if (expected_link_with_art_ns) {
+ EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("art"),
+ StrEq(expected_shared_libs_to_art_ns)))
.WillOnce(Return(true));
}
if (expected_link_with_sphal_ns) {
diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp
index 010e8cc..11c3070 100644
--- a/libnativeloader/public_libraries.cpp
+++ b/libnativeloader/public_libraries.cpp
@@ -181,10 +181,10 @@
return android::base::Join(*sonames, ':');
}
- // Remove the public libs in the runtime namespace.
+ // Remove the public libs in the art namespace.
// These libs are listed in public.android.txt, but we don't want the rest of android
// in default namespace to dlopen the libs.
- // For example, libicuuc.so is exposed to classloader namespace from runtime namespace.
+ // For example, libicuuc.so is exposed to classloader namespace from art namespace.
// Unfortunately, it does not have stable C symbols, and default namespace should only use
// stable symbols in libandroidicu.so. http://b/120786417
for (const std::string& lib_name : kArtApexPublicLibraries) {
@@ -281,7 +281,7 @@
return list;
}
-const std::string& runtime_public_libraries() {
+const std::string& art_public_libraries() {
static std::string list = InitArtPublicLibraries();
return list;
}
diff --git a/libnativeloader/public_libraries.h b/libnativeloader/public_libraries.h
index 2de4172..b892e6f 100644
--- a/libnativeloader/public_libraries.h
+++ b/libnativeloader/public_libraries.h
@@ -29,7 +29,7 @@
// e.g., if it is a vendor app or not, different set of libraries are made available.
const std::string& preloadable_public_libraries();
const std::string& default_public_libraries();
-const std::string& runtime_public_libraries();
+const std::string& art_public_libraries();
const std::string& vendor_public_libraries();
const std::string& extended_public_libraries();
const std::string& neuralnetworks_public_libraries();
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 8d2299f..b0f3786 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -245,6 +245,7 @@
"tests/files/offline/jit_debug_x86/*",
"tests/files/offline/jit_map_arm/*",
"tests/files/offline/gnu_debugdata_arm/*",
+ "tests/files/offline/load_bias_different_section_bias_arm64/*",
"tests/files/offline/load_bias_ro_rx_x86_64/*",
"tests/files/offline/offset_arm/*",
"tests/files/offline/shared_lib_in_apk_arm64/*",
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index eaf867f..dff7a8b 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -22,6 +22,9 @@
#include <memory>
+#define LOG_TAG "unwind"
+#include <log/log.h>
+
#include <android-base/unique_fd.h>
#include <art_api/dex_file_support.h>
@@ -32,6 +35,19 @@
namespace unwindstack {
+static bool CheckDexSupport() {
+ if (std::string err_msg; !art_api::dex::TryLoadLibdexfileExternal(&err_msg)) {
+ ALOGW("Failed to initialize DEX file support: %s", err_msg.c_str());
+ return false;
+ }
+ return true;
+}
+
+static bool HasDexSupport() {
+ static bool has_dex_support = CheckDexSupport();
+ return has_dex_support;
+}
+
std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
MapInfo* info) {
if (!info->name.empty()) {
@@ -57,6 +73,10 @@
std::unique_ptr<DexFileFromFile> DexFileFromFile::Create(uint64_t dex_file_offset_in_file,
const std::string& file) {
+ if (UNLIKELY(!HasDexSupport())) {
+ return nullptr;
+ }
+
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
return nullptr;
@@ -75,6 +95,10 @@
std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
Memory* memory,
const std::string& name) {
+ if (UNLIKELY(!HasDexSupport())) {
+ return nullptr;
+ }
+
std::vector<uint8_t> backing_memory;
for (size_t size = 0;;) {
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index 802beca..24b94f0 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -32,8 +32,8 @@
}
template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
- load_bias_ = load_bias;
+bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
+ section_bias_ = section_bias;
memory_.clear_func_offset();
memory_.clear_text_offset();
@@ -138,7 +138,7 @@
// Relative encodings require adding in the load bias.
if (IsEncodingRelative(table_encoding_)) {
- value += load_bias_;
+ value += section_bias_;
}
info->pc = value;
return info;
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index 0e5eef7..b8dd3dd 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -38,7 +38,7 @@
using DwarfSectionImpl<AddressType>::entries_offset_;
using DwarfSectionImpl<AddressType>::entries_end_;
using DwarfSectionImpl<AddressType>::last_error_;
- using DwarfSectionImpl<AddressType>::load_bias_;
+ using DwarfSectionImpl<AddressType>::section_bias_;
struct FdeInfo {
AddressType pc;
@@ -61,7 +61,7 @@
return pc + this->memory_.cur_offset() - 4;
}
- bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
+ bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
const DwarfFde* GetFdeFromPc(uint64_t pc) override;
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index b505900..2e388c6 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -111,7 +111,7 @@
// Nothing to do.
break;
case DW_EH_PE_pcrel:
- if (pc_offset_ == static_cast<uint64_t>(-1)) {
+ if (pc_offset_ == INT64_MAX) {
// Unsupported encoding.
return false;
}
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 849a31a..cdb6141 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -333,7 +333,7 @@
memory_.set_cur_offset(cur_offset);
// The load bias only applies to the start.
- memory_.set_pc_offset(load_bias_);
+ memory_.set_pc_offset(section_bias_);
bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
fde->pc_start = AdjustPcFromFde(fde->pc_start);
@@ -591,8 +591,9 @@
}
template <typename AddressType>
-bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
- load_bias_ = load_bias;
+bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
+ int64_t section_bias) {
+ section_bias_ = section_bias;
entries_offset_ = offset;
next_entries_offset_ = offset;
entries_end_ = offset + size;
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 3454913..c141b2e 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -53,7 +53,7 @@
valid_ = interface_->Init(&load_bias_);
if (valid_) {
- interface_->InitHeaders(load_bias_);
+ interface_->InitHeaders();
InitGnuDebugdata();
} else {
interface_.reset(nullptr);
@@ -77,9 +77,9 @@
// Ignore the load_bias from the compressed section, the correct load bias
// is in the uncompressed data.
- uint64_t load_bias;
+ int64_t load_bias;
if (gnu->Init(&load_bias)) {
- gnu->InitHeaders(load_bias);
+ gnu->InitHeaders();
interface_->SetGnuDebugdataInterface(gnu);
} else {
// Free all of the memory associated with the gnu_debugdata section.
@@ -124,7 +124,7 @@
}
// Adjust by the load bias.
- if (*memory_address < load_bias_) {
+ if (load_bias_ > 0 && *memory_address < static_cast<uint64_t>(load_bias_)) {
return false;
}
@@ -229,7 +229,7 @@
}
bool Elf::IsValidPc(uint64_t pc) {
- if (!valid_ || pc < load_bias_) {
+ if (!valid_ || (load_bias_ > 0 && pc < static_cast<uint64_t>(load_bias_))) {
return false;
}
@@ -299,7 +299,7 @@
return interface.release();
}
-uint64_t Elf::GetLoadBias(Memory* memory) {
+int64_t Elf::GetLoadBias(Memory* memory) {
if (!IsValidElf(memory)) {
return 0;
}
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index be1f092..e34273c 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -124,10 +124,10 @@
}
template <typename AddressType>
-void ElfInterface::InitHeadersWithTemplate(uint64_t load_bias) {
+void ElfInterface::InitHeadersWithTemplate() {
if (eh_frame_hdr_offset_ != 0) {
eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
- if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, load_bias)) {
+ if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, eh_frame_hdr_section_bias_)) {
eh_frame_.reset(nullptr);
}
}
@@ -136,21 +136,23 @@
// If there is an eh_frame section without an eh_frame_hdr section,
// or using the frame hdr object failed to init.
eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
- if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_, load_bias)) {
+ if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_, eh_frame_section_bias_)) {
eh_frame_.reset(nullptr);
}
}
if (eh_frame_.get() == nullptr) {
eh_frame_hdr_offset_ = 0;
+ eh_frame_hdr_section_bias_ = 0;
eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
eh_frame_offset_ = 0;
+ eh_frame_section_bias_ = 0;
eh_frame_size_ = static_cast<uint64_t>(-1);
}
if (debug_frame_offset_ != 0) {
debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
- if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_, load_bias)) {
+ if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_, debug_frame_section_bias_)) {
debug_frame_.reset(nullptr);
debug_frame_offset_ = 0;
debug_frame_size_ = static_cast<uint64_t>(-1);
@@ -159,7 +161,7 @@
}
template <typename EhdrType, typename PhdrType, typename ShdrType>
-bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
+bool ElfInterface::ReadAllHeaders(int64_t* load_bias) {
EhdrType ehdr;
if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
last_error_.code = ERROR_MEMORY_INVALID;
@@ -175,7 +177,7 @@
}
template <typename EhdrType, typename PhdrType>
-uint64_t ElfInterface::GetLoadBias(Memory* memory) {
+int64_t ElfInterface::GetLoadBias(Memory* memory) {
EhdrType ehdr;
if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
return false;
@@ -190,17 +192,14 @@
// Find the first executable load when looking for the load bias.
if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
- if (phdr.p_vaddr > phdr.p_offset) {
- return phdr.p_vaddr - phdr.p_offset;
- }
- break;
+ return static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
}
}
return 0;
}
template <typename EhdrType, typename PhdrType>
-void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
+void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias) {
uint64_t offset = ehdr.e_phoff;
bool first_exec_load_header = true;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
@@ -219,8 +218,8 @@
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
static_cast<size_t>(phdr.p_memsz)};
// Only set the load bias from the first executable load header.
- if (first_exec_load_header && phdr.p_vaddr > phdr.p_offset) {
- *load_bias = phdr.p_vaddr - phdr.p_offset;
+ if (first_exec_load_header) {
+ *load_bias = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
}
first_exec_load_header = false;
break;
@@ -229,6 +228,7 @@
case PT_GNU_EH_FRAME:
// This is really the pointer to the .eh_frame_hdr section.
eh_frame_hdr_offset_ = phdr.p_offset;
+ eh_frame_hdr_section_bias_ = static_cast<uint64_t>(phdr.p_paddr) - phdr.p_offset;
eh_frame_hdr_size_ = phdr.p_memsz;
break;
@@ -343,24 +343,21 @@
if (shdr.sh_name < sec_size) {
std::string name;
if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
- uint64_t* offset_ptr = nullptr;
- uint64_t* size_ptr = nullptr;
if (name == ".debug_frame") {
- offset_ptr = &debug_frame_offset_;
- size_ptr = &debug_frame_size_;
+ debug_frame_offset_ = shdr.sh_offset;
+ debug_frame_size_ = shdr.sh_size;
+ debug_frame_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
} else if (name == ".gnu_debugdata") {
- offset_ptr = &gnu_debugdata_offset_;
- size_ptr = &gnu_debugdata_size_;
+ gnu_debugdata_offset_ = shdr.sh_offset;
+ gnu_debugdata_size_ = shdr.sh_size;
} else if (name == ".eh_frame") {
- offset_ptr = &eh_frame_offset_;
- size_ptr = &eh_frame_size_;
+ eh_frame_offset_ = shdr.sh_offset;
+ eh_frame_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
+ eh_frame_size_ = shdr.sh_size;
} else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
- offset_ptr = &eh_frame_hdr_offset_;
- size_ptr = &eh_frame_hdr_size_;
- }
- if (offset_ptr != nullptr) {
- *offset_ptr = shdr.sh_offset;
- *size_ptr = shdr.sh_size;
+ eh_frame_hdr_offset_ = shdr.sh_offset;
+ eh_frame_hdr_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
+ eh_frame_hdr_size_ = shdr.sh_size;
}
}
}
@@ -642,16 +639,14 @@
}
// Instantiate all of the needed template functions.
-template void ElfInterface::InitHeadersWithTemplate<uint32_t>(uint64_t);
-template void ElfInterface::InitHeadersWithTemplate<uint64_t>(uint64_t);
+template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
+template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
-template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
-template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
+template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(int64_t*);
+template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(int64_t*);
-template void ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&,
- uint64_t*);
-template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&,
- uint64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, int64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, int64_t*);
template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
@@ -673,8 +668,8 @@
template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);
-template uint64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
-template uint64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
+template int64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
+template int64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
template std::string ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(
Memory*);
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 3dd5d54..76f2dc8 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -26,7 +26,7 @@
namespace unwindstack {
-bool ElfInterfaceArm::Init(uint64_t* load_bias) {
+bool ElfInterfaceArm::Init(int64_t* load_bias) {
if (!ElfInterface32::Init(load_bias)) {
return false;
}
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index 4c3a0c3..1d71cac 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -64,7 +64,7 @@
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, total_entries_); }
- bool Init(uint64_t* load_bias) override;
+ bool Init(int64_t* section_bias) override;
bool GetPrel31Addr(uint32_t offset, uint32_t* addr);
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 5b30a4d..f2dad84 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
@@ -263,8 +264,8 @@
}
uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
- uint64_t cur_load_bias = load_bias.load();
- if (cur_load_bias != static_cast<uint64_t>(-1)) {
+ int64_t cur_load_bias = load_bias.load();
+ if (cur_load_bias != INT64_MAX) {
return cur_load_bias;
}
diff --git a/libunwindstack/include/unwindstack/DwarfMemory.h b/libunwindstack/include/unwindstack/DwarfMemory.h
index 8dd8d2b..c45699a 100644
--- a/libunwindstack/include/unwindstack/DwarfMemory.h
+++ b/libunwindstack/include/unwindstack/DwarfMemory.h
@@ -49,8 +49,8 @@
uint64_t cur_offset() { return cur_offset_; }
void set_cur_offset(uint64_t cur_offset) { cur_offset_ = cur_offset; }
- void set_pc_offset(uint64_t offset) { pc_offset_ = offset; }
- void clear_pc_offset() { pc_offset_ = static_cast<uint64_t>(-1); }
+ void set_pc_offset(int64_t offset) { pc_offset_ = offset; }
+ void clear_pc_offset() { pc_offset_ = INT64_MAX; }
void set_data_offset(uint64_t offset) { data_offset_ = offset; }
void clear_data_offset() { data_offset_ = static_cast<uint64_t>(-1); }
@@ -65,7 +65,7 @@
Memory* memory_;
uint64_t cur_offset_ = 0;
- uint64_t pc_offset_ = static_cast<uint64_t>(-1);
+ int64_t pc_offset_ = INT64_MAX;
uint64_t data_offset_ = static_cast<uint64_t>(-1);
uint64_t func_offset_ = static_cast<uint64_t>(-1);
uint64_t text_offset_ = static_cast<uint64_t>(-1);
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index e9942de..0b3f6d4 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -86,7 +86,7 @@
DwarfErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
- virtual bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) = 0;
+ virtual bool Init(uint64_t offset, uint64_t size, int64_t section_bias) = 0;
virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0;
@@ -150,7 +150,7 @@
bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
- uint64_t load_bias_ = 0;
+ int64_t section_bias_ = 0;
uint64_t entries_offset_ = 0;
uint64_t entries_end_ = 0;
uint64_t pc_offset_ = 0;
@@ -166,7 +166,7 @@
using DwarfSectionImpl<AddressType>::entries_offset_;
using DwarfSectionImpl<AddressType>::entries_end_;
using DwarfSectionImpl<AddressType>::last_error_;
- using DwarfSectionImpl<AddressType>::load_bias_;
+ using DwarfSectionImpl<AddressType>::section_bias_;
using DwarfSectionImpl<AddressType>::cie_entries_;
using DwarfSectionImpl<AddressType>::fde_entries_;
using DwarfSectionImpl<AddressType>::cie32_value_;
@@ -175,7 +175,7 @@
DwarfSectionImplNoHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
virtual ~DwarfSectionImplNoHdr() = default;
- bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
+ bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
const DwarfFde* GetFdeFromPc(uint64_t pc) override;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 56bf318..fc3f2a6 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -75,7 +75,7 @@
std::string GetBuildID();
- uint64_t GetLoadBias() { return load_bias_; }
+ int64_t GetLoadBias() { return load_bias_; }
bool IsValidPc(uint64_t pc);
@@ -101,7 +101,7 @@
static bool GetInfo(Memory* memory, uint64_t* size);
- static uint64_t GetLoadBias(Memory* memory);
+ static int64_t GetLoadBias(Memory* memory);
static std::string GetBuildID(Memory* memory);
@@ -116,7 +116,7 @@
protected:
bool valid_ = false;
- uint64_t load_bias_ = 0;
+ int64_t load_bias_ = 0;
std::unique_ptr<ElfInterface> interface_;
std::unique_ptr<Memory> memory_;
uint32_t machine_type_;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index dbd917d..ae9bd9a 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -52,9 +52,9 @@
ElfInterface(Memory* memory) : memory_(memory) {}
virtual ~ElfInterface();
- virtual bool Init(uint64_t* load_bias) = 0;
+ virtual bool Init(int64_t* load_bias) = 0;
- virtual void InitHeaders(uint64_t load_bias) = 0;
+ virtual void InitHeaders() = 0;
virtual std::string GetSoname() = 0;
@@ -80,10 +80,13 @@
uint64_t dynamic_vaddr() { return dynamic_vaddr_; }
uint64_t dynamic_size() { return dynamic_size_; }
uint64_t eh_frame_hdr_offset() { return eh_frame_hdr_offset_; }
+ int64_t eh_frame_hdr_section_bias() { return eh_frame_hdr_section_bias_; }
uint64_t eh_frame_hdr_size() { return eh_frame_hdr_size_; }
uint64_t eh_frame_offset() { return eh_frame_offset_; }
+ int64_t eh_frame_section_bias() { return eh_frame_section_bias_; }
uint64_t eh_frame_size() { return eh_frame_size_; }
uint64_t debug_frame_offset() { return debug_frame_offset_; }
+ int64_t debug_frame_section_bias() { return debug_frame_section_bias_; }
uint64_t debug_frame_size() { return debug_frame_size_; }
uint64_t gnu_debugdata_offset() { return gnu_debugdata_offset_; }
uint64_t gnu_debugdata_size() { return gnu_debugdata_size_; }
@@ -98,20 +101,20 @@
uint64_t LastErrorAddress() { return last_error_.address; }
template <typename EhdrType, typename PhdrType>
- static uint64_t GetLoadBias(Memory* memory);
+ static int64_t GetLoadBias(Memory* memory);
template <typename EhdrType, typename ShdrType, typename NhdrType>
static std::string ReadBuildIDFromMemory(Memory* memory);
protected:
template <typename AddressType>
- void InitHeadersWithTemplate(uint64_t load_bias);
+ void InitHeadersWithTemplate();
template <typename EhdrType, typename PhdrType, typename ShdrType>
- bool ReadAllHeaders(uint64_t* load_bias);
+ bool ReadAllHeaders(int64_t* load_bias);
template <typename EhdrType, typename PhdrType>
- void ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
+ void ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias);
template <typename EhdrType, typename ShdrType>
void ReadSectionHeaders(const EhdrType& ehdr);
@@ -142,12 +145,15 @@
uint64_t dynamic_size_ = 0;
uint64_t eh_frame_hdr_offset_ = 0;
+ int64_t eh_frame_hdr_section_bias_ = 0;
uint64_t eh_frame_hdr_size_ = 0;
uint64_t eh_frame_offset_ = 0;
+ int64_t eh_frame_section_bias_ = 0;
uint64_t eh_frame_size_ = 0;
uint64_t debug_frame_offset_ = 0;
+ int64_t debug_frame_section_bias_ = 0;
uint64_t debug_frame_size_ = 0;
uint64_t gnu_debugdata_offset_ = 0;
@@ -175,13 +181,11 @@
ElfInterface32(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterface32() = default;
- bool Init(uint64_t* load_bias) override {
+ bool Init(int64_t* load_bias) override {
return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(load_bias);
}
- void InitHeaders(uint64_t load_bias) override {
- ElfInterface::InitHeadersWithTemplate<uint32_t>(load_bias);
- }
+ void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); }
std::string GetSoname() override { return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(); }
@@ -205,13 +209,11 @@
ElfInterface64(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterface64() = default;
- bool Init(uint64_t* load_bias) override {
+ bool Init(int64_t* load_bias) override {
return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(load_bias);
}
- void InitHeaders(uint64_t load_bias) override {
- ElfInterface::InitHeadersWithTemplate<uint64_t>(load_bias);
- }
+ void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); }
std::string GetSoname() override { return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(); }
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 6c5cfc4..8f0c516 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -39,7 +39,7 @@
flags(flags),
name(name),
prev_map(map_info),
- load_bias(static_cast<uint64_t>(-1)),
+ load_bias(INT64_MAX),
build_id(0) {}
MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
const std::string& name)
@@ -49,7 +49,7 @@
flags(flags),
name(name),
prev_map(map_info),
- load_bias(static_cast<uint64_t>(-1)),
+ load_bias(INT64_MAX),
build_id(0) {}
~MapInfo();
@@ -72,7 +72,7 @@
MapInfo* prev_map = nullptr;
- std::atomic_uint64_t load_bias;
+ std::atomic_int64_t load_bias;
// This is a pointer to a new'd std::string.
// Using an atomic value means that we don't need to lock and will
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index b386ef4..a9d6dad 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -35,7 +35,7 @@
TestDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
virtual ~TestDwarfSectionImpl() = default;
- bool Init(uint64_t, uint64_t, uint64_t) override { return false; }
+ bool Init(uint64_t, uint64_t, int64_t) override { return false; }
void GetFdes(std::vector<const DwarfFde*>*) override {}
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index d754fcc..6df2bae 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -30,7 +30,7 @@
MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
virtual ~MockDwarfSection() = default;
- MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
+ MOCK_METHOD3(Init, bool(uint64_t, uint64_t, int64_t));
MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*));
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index bd3083c..832e64a 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -66,8 +66,8 @@
ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterfaceFake() = default;
- bool Init(uint64_t*) override { return false; }
- void InitHeaders(uint64_t) override {}
+ bool Init(int64_t*) override { return false; }
+ void InitHeaders() override {}
std::string GetSoname() override { return fake_soname_; }
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 5b2036b..b048b17 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -112,6 +112,21 @@
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void InitSectionHeadersOffsets();
+ template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+ void InitSectionHeadersOffsetsEhFrameSectionBias(uint64_t addr, uint64_t offset,
+ int64_t expected_bias);
+
+ template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+ void InitSectionHeadersOffsetsEhFrameHdrSectionBias(uint64_t addr, uint64_t offset,
+ int64_t expected_bias);
+
+ template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+ void InitSectionHeadersOffsetsDebugFrameSectionBias(uint64_t addr, uint64_t offset,
+ int64_t expected_bias);
+
+ template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+ void CheckGnuEhFrame(uint64_t addr, uint64_t offset, int64_t expected_bias);
+
template <typename Sym>
void InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset,
uint64_t sym_offset, const char* name);
@@ -132,10 +147,10 @@
void BuildIDSectionTooSmallForHeader();
template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
- void CheckLoadBiasInFirstPhdr(uint64_t load_bias);
+ void CheckLoadBiasInFirstPhdr(int64_t load_bias);
template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
- void CheckLoadBiasInFirstExecPhdr(uint64_t offset, uint64_t vaddr, uint64_t load_bias);
+ void CheckLoadBiasInFirstExecPhdr(uint64_t offset, uint64_t vaddr, int64_t load_bias);
MemoryFake memory_;
};
@@ -172,9 +187,9 @@
phdr.p_align = 0x1000;
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000U, load_bias);
+ EXPECT_EQ(0x2000, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -184,11 +199,11 @@
ASSERT_EQ(0x10000U, load_data.table_size);
}
-TEST_F(ElfInterfaceTest, elf32_single_pt_load) {
+TEST_F(ElfInterfaceTest, single_pt_load_32) {
SinglePtLoad<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_single_pt_load) {
+TEST_F(ElfInterfaceTest, single_pt_load_64) {
SinglePtLoad<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
}
@@ -228,9 +243,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000U, load_bias);
+ EXPECT_EQ(0x2000, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(3U, pt_loads.size());
@@ -251,11 +266,11 @@
ASSERT_EQ(0x10002U, load_data.table_size);
}
-TEST_F(ElfInterfaceTest, elf32_multiple_executable_pt_loads) {
+TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_32) {
MultipleExecutablePtLoads<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_multiple_executable_pt_loads) {
+TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_64) {
MultipleExecutablePtLoads<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
}
@@ -295,9 +310,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * (sizeof(phdr) + 100), &phdr, sizeof(phdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000U, load_bias);
+ EXPECT_EQ(0x2000, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(3U, pt_loads.size());
@@ -318,12 +333,12 @@
ASSERT_EQ(0x10002U, load_data.table_size);
}
-TEST_F(ElfInterfaceTest, elf32_multiple_executable_pt_loads_increments_not_size_of_phdr) {
+TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_increments_not_size_of_phdr_32) {
MultipleExecutablePtLoadsIncrementsNotSizeOfPhdr<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn,
ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_multiple_executable_pt_loads_increments_not_size_of_phdr) {
+TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_increments_not_size_of_phdr_64) {
MultipleExecutablePtLoadsIncrementsNotSizeOfPhdr<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn,
ElfInterface64>();
}
@@ -364,9 +379,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x1001U, load_bias);
+ EXPECT_EQ(0x1001, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -377,11 +392,11 @@
ASSERT_EQ(0x10001U, load_data.table_size);
}
-TEST_F(ElfInterfaceTest, elf32_non_executable_pt_loads) {
+TEST_F(ElfInterfaceTest, non_executable_pt_loads_32) {
NonExecutablePtLoads<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_non_executable_pt_loads) {
+TEST_F(ElfInterfaceTest, non_executable_pt_loads_64) {
NonExecutablePtLoads<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
}
@@ -434,11 +449,10 @@
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_GNU_EH_FRAME;
memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000U, load_bias);
+ EXPECT_EQ(0x2000, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -449,15 +463,15 @@
ASSERT_EQ(0x10000U, load_data.table_size);
}
-TEST_F(ElfInterfaceTest, elf32_many_phdrs) {
+TEST_F(ElfInterfaceTest, many_phdrs_32) {
ElfInterfaceTest::ManyPhdrs<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_many_phdrs) {
+TEST_F(ElfInterfaceTest, many_phdrs_64) {
ElfInterfaceTest::ManyPhdrs<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
}
-TEST_F(ElfInterfaceTest, elf32_arm) {
+TEST_F(ElfInterfaceTest, arm32) {
ElfInterfaceArm elf_arm(&memory_);
Elf32_Ehdr ehdr = {};
@@ -476,9 +490,9 @@
memory_.SetData32(0x2000, 0x1000);
memory_.SetData32(0x2008, 0x1000);
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf_arm.Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
std::vector<uint32_t> entries;
for (auto addr : elf_arm) {
@@ -557,19 +571,19 @@
void ElfInterfaceTest::Soname() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
ASSERT_EQ("fake_soname.so", elf->GetSoname());
}
-TEST_F(ElfInterfaceTest, elf32_soname) {
+TEST_F(ElfInterfaceTest, soname_32) {
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>();
Soname<ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_soname) {
+TEST_F(ElfInterfaceTest, soname_64) {
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>();
Soname<ElfInterface64>();
}
@@ -578,19 +592,19 @@
void ElfInterfaceTest::SonameAfterDtNull() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
ASSERT_EQ("", elf->GetSoname());
}
-TEST_F(ElfInterfaceTest, elf32_soname_after_dt_null) {
+TEST_F(ElfInterfaceTest, soname_after_dt_null_32) {
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTNULL_AFTER);
SonameAfterDtNull<ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_soname_after_dt_null) {
+TEST_F(ElfInterfaceTest, soname_after_dt_null_64) {
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTNULL_AFTER);
SonameAfterDtNull<ElfInterface64>();
}
@@ -599,19 +613,19 @@
void ElfInterfaceTest::SonameSize() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
ASSERT_EQ("", elf->GetSoname());
}
-TEST_F(ElfInterfaceTest, elf32_soname_size) {
+TEST_F(ElfInterfaceTest, soname_size_32) {
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTSIZE_SMALL);
SonameSize<ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_soname_size) {
+TEST_F(ElfInterfaceTest, soname_size_64) {
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTSIZE_SMALL);
SonameSize<ElfInterface64>();
}
@@ -622,19 +636,19 @@
void ElfInterfaceTest::SonameMissingMap() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
ASSERT_EQ("", elf->GetSoname());
}
-TEST_F(ElfInterfaceTest, elf32_soname_missing_map) {
+TEST_F(ElfInterfaceTest, soname_missing_map_32) {
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_MISSING_MAP);
SonameMissingMap<ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, elf64_soname_missing_map) {
+TEST_F(ElfInterfaceTest, soname_missing_map_64) {
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_MISSING_MAP);
SonameMissingMap<ElfInterface64>();
}
@@ -653,17 +667,17 @@
memory_.SetData32(0x10004, 0x500);
memory_.SetData32(0x10008, 250);
- elf.InitHeaders(0);
+ elf.InitHeaders();
EXPECT_FALSE(elf.eh_frame() == nullptr);
EXPECT_TRUE(elf.debug_frame() == nullptr);
}
-TEST_F(ElfInterfaceTest, init_headers_eh_frame32) {
+TEST_F(ElfInterfaceTest, init_headers_eh_frame_32) {
InitHeadersEhFrameTest<ElfInterface32Fake>();
}
-TEST_F(ElfInterfaceTest, init_headers_eh_frame64) {
+TEST_F(ElfInterfaceTest, init_headers_eh_frame_64) {
InitHeadersEhFrameTest<ElfInterface64Fake>();
}
@@ -685,17 +699,17 @@
memory_.SetData32(0x5108, 0x1500);
memory_.SetData32(0x510c, 0x200);
- elf.InitHeaders(0);
+ elf.InitHeaders();
EXPECT_TRUE(elf.eh_frame() == nullptr);
EXPECT_FALSE(elf.debug_frame() == nullptr);
}
-TEST_F(ElfInterfaceTest, init_headers_debug_frame32) {
+TEST_F(ElfInterfaceTest, init_headers_debug_frame_32) {
InitHeadersDebugFrame<ElfInterface32Fake>();
}
-TEST_F(ElfInterfaceTest, init_headers_debug_frame64) {
+TEST_F(ElfInterfaceTest, init_headers_debug_frame_64) {
InitHeadersDebugFrame<ElfInterface64Fake>();
}
@@ -709,16 +723,16 @@
ehdr.e_phentsize = sizeof(Phdr);
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
}
-TEST_F(ElfInterfaceTest, init_program_headers_malformed32) {
+TEST_F(ElfInterfaceTest, init_program_headers_malformed_32) {
InitProgramHeadersMalformed<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, init_program_headers_malformed64) {
+TEST_F(ElfInterfaceTest, init_program_headers_malformed_64) {
InitProgramHeadersMalformed<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>();
}
@@ -732,16 +746,16 @@
ehdr.e_shentsize = sizeof(Shdr);
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
}
-TEST_F(ElfInterfaceTest, init_section_headers_malformed32) {
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_32) {
InitSectionHeadersMalformed<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, init_section_headers_malformed64) {
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_64) {
InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}
@@ -796,11 +810,10 @@
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
EXPECT_EQ(0U, elf->debug_frame_offset());
EXPECT_EQ(0U, elf->debug_frame_size());
EXPECT_EQ(0U, elf->gnu_debugdata_offset());
@@ -811,11 +824,11 @@
ASSERT_FALSE(elf->GetFunctionName(0x90010, &name, &name_offset));
}
-TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata32) {
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata_32) {
InitSectionHeadersMalformedSymData<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata64) {
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata_64) {
InitSectionHeadersMalformedSymData<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}
@@ -866,14 +879,13 @@
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one");
InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two");
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
EXPECT_EQ(0U, elf->debug_frame_offset());
EXPECT_EQ(0U, elf->debug_frame_size());
EXPECT_EQ(0U, elf->gnu_debugdata_offset());
@@ -890,19 +902,19 @@
EXPECT_EQ(32U, name_offset);
}
-TEST_F(ElfInterfaceTest, init_section_headers32) {
+TEST_F(ElfInterfaceTest, init_section_headers_32) {
InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(sizeof(Elf32_Shdr));
}
-TEST_F(ElfInterfaceTest, init_section_headers64) {
+TEST_F(ElfInterfaceTest, init_section_headers_64) {
InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(sizeof(Elf64_Shdr));
}
-TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size32) {
+TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size_32) {
InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(0x100);
}
-TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size64) {
+TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size_64) {
InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(0x100);
}
@@ -967,7 +979,7 @@
shdr.sh_type = SHT_PROGBITS;
shdr.sh_link = 2;
shdr.sh_name = 0x400;
- shdr.sh_addr = 0x6000;
+ shdr.sh_addr = 0xa000;
shdr.sh_offset = 0xa000;
shdr.sh_entsize = 0x100;
shdr.sh_size = 0xf00;
@@ -977,10 +989,10 @@
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_NOTE;
shdr.sh_name = 0x500;
+ shdr.sh_addr = 0xb000;
shdr.sh_offset = 0xb000;
shdr.sh_size = 0xf00;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
@@ -988,29 +1000,352 @@
memory_.SetMemory(0xf400, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
EXPECT_EQ(0x6000U, elf->debug_frame_offset());
+ EXPECT_EQ(0, elf->debug_frame_section_bias());
EXPECT_EQ(0x500U, elf->debug_frame_size());
+
EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset());
EXPECT_EQ(0x800U, elf->gnu_debugdata_size());
+
EXPECT_EQ(0x7000U, elf->eh_frame_offset());
+ EXPECT_EQ(0, elf->eh_frame_section_bias());
EXPECT_EQ(0x800U, elf->eh_frame_size());
+
EXPECT_EQ(0xa000U, elf->eh_frame_hdr_offset());
+ EXPECT_EQ(0, elf->eh_frame_hdr_section_bias());
EXPECT_EQ(0xf00U, elf->eh_frame_hdr_size());
+
EXPECT_EQ(0xb000U, elf->gnu_build_id_offset());
EXPECT_EQ(0xf00U, elf->gnu_build_id_size());
}
-TEST_F(ElfInterfaceTest, init_section_headers_offsets32) {
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_32) {
InitSectionHeadersOffsets<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, init_section_headers_offsets64) {
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_64) {
InitSectionHeadersOffsets<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}
+template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitSectionHeadersOffsetsEhFrameSectionBias(uint64_t addr, uint64_t offset,
+ int64_t expected_bias) {
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+ uint64_t elf_offset = 0x2000;
+
+ Ehdr ehdr = {};
+ ehdr.e_shoff = elf_offset;
+ ehdr.e_shnum = 4;
+ ehdr.e_shentsize = sizeof(Shdr);
+ ehdr.e_shstrndx = 2;
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ elf_offset += ehdr.e_shentsize;
+
+ Shdr shdr = {};
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_link = 2;
+ shdr.sh_name = 0x200;
+ shdr.sh_addr = 0x8000;
+ shdr.sh_offset = 0x8000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = 0x800;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+ elf_offset += ehdr.e_shentsize;
+
+ // The string data for section header names.
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x20000;
+ shdr.sh_offset = 0xf000;
+ shdr.sh_size = 0x1000;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+ elf_offset += ehdr.e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_link = 2;
+ shdr.sh_name = 0x100;
+ shdr.sh_addr = addr;
+ shdr.sh_offset = offset;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = 0x500;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+
+ memory_.SetMemory(0xf100, ".eh_frame", sizeof(".eh_frame"));
+ memory_.SetMemory(0xf200, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
+
+ int64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0, load_bias);
+ EXPECT_EQ(offset, elf->eh_frame_offset());
+ EXPECT_EQ(expected_bias, elf->eh_frame_section_bias());
+ EXPECT_EQ(0x500U, elf->eh_frame_size());
+
+ EXPECT_EQ(0x8000U, elf->eh_frame_hdr_offset());
+ EXPECT_EQ(0, elf->eh_frame_hdr_section_bias());
+ EXPECT_EQ(0x800U, elf->eh_frame_hdr_size());
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_zero_32) {
+ InitSectionHeadersOffsetsEhFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(0x4000,
+ 0x4000, 0);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_zero_64) {
+ InitSectionHeadersOffsetsEhFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(0x6000,
+ 0x6000, 0);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_positive_32) {
+ InitSectionHeadersOffsetsEhFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
+ 0x5000, 0x4000, 0x1000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_positive_64) {
+ InitSectionHeadersOffsetsEhFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
+ 0x6000, 0x4000, 0x2000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_negative_32) {
+ InitSectionHeadersOffsetsEhFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
+ 0x3000, 0x4000, -0x1000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_negative_64) {
+ InitSectionHeadersOffsetsEhFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
+ 0x6000, 0x9000, -0x3000);
+}
+
+template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitSectionHeadersOffsetsEhFrameHdrSectionBias(uint64_t addr,
+ uint64_t offset,
+ int64_t expected_bias) {
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+ uint64_t elf_offset = 0x2000;
+
+ Ehdr ehdr = {};
+ ehdr.e_shoff = elf_offset;
+ ehdr.e_shnum = 4;
+ ehdr.e_shentsize = sizeof(Shdr);
+ ehdr.e_shstrndx = 2;
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ elf_offset += ehdr.e_shentsize;
+
+ Shdr shdr = {};
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_link = 2;
+ shdr.sh_name = 0x200;
+ shdr.sh_addr = addr;
+ shdr.sh_offset = offset;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = 0x800;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+ elf_offset += ehdr.e_shentsize;
+
+ // The string data for section header names.
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x20000;
+ shdr.sh_offset = 0xf000;
+ shdr.sh_size = 0x1000;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+ elf_offset += ehdr.e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_link = 2;
+ shdr.sh_name = 0x100;
+ shdr.sh_addr = 0x5000;
+ shdr.sh_offset = 0x5000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = 0x500;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+
+ memory_.SetMemory(0xf100, ".eh_frame", sizeof(".eh_frame"));
+ memory_.SetMemory(0xf200, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
+
+ int64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0, load_bias);
+ EXPECT_EQ(0x5000U, elf->eh_frame_offset());
+ EXPECT_EQ(0, elf->eh_frame_section_bias());
+ EXPECT_EQ(0x500U, elf->eh_frame_size());
+ EXPECT_EQ(offset, elf->eh_frame_hdr_offset());
+ EXPECT_EQ(expected_bias, elf->eh_frame_hdr_section_bias());
+ EXPECT_EQ(0x800U, elf->eh_frame_hdr_size());
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_zero_32) {
+ InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(0x9000,
+ 0x9000, 0);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_zero_64) {
+ InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(0xa000,
+ 0xa000, 0);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_positive_32) {
+ InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
+ 0x9000, 0x4000, 0x5000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_positive_64) {
+ InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
+ 0x6000, 0x1000, 0x5000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_negative_32) {
+ InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
+ 0x3000, 0x5000, -0x2000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_negative_64) {
+ InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
+ 0x5000, 0x9000, -0x4000);
+}
+
+template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitSectionHeadersOffsetsDebugFrameSectionBias(uint64_t addr,
+ uint64_t offset,
+ int64_t expected_bias) {
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+ uint64_t elf_offset = 0x2000;
+
+ Ehdr ehdr = {};
+ ehdr.e_shoff = elf_offset;
+ ehdr.e_shnum = 3;
+ ehdr.e_shentsize = sizeof(Shdr);
+ ehdr.e_shstrndx = 2;
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ elf_offset += ehdr.e_shentsize;
+
+ Shdr shdr = {};
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_link = 2;
+ shdr.sh_name = 0x100;
+ shdr.sh_addr = addr;
+ shdr.sh_offset = offset;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = 0x800;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+ elf_offset += ehdr.e_shentsize;
+
+ // The string data for section header names.
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x20000;
+ shdr.sh_offset = 0xf000;
+ shdr.sh_size = 0x1000;
+ memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
+
+ memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
+
+ int64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0, load_bias);
+ EXPECT_EQ(offset, elf->debug_frame_offset());
+ EXPECT_EQ(expected_bias, elf->debug_frame_section_bias());
+ EXPECT_EQ(0x800U, elf->debug_frame_size());
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_zero_32) {
+ InitSectionHeadersOffsetsDebugFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(0x5000,
+ 0x5000, 0);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_zero_64) {
+ InitSectionHeadersOffsetsDebugFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(0xa000,
+ 0xa000, 0);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_positive_32) {
+ InitSectionHeadersOffsetsDebugFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
+ 0x5000, 0x2000, 0x3000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_positive_64) {
+ InitSectionHeadersOffsetsDebugFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
+ 0x7000, 0x1000, 0x6000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_negative_32) {
+ InitSectionHeadersOffsetsDebugFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
+ 0x6000, 0x7000, -0x1000);
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_negative_64) {
+ InitSectionHeadersOffsetsDebugFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
+ 0x3000, 0x5000, -0x2000);
+}
+
+template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+void ElfInterfaceTest::CheckGnuEhFrame(uint64_t addr, uint64_t offset, int64_t expected_bias) {
+ std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
+
+ Ehdr ehdr = {};
+ ehdr.e_phoff = 0x100;
+ ehdr.e_phnum = 2;
+ ehdr.e_phentsize = sizeof(Phdr);
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ uint64_t phdr_offset = 0x100;
+
+ Phdr phdr = {};
+ phdr.p_type = PT_LOAD;
+ phdr.p_memsz = 0x10000;
+ phdr.p_flags = PF_R | PF_X;
+ phdr.p_align = 0x1000;
+ memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
+ phdr_offset += sizeof(phdr);
+
+ memset(&phdr, 0, sizeof(phdr));
+ phdr.p_type = PT_GNU_EH_FRAME;
+ phdr.p_paddr = addr;
+ phdr.p_offset = offset;
+ memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
+
+ int64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0, load_bias);
+ EXPECT_EQ(expected_bias, elf->eh_frame_hdr_section_bias());
+}
+
+TEST_F(ElfInterfaceTest, eh_frame_zero_section_bias_32) {
+ ElfInterfaceTest::CheckGnuEhFrame<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x4000, 0x4000, 0);
+}
+
+TEST_F(ElfInterfaceTest, eh_frame_zero_section_bias_64) {
+ ElfInterfaceTest::CheckGnuEhFrame<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x4000, 0x4000, 0);
+}
+
+TEST_F(ElfInterfaceTest, eh_frame_positive_section_bias_32) {
+ ElfInterfaceTest::CheckGnuEhFrame<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x4000, 0x1000, 0x3000);
+}
+
+TEST_F(ElfInterfaceTest, eh_frame_positive_section_bias_64) {
+ ElfInterfaceTest::CheckGnuEhFrame<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x4000, 0x1000, 0x3000);
+}
+
+TEST_F(ElfInterfaceTest, eh_frame_negative_section_bias_32) {
+ ElfInterfaceTest::CheckGnuEhFrame<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x4000, 0x5000,
+ -0x1000);
+}
+
+TEST_F(ElfInterfaceTest, eh_frame_negative_section_bias_64) {
+ ElfInterfaceTest::CheckGnuEhFrame<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x4000, 0x5000,
+ -0x1000);
+}
+
TEST_F(ElfInterfaceTest, is_valid_pc_from_pt_load) {
std::unique_ptr<ElfInterface> elf(new ElfInterface32(&memory_));
@@ -1028,9 +1363,9 @@
phdr.p_align = 0x1000;
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0, load_bias);
EXPECT_TRUE(elf->IsValidPc(0));
EXPECT_TRUE(elf->IsValidPc(0x5000));
EXPECT_TRUE(elf->IsValidPc(0xffff));
@@ -1054,9 +1389,9 @@
phdr.p_align = 0x1000;
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000U, load_bias);
+ EXPECT_EQ(0x2000, load_bias);
EXPECT_FALSE(elf->IsValidPc(0));
EXPECT_FALSE(elf->IsValidPc(0x1000));
EXPECT_FALSE(elf->IsValidPc(0x1fff));
@@ -1111,10 +1446,10 @@
memory_.SetData32(0x708, 0x2100);
memory_.SetData32(0x70c, 0x200);
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- elf->InitHeaders(0);
- EXPECT_EQ(0U, load_bias);
+ elf->InitHeaders();
+ EXPECT_EQ(0, load_bias);
EXPECT_FALSE(elf->IsValidPc(0));
EXPECT_FALSE(elf->IsValidPc(0x20ff));
EXPECT_TRUE(elf->IsValidPc(0x2100));
@@ -1168,10 +1503,10 @@
memory_.SetData32(0x708, 0x20f8);
memory_.SetData32(0x70c, 0x200);
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- elf->InitHeaders(0);
- EXPECT_EQ(0U, load_bias);
+ elf->InitHeaders();
+ EXPECT_EQ(0, load_bias);
EXPECT_FALSE(elf->IsValidPc(0));
EXPECT_FALSE(elf->IsValidPc(0x27ff));
EXPECT_TRUE(elf->IsValidPc(0x2800));
@@ -1207,7 +1542,6 @@
note_offset += sizeof("GNU");
// This part of the note does not contain any trailing '\0'.
memcpy(¬e_section[note_offset], "BUILDID", 7);
- note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1224,16 +1558,23 @@
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
ASSERT_EQ("BUILDID", elf->GetBuildID());
}
+TEST_F(ElfInterfaceTest, build_id_32) {
+ BuildID<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, build_id_64) {
+ BuildID<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDTwoNotes() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -1272,7 +1613,6 @@
note_offset += sizeof("GNU");
// This part of the note does not contain any trailing '\0'.
memcpy(¬e_section[note_offset], "BUILDID", 7);
- note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1289,16 +1629,23 @@
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
ASSERT_EQ("BUILDID", elf->GetBuildID());
}
+TEST_F(ElfInterfaceTest, build_id_two_notes_32) {
+ BuildIDTwoNotes<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, build_id_two_notes_64) {
+ BuildIDTwoNotes<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDSectionTooSmallForName () {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -1326,7 +1673,6 @@
note_offset += sizeof("GNU");
// This part of the note does not contain any trailing '\0'.
memcpy(¬e_section[note_offset], "BUILDID", 7);
- note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1343,16 +1689,23 @@
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
ASSERT_EQ("", elf->GetBuildID());
}
+TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name_32) {
+ BuildIDSectionTooSmallForName<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name_64) {
+ BuildIDSectionTooSmallForName<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDSectionTooSmallForDesc () {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -1380,7 +1733,6 @@
note_offset += sizeof("GNU");
// This part of the note does not contain any trailing '\0'.
memcpy(¬e_section[note_offset], "BUILDID", 7);
- note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1397,16 +1749,23 @@
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
ASSERT_EQ("", elf->GetBuildID());
}
+TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc_32) {
+ BuildIDSectionTooSmallForDesc<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc_64) {
+ BuildIDSectionTooSmallForDesc<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDSectionTooSmallForHeader () {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -1434,7 +1793,6 @@
note_offset += sizeof("GNU");
// This part of the note does not contain any trailing '\0'.
memcpy(¬e_section[note_offset], "BUILDID", 7);
- note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1451,58 +1809,25 @@
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
- uint64_t load_bias = 0;
+ int64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
ASSERT_EQ("", elf->GetBuildID());
}
-TEST_F(ElfInterfaceTest, build_id32) {
- BuildID<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id64) {
- BuildID<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_two_notes32) {
- BuildIDTwoNotes<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_two_notes64) {
- BuildIDTwoNotes<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name32) {
- BuildIDSectionTooSmallForName<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name64) {
- BuildIDSectionTooSmallForName<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc32) {
- BuildIDSectionTooSmallForDesc<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc64) {
- BuildIDSectionTooSmallForDesc<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header32) {
+TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header_32) {
BuildIDSectionTooSmallForHeader<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
}
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header64) {
+TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header_64) {
BuildIDSectionTooSmallForHeader<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
}
template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
-void ElfInterfaceTest::CheckLoadBiasInFirstPhdr(uint64_t load_bias) {
+void ElfInterfaceTest::CheckLoadBiasInFirstPhdr(int64_t load_bias) {
Ehdr ehdr = {};
ehdr.e_phoff = 0x100;
ehdr.e_phnum = 2;
@@ -1526,11 +1851,11 @@
phdr.p_align = 0x1000;
memory_.SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
- uint64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
+ int64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
ASSERT_EQ(load_bias, static_load_bias);
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
- uint64_t init_load_bias = 0;
+ int64_t init_load_bias = 0;
ASSERT_TRUE(elf->Init(&init_load_bias));
ASSERT_EQ(init_load_bias, static_load_bias);
}
@@ -1553,7 +1878,7 @@
template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
void ElfInterfaceTest::CheckLoadBiasInFirstExecPhdr(uint64_t offset, uint64_t vaddr,
- uint64_t load_bias) {
+ int64_t load_bias) {
Ehdr ehdr = {};
ehdr.e_phoff = 0x100;
ehdr.e_phnum = 3;
@@ -1586,11 +1911,11 @@
phdr.p_align = 0x1000;
memory_.SetMemory(0x200 + sizeof(phdr), &phdr, sizeof(phdr));
- uint64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
+ int64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
ASSERT_EQ(load_bias, static_load_bias);
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
- uint64_t init_load_bias = 0;
+ int64_t init_load_bias = 0;
ASSERT_TRUE(elf->Init(&init_load_bias));
ASSERT_EQ(init_load_bias, static_load_bias);
}
@@ -1603,20 +1928,20 @@
CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000, 0x1000, 0);
}
-TEST_F(ElfInterfaceTest, get_load_bias_exec_non_zero_32) {
+TEST_F(ElfInterfaceTest, get_load_bias_exec_positive_32) {
CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x1000, 0x4000, 0x3000);
}
-TEST_F(ElfInterfaceTest, get_load_bias_exec_non_zero_64) {
+TEST_F(ElfInterfaceTest, get_load_bias_exec_positive_64) {
CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000, 0x4000, 0x3000);
}
-TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_from_error_32) {
- CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x5000, 0x1000, 0);
+TEST_F(ElfInterfaceTest, get_load_bias_exec_negative_32) {
+ CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x5000, 0x1000, -0x4000);
}
-TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_from_error_64) {
- CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, 0);
+TEST_F(ElfInterfaceTest, get_load_bias_exec_negative_64) {
+ CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, -0x4000);
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index c432d6d..8c1eade 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -310,8 +310,8 @@
ElfInterfaceMock(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterfaceMock() = default;
- bool Init(uint64_t*) override { return false; }
- void InitHeaders(uint64_t) override {}
+ bool Init(int64_t*) override { return false; }
+ void InitHeaders() override {}
std::string GetSoname() override { return ""; }
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; }
std::string GetBuildID() override { return ""; }
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
index 2c98928..da3dbf2 100644
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -84,7 +84,7 @@
elf_->FakeSetLoadBias(0);
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
- map_info_->load_bias = static_cast<uint64_t>(-1);
+ map_info_->load_bias = INT64_MAX;
elf_->FakeSetLoadBias(0x1000);
EXPECT_EQ(0x1000U, map_info_->GetLoadBias(process_memory_));
}
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoTest.cpp
index e2cbb98..ef76b1b 100644
--- a/libunwindstack/tests/MapInfoTest.cpp
+++ b/libunwindstack/tests/MapInfoTest.cpp
@@ -35,7 +35,7 @@
EXPECT_EQ(3UL, map_info.offset);
EXPECT_EQ(4UL, map_info.flags);
EXPECT_EQ("map", map_info.name);
- EXPECT_EQ(static_cast<uint64_t>(-1), map_info.load_bias);
+ EXPECT_EQ(INT64_MAX, map_info.load_bias);
EXPECT_EQ(0UL, map_info.elf_offset);
EXPECT_TRUE(map_info.elf.get() == nullptr);
}
@@ -51,7 +51,7 @@
EXPECT_EQ(3UL, map_info.offset);
EXPECT_EQ(4UL, map_info.flags);
EXPECT_EQ("string_map", map_info.name);
- EXPECT_EQ(static_cast<uint64_t>(-1), map_info.load_bias);
+ EXPECT_EQ(INT64_MAX, map_info.load_bias);
EXPECT_EQ(0UL, map_info.elf_offset);
EXPECT_TRUE(map_info.elf.get() == nullptr);
}
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index bded57a..72eef3e 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1534,4 +1534,53 @@
EXPECT_EQ(0x7ffd22415e90ULL, unwinder.frames()[16].sp);
}
+TEST_F(UnwindOfflineTest, load_bias_different_section_bias_arm64) {
+ ASSERT_NO_FATAL_FAILURE(Init("load_bias_different_section_bias_arm64/", ARCH_ARM64));
+
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.Unwind();
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(12U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000000d59bc linker64 (__dl_syscall+28)\n"
+ " #01 pc 00000000000554e8 linker64 (__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1148)\n"
+ " #02 pc 00000000000008c0 vdso (__kernel_rt_sigreturn)\n"
+ " #03 pc 000000000007f3e8 libc.so (abort+168)\n"
+ " #04 pc 00000000000459fc test (std::__ndk1::__throw_bad_cast()+4)\n"
+ " #05 pc 0000000000056d80 test (testing::Test::Run()+88)\n"
+ " #06 pc 000000000005724c test (testing::TestInfo::Run()+112)\n"
+ " #07 pc 0000000000057558 test (testing::TestSuite::Run()+116)\n"
+ " #08 pc 000000000005bffc test (testing::internal::UnitTestImpl::RunAllTests()+464)\n"
+ " #09 pc 000000000005bd9c test (testing::UnitTest::Run()+116)\n"
+ " #10 pc 00000000000464e4 test (main+144)\n"
+ " #11 pc 000000000007aa34 libc.so (__libc_init+108)\n",
+ frame_info);
+
+ EXPECT_EQ(0x7112cb99bcULL, unwinder.frames()[0].pc);
+ EXPECT_EQ(0x7112bdbbf0ULL, unwinder.frames()[0].sp);
+ EXPECT_EQ(0x7112c394e8ULL, unwinder.frames()[1].pc);
+ EXPECT_EQ(0x7112bdbbf0ULL, unwinder.frames()[1].sp);
+ EXPECT_EQ(0x7112be28c0ULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0x7112bdbda0ULL, unwinder.frames()[2].sp);
+ EXPECT_EQ(0x71115ab3e8ULL, unwinder.frames()[3].pc);
+ EXPECT_EQ(0x7fdd4a3f00ULL, unwinder.frames()[3].sp);
+ EXPECT_EQ(0x5f739dc9fcULL, unwinder.frames()[4].pc);
+ EXPECT_EQ(0x7fdd4a3fe0ULL, unwinder.frames()[4].sp);
+ EXPECT_EQ(0x5f739edd80ULL, unwinder.frames()[5].pc);
+ EXPECT_EQ(0x7fdd4a3ff0ULL, unwinder.frames()[5].sp);
+ EXPECT_EQ(0x5f739ee24cULL, unwinder.frames()[6].pc);
+ EXPECT_EQ(0x7fdd4a4010ULL, unwinder.frames()[6].sp);
+ EXPECT_EQ(0x5f739ee558ULL, unwinder.frames()[7].pc);
+ EXPECT_EQ(0x7fdd4a4040ULL, unwinder.frames()[7].sp);
+ EXPECT_EQ(0x5f739f2ffcULL, unwinder.frames()[8].pc);
+ EXPECT_EQ(0x7fdd4a4070ULL, unwinder.frames()[8].sp);
+ EXPECT_EQ(0x5f739f2d9cULL, unwinder.frames()[9].pc);
+ EXPECT_EQ(0x7fdd4a4100ULL, unwinder.frames()[9].sp);
+ EXPECT_EQ(0x5f739dd4e4ULL, unwinder.frames()[10].pc);
+ EXPECT_EQ(0x7fdd4a4130ULL, unwinder.frames()[10].sp);
+ EXPECT_EQ(0x71115a6a34ULL, unwinder.frames()[11].pc);
+ EXPECT_EQ(0x7fdd4a4170ULL, unwinder.frames()[11].sp);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so
new file mode 100644
index 0000000..7bb7156
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64 b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64
new file mode 100644
index 0000000..00a3896
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt
new file mode 100644
index 0000000..a2babee
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt
@@ -0,0 +1,7 @@
+5f73997000-5f739dc000 r--p 0 00:00 0 test
+5f739dc000-5f73a43000 r-xp 44000 00:00 0 test
+711152c000-711156e000 r--p 0 00:00 0 libc.so
+711156e000-7111611000 --xp 42000 00:00 0 libc.so
+7112be2000-7112be4000 r-xp 0 00:00 0 vdso
+7112be4000-7112c1c000 r--p 0 00:00 0 linker64
+7112c1c000-7112ce1000 r-xp 38000 00:00 0 linker64
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt
new file mode 100644
index 0000000..3c601e1
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt
@@ -0,0 +1,33 @@
+x0: 7112bdbc24
+x1: 0
+x2: ffffffff
+x3: 0
+x4: 0
+x5: 0
+x6: 0
+x7: 7f7f7f7f7f7f7f7f
+x8: 62
+x9: a78826643b37f4a1
+x10: 7112bdbc20
+x11: 4100
+x12: 7112bdbb70
+x13: 18
+x14: 1d6518077
+x15: 2a43148faf732a
+x16: 16fc0
+x17: 71115f61a0
+x18: 7111d6a000
+x19: 7112cef1b0
+x20: 7112bdbda0
+x21: 59616d61
+x22: 1
+x23: 7112bdbc24
+x24: 4b0e
+x25: 62
+x26: 2
+x27: 0
+x28: 7111934020
+x29: 7112bdbd90
+sp: 7112bdbbf0
+lr: 7112c394ec
+pc: 7112cb99bc
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data
new file mode 100644
index 0000000..1674733
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data
new file mode 100644
index 0000000..6d7b48a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test
new file mode 100644
index 0000000..3a75b8f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso
new file mode 100644
index 0000000..4940916
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso
Binary files differ
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 9d00602..953b859 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_UTILS_FLATTENABLE_H
#define ANDROID_UTILS_FLATTENABLE_H
+// DO NOT USE: please use parcelable instead
+// This code is deprecated and will not be supported via AIDL code gen. For data
+// to be sent over binder, please use parcelables.
#include <stdint.h>
#include <string.h>
@@ -28,7 +31,9 @@
namespace android {
-
+// DO NOT USE: please use parcelable instead
+// This code is deprecated and will not be supported via AIDL code gen. For data
+// to be sent over binder, please use parcelables.
class FlattenableUtils {
public:
template<size_t N>
@@ -79,7 +84,9 @@
}
};
-
+// DO NOT USE: please use parcelable instead
+// This code is deprecated and will not be supported via AIDL code gen. For data
+// to be sent over binder, please use parcelables.
/*
* The Flattenable protocol allows an object to serialize itself out
* to a byte-buffer and an array of file descriptors.
@@ -131,6 +138,9 @@
return static_cast<T*>(this)->T::unflatten(buffer, size, fds, count);
}
+// DO NOT USE: please use parcelable instead
+// This code is deprecated and will not be supported via AIDL code gen. For data
+// to be sent over binder, please use parcelables.
/*
* LightFlattenable is a protocol allowing object to serialize themselves out
* to a byte-buffer. Because it doesn't handle file-descriptors,
@@ -171,6 +181,9 @@
return static_cast<T*>(this)->T::unflatten(buffer, size);
}
+// DO NOT USE: please use parcelable instead
+// This code is deprecated and will not be supported via AIDL code gen. For data
+// to be sent over binder, please use parcelables.
/*
* LightFlattenablePod is an implementation of the LightFlattenable protocol
* for POD (plain-old-data) objects.
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 372e10f..a5411d8 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -31,6 +31,7 @@
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/socket.h>
+#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/types.h>
@@ -139,6 +140,10 @@
/* ro.lmk.psi_complete_stall_ms property defaults */
#define DEF_COMPLETE_STALL 700
+static inline int sys_pidfd_open(pid_t pid, unsigned int flags) {
+ return syscall(__NR_pidfd_open, pid, flags);
+}
+
/* default to old in-kernel interface if no memory pressure events */
static bool use_inkernel_interface = true;
static bool has_inkernel_module;
@@ -169,6 +174,11 @@
static int level_oomadj[VMPRESS_LEVEL_COUNT];
static int mpevfd[VMPRESS_LEVEL_COUNT] = { -1, -1, -1 };
+static bool pidfd_supported;
+static int last_kill_pid_or_fd = -1;
+static struct timespec last_kill_tm;
+
+/* lmkd configurable parameters */
static bool debug_process_killing;
static bool enable_pressure_upgrade;
static int64_t upgrade_pressure;
@@ -197,6 +207,8 @@
POLLING_DO_NOT_CHANGE,
POLLING_START,
POLLING_STOP,
+ POLLING_PAUSE,
+ POLLING_RESUME,
};
/*
@@ -207,6 +219,7 @@
*/
struct polling_params {
struct event_handler_info* poll_handler;
+ struct event_handler_info* paused_handler;
struct timespec poll_start_tm;
struct timespec last_poll_tm;
int polling_interval_ms;
@@ -235,8 +248,11 @@
/* vmpressure event handler data */
static struct event_handler_info vmpressure_hinfo[VMPRESS_LEVEL_COUNT];
-/* 3 memory pressure levels, 1 ctrl listen socket, 2 ctrl data socket, 1 lmk events */
-#define MAX_EPOLL_EVENTS (2 + MAX_DATA_CONN + VMPRESS_LEVEL_COUNT)
+/*
+ * 1 ctrl listen socket, 2 ctrl data socket, 3 memory pressure levels,
+ * 1 lmk events + 1 fd to wait for process death
+ */
+#define MAX_EPOLL_EVENTS (1 + MAX_DATA_CONN + VMPRESS_LEVEL_COUNT + 1 + 1)
static int epollfd;
static int maxevents;
@@ -782,15 +798,15 @@
close(fd);
return -1;
}
+ line[ret] = '\0';
sscanf(line, "%d %d ", &total, &rss);
close(fd);
return rss;
}
-static char *proc_get_name(int pid) {
+static char *proc_get_name(int pid, char *buf, size_t buf_size) {
char path[PATH_MAX];
- static char line[LINE_MAX];
int fd;
char *cp;
ssize_t ret;
@@ -801,25 +817,24 @@
if (fd == -1) {
return NULL;
}
- ret = read_all(fd, line, sizeof(line) - 1);
+ ret = read_all(fd, buf, buf_size - 1);
close(fd);
if (ret < 0) {
return NULL;
}
+ buf[ret] = '\0';
- cp = strchr(line, ' ');
+ cp = strchr(buf, ' ');
if (cp) {
*cp = '\0';
- } else {
- line[ret] = '\0';
}
- return line;
+ return buf;
}
static void cmd_procprio(LMKD_CTRL_PACKET packet) {
struct proc *procp;
- char path[80];
+ char path[LINE_MAX];
char val[20];
int soft_limit_mult;
struct lmk_procprio params;
@@ -856,7 +871,8 @@
}
if (use_inkernel_interface) {
- stats_store_taskname(params.pid, proc_get_name(params.pid), kpoll_info.poll_fd);
+ stats_store_taskname(params.pid, proc_get_name(params.pid, path, sizeof(path)),
+ kpoll_info.poll_fd);
return;
}
@@ -1647,11 +1663,112 @@
closedir(d);
}
-static int last_killed_pid = -1;
+static bool is_kill_pending(void) {
+ char buf[24];
+
+ if (last_kill_pid_or_fd < 0) {
+ return false;
+ }
+
+ if (pidfd_supported) {
+ return true;
+ }
+
+ /* when pidfd is not supported base the decision on /proc/<pid> existence */
+ snprintf(buf, sizeof(buf), "/proc/%d/", last_kill_pid_or_fd);
+ if (access(buf, F_OK) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool is_waiting_for_kill(void) {
+ return pidfd_supported && last_kill_pid_or_fd >= 0;
+}
+
+static void stop_wait_for_proc_kill(bool finished) {
+ struct epoll_event epev;
+
+ if (last_kill_pid_or_fd < 0) {
+ return;
+ }
+
+ if (debug_process_killing) {
+ struct timespec curr_tm;
+
+ if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
+ /*
+ * curr_tm is used here merely to report kill duration, so this failure is not fatal.
+ * Log an error and continue.
+ */
+ ALOGE("Failed to get current time");
+ }
+
+ if (finished) {
+ ALOGI("Process got killed in %ldms",
+ get_time_diff_ms(&last_kill_tm, &curr_tm));
+ } else {
+ ALOGI("Stop waiting for process kill after %ldms",
+ get_time_diff_ms(&last_kill_tm, &curr_tm));
+ }
+ }
+
+ if (pidfd_supported) {
+ /* unregister fd */
+ if (epoll_ctl(epollfd, EPOLL_CTL_DEL, last_kill_pid_or_fd, &epev) != 0) {
+ ALOGE("epoll_ctl for last killed process failed; errno=%d", errno);
+ return;
+ }
+ maxevents--;
+ close(last_kill_pid_or_fd);
+ }
+
+ last_kill_pid_or_fd = -1;
+}
+
+static void kill_done_handler(int data __unused, uint32_t events __unused,
+ struct polling_params *poll_params) {
+ stop_wait_for_proc_kill(true);
+ poll_params->update = POLLING_RESUME;
+}
+
+static void start_wait_for_proc_kill(int pid) {
+ static struct event_handler_info kill_done_hinfo = { 0, kill_done_handler };
+ struct epoll_event epev;
+
+ if (last_kill_pid_or_fd >= 0) {
+ /* Should not happen but if it does we should stop previous wait */
+ ALOGE("Attempt to wait for a kill while another wait is in progress");
+ stop_wait_for_proc_kill(false);
+ }
+
+ if (!pidfd_supported) {
+ /* If pidfd is not supported store PID of the process being killed */
+ last_kill_pid_or_fd = pid;
+ return;
+ }
+
+ last_kill_pid_or_fd = TEMP_FAILURE_RETRY(sys_pidfd_open(pid, 0));
+ if (last_kill_pid_or_fd < 0) {
+ ALOGE("pidfd_open for process pid %d failed; errno=%d", pid, errno);
+ return;
+ }
+
+ epev.events = EPOLLIN;
+ epev.data.ptr = (void *)&kill_done_hinfo;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, last_kill_pid_or_fd, &epev) != 0) {
+ ALOGE("epoll_ctl for last kill failed; errno=%d", errno);
+ close(last_kill_pid_or_fd);
+ last_kill_pid_or_fd = -1;
+ return;
+ }
+ maxevents++;
+}
/* Kill one process specified by procp. Returns the size of the process killed */
static int kill_one_process(struct proc* procp, int min_oom_score, int kill_reason,
- const char *kill_desc, union meminfo *mi) {
+ const char *kill_desc, union meminfo *mi, struct timespec *tm) {
int pid = procp->pid;
uid_t uid = procp->uid;
int tgid;
@@ -1660,6 +1777,7 @@
int r;
int result = -1;
struct memory_stat *mem_st;
+ char buf[LINE_MAX];
tgid = proc_get_tgid(pid);
if (tgid >= 0 && tgid != pid) {
@@ -1667,7 +1785,7 @@
goto out;
}
- taskname = proc_get_name(pid);
+ taskname = proc_get_name(pid, buf, sizeof(buf));
if (!taskname) {
goto out;
}
@@ -1681,12 +1799,16 @@
TRACE_KILL_START(pid);
+ /* Have to start waiting before sending SIGKILL to make sure pid is valid */
+ start_wait_for_proc_kill(pid);
+
/* CAP_KILL required */
r = kill(pid, SIGKILL);
TRACE_KILL_END();
if (r) {
+ stop_wait_for_proc_kill(false);
ALOGE("kill(%d): errno=%d", pid, errno);
/* Delete process record even when we fail to kill so that we don't get stuck on it */
goto out;
@@ -1694,6 +1816,8 @@
set_process_group_and_prio(pid, SP_FOREGROUND, ANDROID_PRIORITY_HIGHEST);
+ last_kill_tm = *tm;
+
inc_killcnt(procp->oomadj);
killinfo_log(procp, min_oom_score, tasksize, kill_reason, mi);
@@ -1706,8 +1830,6 @@
uid, procp->oomadj, tasksize * page_k);
}
- last_killed_pid = pid;
-
stats_write_lmk_kill_occurred(LMK_KILL_OCCURRED, uid, taskname,
procp->oomadj, min_oom_score, tasksize, mem_st);
@@ -1727,7 +1849,7 @@
* Returns size of the killed process.
*/
static int find_and_kill_process(int min_score_adj, int kill_reason, const char *kill_desc,
- union meminfo *mi) {
+ union meminfo *mi, struct timespec *tm) {
int i;
int killed_size = 0;
bool lmk_state_change_start = false;
@@ -1742,7 +1864,7 @@
if (!procp)
break;
- killed_size = kill_one_process(procp, min_score_adj, kill_reason, kill_desc, mi);
+ killed_size = kill_one_process(procp, min_score_adj, kill_reason, kill_desc, mi, tm);
if (killed_size >= 0) {
if (!lmk_state_change_start) {
lmk_state_change_start = true;
@@ -1821,23 +1943,6 @@
level - 1 : level);
}
-static bool is_kill_pending(void) {
- char buf[24];
-
- if (last_killed_pid < 0) {
- return false;
- }
-
- snprintf(buf, sizeof(buf), "/proc/%d/", last_killed_pid);
- if (access(buf, F_OK) == 0) {
- return true;
- }
-
- // reset last killed PID because there's nothing pending
- last_killed_pid = -1;
- return false;
-}
-
enum zone_watermark {
WMARK_MIN = 0,
WMARK_LOW,
@@ -1933,9 +2038,13 @@
/* Skip while still killing a process */
if (is_kill_pending()) {
- /* TODO: replace this quick polling with pidfd polling if kernel supports */
goto no_kill;
}
+ /*
+ * Process is dead, stop waiting. This has no effect if pidfds are supported and
+ * death notification already caused waiting to stop.
+ */
+ stop_wait_for_proc_kill(true);
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
ALOGE("Failed to get current time");
@@ -2066,7 +2175,8 @@
/* Kill a process if necessary */
if (kill_reason != NONE) {
- int pages_freed = find_and_kill_process(min_score_adj, kill_reason, kill_desc, &mi);
+ int pages_freed = find_and_kill_process(min_score_adj, kill_reason, kill_desc, &mi,
+ &curr_tm);
if (pages_freed > 0) {
killing = true;
if (cut_thrashing_limit) {
@@ -2080,6 +2190,13 @@
}
no_kill:
+ /* Do not poll if kernel supports pidfd waiting */
+ if (is_waiting_for_kill()) {
+ /* Pause polling if we are waiting for process death notification */
+ poll_params->update = POLLING_PAUSE;
+ return;
+ }
+
/*
* Start polling after initial PSI event;
* extend polling while device is in direct reclaim or process is being killed;
@@ -2109,7 +2226,6 @@
union meminfo mi;
struct zoneinfo zi;
struct timespec curr_tm;
- static struct timespec last_kill_tm;
static unsigned long kill_skip_count = 0;
enum vmpressure_level level = (enum vmpressure_level)data;
long other_free = 0, other_file = 0;
@@ -2158,15 +2274,26 @@
return;
}
- if (kill_timeout_ms) {
- // If we're within the timeout, see if there's pending reclaim work
- // from the last killed process. If there is (as evidenced by
- // /proc/<pid> continuing to exist), skip killing for now.
- if ((get_time_diff_ms(&last_kill_tm, &curr_tm) < kill_timeout_ms) &&
- (low_ram_device || is_kill_pending())) {
+ if (kill_timeout_ms && get_time_diff_ms(&last_kill_tm, &curr_tm) < kill_timeout_ms) {
+ /*
+ * If we're within the no-kill timeout, see if there's pending reclaim work
+ * from the last killed process. If so, skip killing for now.
+ */
+ if (is_kill_pending()) {
kill_skip_count++;
return;
}
+ /*
+ * Process is dead, stop waiting. This has no effect if pidfds are supported and
+ * death notification already caused waiting to stop.
+ */
+ stop_wait_for_proc_kill(true);
+ } else {
+ /*
+ * Killing took longer than no-kill timeout. Stop waiting for the last process
+ * to die because we are ready to kill again.
+ */
+ stop_wait_for_proc_kill(false);
}
if (kill_skip_count > 0) {
@@ -2265,7 +2392,7 @@
do_kill:
if (low_ram_device) {
/* For Go devices kill only one task */
- if (find_and_kill_process(level_oomadj[level], -1, NULL, &mi) == 0) {
+ if (find_and_kill_process(level_oomadj[level], -1, NULL, &mi, &curr_tm) == 0) {
if (debug_process_killing) {
ALOGI("Nothing to kill");
}
@@ -2288,7 +2415,7 @@
min_score_adj = level_oomadj[level];
}
- pages_freed = find_and_kill_process(min_score_adj, -1, NULL, &mi);
+ pages_freed = find_and_kill_process(min_score_adj, -1, NULL, &mi, &curr_tm);
if (pages_freed == 0) {
/* Rate limit kill reports when nothing was reclaimed */
@@ -2296,9 +2423,6 @@
report_skip_count++;
return;
}
- } else {
- /* If we killed anything, update the last killed timestamp. */
- last_kill_tm = curr_tm;
}
/* Log whenever we kill or when report rate limit allows */
@@ -2321,6 +2445,10 @@
last_report_tm = curr_tm;
}
+ if (is_waiting_for_kill()) {
+ /* pause polling if we are waiting for process death notification */
+ poll_params->update = POLLING_PAUSE;
+ }
}
static bool init_mp_psi(enum vmpressure_level level, bool use_new_strategy) {
@@ -2472,6 +2600,7 @@
.fd = -1,
};
struct epoll_event epev;
+ int pidfd;
int i;
int ret;
@@ -2562,9 +2691,61 @@
ALOGE("Failed to read %s: %s", file_data.filename, strerror(errno));
}
+ /* check if kernel supports pidfd_open syscall */
+ pidfd = TEMP_FAILURE_RETRY(sys_pidfd_open(getpid(), 0));
+ if (pidfd < 0) {
+ pidfd_supported = (errno != ENOSYS);
+ } else {
+ pidfd_supported = true;
+ close(pidfd);
+ }
+ ALOGI("Process polling is %s", pidfd_supported ? "supported" : "not supported" );
+
return 0;
}
+static void call_handler(struct event_handler_info* handler_info,
+ struct polling_params *poll_params, uint32_t events) {
+ struct timespec curr_tm;
+
+ handler_info->handler(handler_info->data, events, poll_params);
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
+ poll_params->last_poll_tm = curr_tm;
+
+ switch (poll_params->update) {
+ case POLLING_START:
+ /*
+ * Poll for the duration of PSI_WINDOW_SIZE_MS after the
+ * initial PSI event because psi events are rate-limited
+ * at one per sec.
+ */
+ poll_params->poll_start_tm = curr_tm;
+ if (poll_params->poll_handler != handler_info) {
+ poll_params->poll_handler = handler_info;
+ }
+ break;
+ case POLLING_STOP:
+ poll_params->poll_handler = NULL;
+ break;
+ case POLLING_PAUSE:
+ poll_params->paused_handler = handler_info;
+ poll_params->poll_handler = NULL;
+ break;
+ case POLLING_RESUME:
+ poll_params->poll_start_tm = curr_tm;
+ poll_params->poll_handler = poll_params->paused_handler;
+ break;
+ case POLLING_DO_NOT_CHANGE:
+ if (get_time_diff_ms(&poll_params->poll_start_tm, &curr_tm) > PSI_WINDOW_SIZE_MS) {
+ /* Polled for the duration of PSI window, time to stop */
+ poll_params->poll_handler = NULL;
+ }
+ /* WARNING: skipping the rest of the function */
+ return;
+ }
+ poll_params->update = POLLING_DO_NOT_CHANGE;
+}
+
static void mainloop(void) {
struct event_handler_info* handler_info;
struct polling_params poll_params;
@@ -2581,41 +2762,33 @@
int i;
if (poll_params.poll_handler) {
- /* Calculate next timeout */
- clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
- delay = get_time_diff_ms(&poll_params.last_poll_tm, &curr_tm);
- delay = (delay < poll_params.polling_interval_ms) ?
- poll_params.polling_interval_ms - delay : poll_params.polling_interval_ms;
-
- /* Wait for events until the next polling timeout */
- nevents = epoll_wait(epollfd, events, maxevents, delay);
+ bool poll_now;
clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
- if (get_time_diff_ms(&poll_params.last_poll_tm, &curr_tm) >=
- poll_params.polling_interval_ms) {
- /* Set input params for the call */
- poll_params.poll_handler->handler(poll_params.poll_handler->data, 0, &poll_params);
- poll_params.last_poll_tm = curr_tm;
+ if (poll_params.poll_handler == poll_params.paused_handler) {
+ /*
+ * Just transitioned into POLLING_RESUME. Reset paused_handler
+ * and poll immediately
+ */
+ poll_params.paused_handler = NULL;
+ poll_now = true;
+ nevents = 0;
+ } else {
+ /* Calculate next timeout */
+ delay = get_time_diff_ms(&poll_params.last_poll_tm, &curr_tm);
+ delay = (delay < poll_params.polling_interval_ms) ?
+ poll_params.polling_interval_ms - delay : poll_params.polling_interval_ms;
- if (poll_params.update != POLLING_DO_NOT_CHANGE) {
- switch (poll_params.update) {
- case POLLING_START:
- poll_params.poll_start_tm = curr_tm;
- break;
- case POLLING_STOP:
- poll_params.poll_handler = NULL;
- break;
- default:
- break;
- }
- poll_params.update = POLLING_DO_NOT_CHANGE;
- } else {
- if (get_time_diff_ms(&poll_params.poll_start_tm, &curr_tm) >
- PSI_WINDOW_SIZE_MS) {
- /* Polled for the duration of PSI window, time to stop */
- poll_params.poll_handler = NULL;
- }
- }
+ /* Wait for events until the next polling timeout */
+ nevents = epoll_wait(epollfd, events, maxevents, delay);
+
+ /* Update current time after wait */
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
+ poll_now = (get_time_diff_ms(&poll_params.last_poll_tm, &curr_tm) >=
+ poll_params.polling_interval_ms);
+ }
+ if (poll_now) {
+ call_handler(poll_params.poll_handler, &poll_params, 0);
}
} else {
/* Wait for events with no timeout */
@@ -2655,29 +2828,7 @@
}
if (evt->data.ptr) {
handler_info = (struct event_handler_info*)evt->data.ptr;
- /* Set input params for the call */
- handler_info->handler(handler_info->data, evt->events, &poll_params);
-
- if (poll_params.update != POLLING_DO_NOT_CHANGE) {
- switch (poll_params.update) {
- case POLLING_START:
- /*
- * Poll for the duration of PSI_WINDOW_SIZE_MS after the
- * initial PSI event because psi events are rate-limited
- * at one per sec.
- */
- clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
- poll_params.poll_start_tm = poll_params.last_poll_tm = curr_tm;
- poll_params.poll_handler = handler_info;
- break;
- case POLLING_STOP:
- poll_params.poll_handler = NULL;
- break;
- default:
- break;
- }
- poll_params.update = POLLING_DO_NOT_CHANGE;
- }
+ call_handler(handler_info, &poll_params, evt->events);
}
}
}
diff --git a/logcat/Android.bp b/logcat/Android.bp
index f1b18b2..e6b0c7d 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -50,16 +50,13 @@
],
}
-cc_prebuilt_binary {
+sh_binary {
name: "logpersist.start",
- srcs: ["logpersist"],
+ src: "logpersist",
init_rc: ["logcatd.rc"],
required: ["logcatd"],
symlinks: [
"logpersist.stop",
"logpersist.cat",
],
- strip: {
- none: true,
- },
}
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 665bd38..d9cc0db 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -143,10 +143,6 @@
void LogAudit::auditParse(const std::string& string, uid_t uid,
std::string* bug_num) {
- if (!__android_log_is_debuggable()) {
- bug_num->assign("");
- return;
- }
static std::map<std::string, std::string> denial_to_bug =
populateDenialMap();
std::string scontext = denialParse(string, ':', "scontext=u:object_r:");
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index c8f0a8b..e1bb02f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -236,12 +236,10 @@
ifeq ($(_enforce_vndk_at_runtime),true)
# for VNDK enforced devices
-LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
-include $(BUILD_SYSTEM)/base_rules.mk
-ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
-check_backward_compatibility := true
-vndk_version := $(PLATFORM_VNDK_VERSION)
-include $(LOCAL_PATH)/update_and_install_ld_config.mk
+# This file will be replaced with dynamically generated one from system/linkerconfig
+LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+LOCAL_SRC_FILES := etc/ld.config.txt
+include $(BUILD_PREBUILT)
else ifeq ($(_enforce_vndk_lite_at_runtime),true)
@@ -262,36 +260,6 @@
endif # ifeq ($(_enforce_vndk_at_runtime),true)
-# ld.config.txt for VNDK versions older than PLATFORM_VNDK_VERSION
-# are built with the VNDK libraries lists under /prebuilts/vndk.
-#
-# ld.config.$(VER).txt is built and installed for all VNDK versions
-# listed in PRODUCT_EXTRA_VNDK_VERSIONS.
-#
-# $(1): VNDK version
-define build_versioned_ld_config
-include $(CLEAR_VARS)
-LOCAL_MODULE := ld.config.$(1).txt
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
-LOCAL_MODULE_STEM := $$(LOCAL_MODULE)
-include $(BUILD_SYSTEM)/base_rules.mk
-ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
-check_backward_compatibility := true
-vndk_version := $(1)
-lib_list_from_prebuilts := true
-include $(LOCAL_PATH)/update_and_install_ld_config.mk
-endef
-
-vndk_snapshots := $(wildcard prebuilts/vndk/*)
-supported_vndk_snapshot_versions := \
- $(strip $(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)))
-$(foreach ver,$(supported_vndk_snapshot_versions),\
- $(eval $(call build_versioned_ld_config,$(ver))))
-
-vndk_snapshots :=
-supported_vndk_snapshot_versions :=
-
#######################################
# ld.config.vndk_lite.txt
#
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index bb8d4d0..a99756a 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -42,29 +42,29 @@
# APEX related namespaces.
###############################################################################
-additional.namespaces = runtime,conscrypt,media,neuralnetworks,resolv
+additional.namespaces = art,conscrypt,media,neuralnetworks,resolv
# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
# If a shared library or an executable requests a shared library that
# cannot be loaded into the default namespace, the dynamic linker tries
-# to load the shared library from the runtime namespace. And then, if the
-# shared library cannot be loaded from the runtime namespace either, the
+# to load the shared library from the art namespace. And then, if the
+# shared library cannot be loaded from the art namespace either, the
# dynamic linker tries to load the shared library from the resolv namespace.
# Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = runtime,resolv,neuralnetworks
-namespace.default.asan.links = runtime,resolv,neuralnetworks
-namespace.default.link.runtime.shared_libs = libandroidicu.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
+namespace.default.links = art,resolv,neuralnetworks
+namespace.default.asan.links = art,resolv,neuralnetworks
+namespace.default.link.art.shared_libs = libandroidicu.so
+namespace.default.link.art.shared_libs += libdexfile_external.so
+namespace.default.link.art.shared_libs += libdexfiled_external.so
# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.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
+namespace.default.link.art.shared_libs += libicui18n.so
+namespace.default.link.art.shared_libs += libicuuc.so
+namespace.default.link.art.shared_libs += libnativebridge.so
+namespace.default.link.art.shared_libs += libnativehelper.so
+namespace.default.link.art.shared_libs += libnativeloader.so
# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.runtime.shared_libs += libpac.so
+namespace.default.link.art.shared_libs += libpac.so
# When libnetd_resolv.so can't be found in the default namespace, search for it
# in the resolv namespace. Don't allow any other libraries from the resolv namespace
@@ -75,25 +75,25 @@
namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
###############################################################################
-# "runtime" APEX namespace
+# "art" APEX namespace
#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
+# This namespace exposes externally accessible libraries from the ART APEX.
+# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
+namespace.art.isolated = true
# Visible to allow links to be created at runtime, e.g. through
# android_link_namespaces in libnativeloader.
-namespace.runtime.visible = true
+namespace.art.visible = true
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
+namespace.art.search.paths = /apex/com.android.art/${LIB}
+namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
+namespace.art.links = default,neuralnetworks
# Need allow_all_shared_libs because libart.so can dlopen oat files in
# /system/framework and /data.
# TODO(b/130340935): Use a dynamically created linker namespace similar to
# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
+namespace.art.link.default.allow_all_shared_libs = true
+namespace.art.link.neuralnetworks.shared_libs = libneuralnetworks.so
###############################################################################
# "media" APEX namespace
@@ -136,8 +136,8 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
+namespace.conscrypt.links = art,default
+namespace.conscrypt.link.art.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 60035aa..5c87843 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -1,803 +1,3 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Bionic loader config file.
-#
-
-# Don't change the order here. The first pattern that matches with the
-# absolute path of an executable is selected.
-dir.system = /system/bin/
-dir.system = /system/xbin/
-dir.system = /%SYSTEM_EXT%/bin/
-dir.system = /%PRODUCT%/bin/
-
-dir.vendor = /odm/bin/
-dir.vendor = /vendor/bin/
-dir.vendor = /data/nativetest/odm
-dir.vendor = /data/nativetest64/odm
-dir.vendor = /data/benchmarktest/odm
-dir.vendor = /data/benchmarktest64/odm
-dir.vendor = /data/nativetest/vendor
-dir.vendor = /data/nativetest64/vendor
-dir.vendor = /data/benchmarktest/vendor
-dir.vendor = /data/benchmarktest64/vendor
-
-dir.unrestricted = /data/nativetest/unrestricted
-dir.unrestricted = /data/nativetest64/unrestricted
-
-# TODO(b/123864775): Ensure tests are run from /data/nativetest{,64} or (if
-# necessary) the unrestricted subdirs above. Then clean this up.
-dir.unrestricted = /data/local/tmp
-
-dir.postinstall = /postinstall
-
-# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
-# This must be last.
-dir.system = /data
-
-[system]
-additional.namespaces = runtime,conscrypt,media,neuralnetworks,resolv,sphal,vndk,rs
-
-###############################################################################
-# "default" namespace
-#
-# Framework-side code runs in this namespace. Libs from /vendor partition
-# can't be loaded in this namespace.
-###############################################################################
-namespace.default.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.default.visible = true
-
-namespace.default.search.paths = /system/${LIB}
-namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
-
-# We can't have entire /system/${LIB} as permitted paths because doing so
-# makes it possible to load libs in /system/${LIB}/vndk* directories by
-# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
-# VNDK libs are built with previous versions of Android and thus must not be
-# loaded into this namespace where libs built with the current version of
-# Android are loaded. Mixing the two types of libs in the same namespace can
-# cause unexpected problem.
-namespace.default.permitted.paths = /system/${LIB}/drm
-namespace.default.permitted.paths += /system/${LIB}/extractors
-namespace.default.permitted.paths += /system/${LIB}/hw
-namespace.default.permitted.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.permitted.paths += /%PRODUCT%/${LIB}
-# These are where odex files are located. libart has to be able to dlopen the files
-namespace.default.permitted.paths += /system/framework
-namespace.default.permitted.paths += /system/app
-namespace.default.permitted.paths += /system/priv-app
-namespace.default.permitted.paths += /%SYSTEM_EXT%/framework
-namespace.default.permitted.paths += /%SYSTEM_EXT%/app
-namespace.default.permitted.paths += /%SYSTEM_EXT%/priv-app
-namespace.default.permitted.paths += /vendor/framework
-namespace.default.permitted.paths += /vendor/app
-namespace.default.permitted.paths += /vendor/priv-app
-namespace.default.permitted.paths += /system/vendor/framework
-namespace.default.permitted.paths += /system/vendor/app
-namespace.default.permitted.paths += /system/vendor/priv-app
-namespace.default.permitted.paths += /odm/framework
-namespace.default.permitted.paths += /odm/app
-namespace.default.permitted.paths += /odm/priv-app
-namespace.default.permitted.paths += /oem/app
-namespace.default.permitted.paths += /%PRODUCT%/framework
-namespace.default.permitted.paths += /%PRODUCT%/app
-namespace.default.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.permitted.paths += /data
-namespace.default.permitted.paths += /mnt/expand
-namespace.default.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
-namespace.default.permitted.paths += /system/${LIB}/bootstrap
-
-namespace.default.asan.search.paths = /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /%PRODUCT%/${LIB}
-
-namespace.default.asan.permitted.paths = /data
-namespace.default.asan.permitted.paths += /system/${LIB}/drm
-namespace.default.asan.permitted.paths += /system/${LIB}/extractors
-namespace.default.asan.permitted.paths += /system/${LIB}/hw
-namespace.default.asan.permitted.paths += /system/framework
-namespace.default.asan.permitted.paths += /system/app
-namespace.default.asan.permitted.paths += /system/priv-app
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/framework
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/app
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/priv-app
-namespace.default.asan.permitted.paths += /vendor/framework
-namespace.default.asan.permitted.paths += /vendor/app
-namespace.default.asan.permitted.paths += /vendor/priv-app
-namespace.default.asan.permitted.paths += /system/vendor/framework
-namespace.default.asan.permitted.paths += /system/vendor/app
-namespace.default.asan.permitted.paths += /system/vendor/priv-app
-namespace.default.asan.permitted.paths += /odm/framework
-namespace.default.asan.permitted.paths += /odm/app
-namespace.default.asan.permitted.paths += /odm/priv-app
-namespace.default.asan.permitted.paths += /oem/app
-namespace.default.asan.permitted.paths += /%PRODUCT%/${LIB}
-namespace.default.asan.permitted.paths += /%PRODUCT%/framework
-namespace.default.asan.permitted.paths += /%PRODUCT%/app
-namespace.default.asan.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.asan.permitted.paths += /mnt/expand
-namespace.default.asan.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
-namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
-
-# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-# If a shared library or an executable requests a shared library that
-# cannot be loaded into the default namespace, the dynamic linker tries
-# to load the shared library from the runtime namespace. And then, if the
-# shared library cannot be loaded from the runtime namespace either, the
-# dynamic linker tries to load the shared library from the resolv namespace.
-# Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = runtime,resolv,neuralnetworks
-namespace.default.link.runtime.shared_libs = libandroidicu.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.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
-
-# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.runtime.shared_libs += libpac.so
-namespace.default.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# When libnetd_resolv.so can't be found in the default namespace, search for it
-# in the resolv namespace. Don't allow any other libraries from the resolv namespace
-# to be loaded in the default namespace.
-namespace.default.link.resolv.shared_libs = libnetd_resolv.so
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.runtime.visible = true
-
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
-# Need allow_all_shared_libs because libart.so can dlopen oat files in
-# /system/framework and /data.
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "media" APEX namespace
-#
-# This namespace is for libraries within the media APEX.
-###############################################################################
-namespace.media.isolated = true
-namespace.media.visible = true
-
-namespace.media.search.paths = /apex/com.android.media/${LIB}
-namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
-
-namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
-namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors
-
-namespace.media.links = default,neuralnetworks
-namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libbinder_ndk.so
-namespace.media.link.default.shared_libs += libcgrouprc.so
-namespace.media.link.default.shared_libs += libmediametrics.so
-namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "conscrypt" APEX namespace
-#
-# This namespace is for libraries within the conscrypt APEX.
-# Keep in sync with the "conscrypt" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.conscrypt.isolated = true
-namespace.conscrypt.visible = true
-
-namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
-namespace.conscrypt.link.default.shared_libs = libc.so
-namespace.conscrypt.link.default.shared_libs += libm.so
-namespace.conscrypt.link.default.shared_libs += libdl.so
-namespace.conscrypt.link.default.shared_libs += liblog.so
-
-###############################################################################
-# "resolv" APEX namespace
-#
-# This namespace is for libraries within the resolv APEX.
-###############################################################################
-namespace.resolv.isolated = true
-namespace.resolv.visible = true
-
-namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.links = default
-namespace.resolv.link.default.shared_libs = libc.so
-namespace.resolv.link.default.shared_libs += libcgrouprc.so
-namespace.resolv.link.default.shared_libs += libm.so
-namespace.resolv.link.default.shared_libs += libdl.so
-namespace.resolv.link.default.shared_libs += libbinder_ndk.so
-namespace.resolv.link.default.shared_libs += liblog.so
-namespace.resolv.link.default.shared_libs += libvndksupport.so
-
-###############################################################################
-# "sphal" namespace
-#
-# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
-# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
-# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
-#
-# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
-# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
-# that they should be searched and loaded from this namespace.
-#
-# Note that there is no link from the default namespace to this namespace.
-###############################################################################
-namespace.sphal.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.sphal.visible = true
-
-namespace.sphal.search.paths = /odm/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}/hw
-
-namespace.sphal.permitted.paths = /odm/${LIB}
-namespace.sphal.permitted.paths += /vendor/${LIB}
-namespace.sphal.permitted.paths += /system/vendor/${LIB}
-
-namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}
-namespace.sphal.asan.search.paths += /odm/${LIB}
-namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.search.paths += /vendor/${LIB}
-
-namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}
-namespace.sphal.asan.permitted.paths += /odm/${LIB}
-namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.permitted.paths += /vendor/${LIB}
-
-# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used. Order is important here as the namespaces are
-# tried in this order. rs should be before vndk because both are capable
-# of loading libRS_internal.so
-namespace.sphal.links = rs,default,vndk,neuralnetworks
-
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
-namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.sphal.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-
-###############################################################################
-# "rs" namespace
-#
-# This namespace is exclusively for Renderscript internal libraries.
-# This namespace has slightly looser restriction than the vndk namespace because
-# of the genuine characteristics of Renderscript; /data is in the permitted path
-# to load the compiled *.so file and libmediandk.so can be used here.
-###############################################################################
-namespace.rs.isolated = true
-namespace.rs.visible = true
-
-namespace.rs.search.paths = /odm/${LIB}/vndk-sp
-namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.search.paths += /odm/${LIB}
-namespace.rs.search.paths += /vendor/${LIB}
-
-namespace.rs.permitted.paths = /odm/${LIB}
-namespace.rs.permitted.paths += /vendor/${LIB}
-namespace.rs.permitted.paths += /system/vendor/${LIB}
-namespace.rs.permitted.paths += /data
-
-namespace.rs.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
-namespace.rs.asan.search.paths += /odm/${LIB}
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.search.paths += /vendor/${LIB}
-
-namespace.rs.asan.permitted.paths = /data/asan/odm/${LIB}
-namespace.rs.asan.permitted.paths += /odm/${LIB}
-namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.permitted.paths += /vendor/${LIB}
-namespace.rs.asan.permitted.paths += /data
-
-namespace.rs.links = default,neuralnetworks
-
-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.
-namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.rs.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is exclusively for vndk-sp libs.
-###############################################################################
-namespace.vndk.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.vndk.visible = true
-
-namespace.vndk.search.paths = /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.permitted.paths = /odm/${LIB}/hw
-namespace.vndk.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /vendor/${LIB}/egl
-namespace.vndk.permitted.paths += /system/vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /system/vendor/${LIB}/egl
-# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
-namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.asan.permitted.paths = /data/asan/odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /vendor/${LIB}/egl
-
-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 "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,runtime,neuralnetworks
-
-# 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.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-
-# Allow VNDK-SP extensions to use vendor libraries
-namespace.vndk.link.sphal.allow_all_shared_libs = true
-
-# LLNDK library moved into apex
-namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
-###############################################################################
-# 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
-# the default namespace. 'system' namespace will be added to give limited
-# (LL-NDK only) access.
-###############################################################################
-[vendor]
-additional.namespaces = runtime,system,neuralnetworks,vndk%VNDK_IN_SYSTEM_NS%
-
-###############################################################################
-# "default" namespace
-#
-# This is the default linker namespace for a vendor process (a process started
-# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
-# are loaded directly into this namespace. However, other libs under the system
-# partition (VNDK and LLNDK libraries) are not loaded here but from the
-# separate namespace 'system'. The delegation to the system namespace is done
-# via the 'namespace.default.link.system.shared_libs' property below.
-#
-# '#VNDK27#' TAG is only for building ld.config.27.txt for backward
-# compatibility. (TODO:b/123390078) Move them to a separate file.
-###############################################################################
-namespace.default.isolated = true
-namespace.default.visible = true
-
-namespace.default.search.paths = /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.permitted.paths = /odm
-namespace.default.permitted.paths += /vendor
-namespace.default.permitted.paths += /system/vendor
-#VNDK27#namespace.default.search.paths += /vendor/${LIB}/hw
-#VNDK27#namespace.default.search.paths += /vendor/${LIB}/egl
-
-namespace.default.asan.search.paths = /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths += /vendor/${LIB}
-#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/hw
-#VNDK27#namespace.default.asan.search.paths += /vendor/${LIB}/hw
-#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/egl
-#VNDK27#namespace.default.asan.search.paths += /vendor/${LIB}/egl
-
-namespace.default.asan.permitted.paths = /data/asan/odm
-namespace.default.asan.permitted.paths += /odm
-namespace.default.asan.permitted.paths += /data/asan/vendor
-namespace.default.asan.permitted.paths += /vendor
-
-namespace.default.links = system,vndk%VNDK_IN_SYSTEM_NS%,runtime,neuralnetworks
-namespace.default.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.default.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
-namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
-
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = system
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.system.allow_all_shared_libs = true
-
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is where VNDK and VNDK-SP libraries are loaded for
-# a vendor process.
-###############################################################################
-namespace.vndk.isolated = false
-
-namespace.vndk.search.paths = /odm/${LIB}/vndk
-namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-# 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. The links here should be identical to that of the
-# 'vndk_in_system' namespace, except for the link between 'vndk' and
-# 'vndk_in_system'.
-namespace.vndk.links = system,default%VNDK_IN_SYSTEM_NS%,runtime,neuralnetworks
-
-namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.default.allow_all_shared_libs = true
-
-namespace.vndk.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "system" namespace
-#
-# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
-# a vendor process.
-###############################################################################
-namespace.system.isolated = false
-
-namespace.system.search.paths = /system/${LIB}
-namespace.system.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.system.search.paths += /%PRODUCT%/${LIB}
-
-namespace.system.asan.search.paths = /data/asan/system/${LIB}
-namespace.system.asan.search.paths += /system/${LIB}
-namespace.system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.system.asan.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.system.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.system.asan.search.paths += /%PRODUCT%/${LIB}
-
-namespace.system.links = runtime
-namespace.system.link.runtime.shared_libs = libdexfile_external.so
-namespace.system.link.runtime.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.system.link.runtime.shared_libs += libicui18n.so
-namespace.system.link.runtime.shared_libs += libicuuc.so
-namespace.system.link.runtime.shared_libs += libnativebridge.so
-namespace.system.link.runtime.shared_libs += libnativehelper.so
-namespace.system.link.runtime.shared_libs += libnativeloader.so
-# Workaround for b/124772622
-namespace.system.link.runtime.shared_libs += libandroidicu.so
-namespace.system.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# "vndk_in_system" namespace
-#
-# This namespace is where no-vendor-variant VNDK libraries are loaded for a
-# vendor process. Note that we do not simply export these libraries from
-# "system" namespace, because in some case both the core variant and the
-# vendor variant of a VNDK library may be loaded. In such case, we do not
-# want to eliminate double-loading because doing so means the global states
-# of the library would be shared.
-#
-# Only the no-vendor-variant VNDK libraries are whitelisted in this namespace.
-# This is to ensure that we do not load libraries needed by no-vendor-variant
-# VNDK libraries into vndk_in_system namespace.
-###############################################################################
-namespace.vndk_in_system.isolated = true
-namespace.vndk_in_system.visible = true
-
-# The search paths here should be kept the same as that of the 'system'
-# namespace.
-namespace.vndk_in_system.search.paths = /system/${LIB}
-namespace.vndk_in_system.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.vndk_in_system.search.paths += /%PRODUCT%/${LIB}
-
-namespace.vndk_in_system.asan.search.paths = /data/asan/system/${LIB}
-namespace.vndk_in_system.asan.search.paths += /system/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.vndk_in_system.asan.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.vndk_in_system.asan.search.paths += /%PRODUCT%/${LIB}
-
-namespace.vndk_in_system.whitelisted = %VNDK_USING_CORE_VARIANT_LIBRARIES%
-
-# The links here should be identical to that of the 'vndk' namespace, with the
-# following exception:
-# 1. 'vndk_in_system' needs to be freely linked back to 'vndk'.
-# 2. 'vndk_in_system' does not need to link to 'default', as any library that
-# requires anything vendor would not be a vndk_in_system library.
-namespace.vndk_in_system.links = vndk,system,runtime,neuralnetworks
-namespace.vndk_in_system.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk_in_system.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.vndk_in_system.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk_in_system.link.vndk.allow_all_shared_libs = true
-namespace.vndk_in_system.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = system
-namespace.neuralnetworks.link.system.shared_libs = libc.so
-namespace.neuralnetworks.link.system.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.system.shared_libs += libdl.so
-namespace.neuralnetworks.link.system.shared_libs += liblog.so
-namespace.neuralnetworks.link.system.shared_libs += libm.so
-namespace.neuralnetworks.link.system.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.system.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.system.shared_libs += libsync.so
-namespace.neuralnetworks.link.system.shared_libs += libvndksupport.so
-
-###############################################################################
-# Namespace config for native tests that need access to both system and vendor
-# libraries. This replicates the default linker config (done by
-# init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
-# includes the requisite namespace setup for APEXes.
-###############################################################################
-[unrestricted]
-additional.namespaces = runtime,media,conscrypt,resolv,neuralnetworks
-
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.default.visible = true
-
-namespace.default.search.paths = /system/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.asan.search.paths = /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths += /vendor/${LIB}
-
-# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-namespace.default.links = runtime,resolv,neuralnetworks
-namespace.default.link.runtime.shared_libs = libandroidicu.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.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
-
-# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.runtime.shared_libs += libpac.so
-namespace.default.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.default.link.resolv.shared_libs = libnetd_resolv.so
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.runtime.visible = true
-
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "media" APEX namespace
-#
-# This namespace is for libraries within the media APEX.
-###############################################################################
-namespace.media.isolated = true
-namespace.media.visible = true
-
-namespace.media.search.paths = /apex/com.android.media/${LIB}
-namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
-
-namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
-namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors
-
-namespace.media.links = default,neuralnetworks
-namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libbinder_ndk.so
-namespace.media.link.default.shared_libs += libmediametrics.so
-namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-
-###############################################################################
-# "conscrypt" APEX namespace
-#
-# This namespace is for libraries within the conscrypt APEX.
-# Keep in sync with the "conscrypt" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.conscrypt.isolated = true
-namespace.conscrypt.visible = true
-
-namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
-namespace.conscrypt.link.default.shared_libs = libc.so
-namespace.conscrypt.link.default.shared_libs += libm.so
-namespace.conscrypt.link.default.shared_libs += libdl.so
-namespace.conscrypt.link.default.shared_libs += liblog.so
-
-###############################################################################
-# "resolv" APEX namespace
-#
-# This namespace is for libraries within the resolv APEX.
-###############################################################################
-namespace.resolv.isolated = true
-namespace.resolv.visible = true
-
-namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.links = default
-namespace.resolv.link.default.shared_libs = libc.so
-namespace.resolv.link.default.shared_libs += libm.so
-namespace.resolv.link.default.shared_libs += libdl.so
-namespace.resolv.link.default.shared_libs += libbinder_ndk.so
-namespace.resolv.link.default.shared_libs += liblog.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
-###############################################################################
-# Namespace config for binaries under /postinstall.
-# Only default namespace is 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.
-###############################################################################
-[postinstall]
-namespace.default.isolated = false
-namespace.default.search.paths = /system/${LIB}
-namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
+# This file is no longer in use.
+# Please update linker configuration generator instead.
+# You can find the code from /system/linkerconfig
\ No newline at end of file
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index b9b95a6..9c9f4a9 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -35,7 +35,7 @@
dir.system = /data
[system]
-additional.namespaces = runtime,conscrypt,media,neuralnetworks,resolv,sphal,vndk,rs
+additional.namespaces = art,conscrypt,media,neuralnetworks,resolv,sphal,vndk,rs
###############################################################################
# "default" namespace
@@ -68,23 +68,23 @@
# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
# If a shared library or an executable requests a shared library that
# cannot be loaded into the default namespace, the dynamic linker tries
-# to load the shared library from the runtime namespace. And then, if the
-# shared library cannot be loaded from the runtime namespace either, the
+# to load the shared library from the art namespace. And then, if the
+# shared library cannot be loaded from the art namespace either, the
# dynamic linker tries to load the shared library from the resolv namespace.
# Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = runtime,resolv,neuralnetworks
-namespace.default.link.runtime.shared_libs = libandroidicu.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
+namespace.default.links = art,resolv,neuralnetworks
+namespace.default.link.art.shared_libs = libandroidicu.so
+namespace.default.link.art.shared_libs += libdexfile_external.so
+namespace.default.link.art.shared_libs += libdexfiled_external.so
# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.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
+namespace.default.link.art.shared_libs += libicui18n.so
+namespace.default.link.art.shared_libs += libicuuc.so
+namespace.default.link.art.shared_libs += libnativebridge.so
+namespace.default.link.art.shared_libs += libnativehelper.so
+namespace.default.link.art.shared_libs += libnativeloader.so
# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.runtime.shared_libs += libpac.so
+namespace.default.link.art.shared_libs += libpac.so
# When libnetd_resolv.so can't be found in the default namespace, search for it
# in the resolv namespace. Don't allow any other libraries from the resolv namespace
@@ -95,25 +95,25 @@
namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
###############################################################################
-# "runtime" APEX namespace
+# "art" APEX namespace
#
-# This namespace pulls in externally accessible libs from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
+# This namespace pulls in externally accessible libs from the ART APEX.
+# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
+namespace.art.isolated = true
# Visible to allow links to be created at runtime, e.g. through
# android_link_namespaces in libnativeloader.
-namespace.runtime.visible = true
+namespace.art.visible = true
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
+namespace.art.search.paths = /apex/com.android.art/${LIB}
+namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
+namespace.art.links = default,neuralnetworks
# Need allow_all_shared_libs because libart.so can dlopen oat files in
# /system/framework and /data.
# TODO(b/130340935): Use a dynamically created linker namespace similar to
# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
+namespace.art.link.default.allow_all_shared_libs = true
+namespace.art.link.neuralnetworks.shared_libs = libneuralnetworks.so
###############################################################################
# "media" APEX namespace
@@ -148,12 +148,13 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
+namespace.conscrypt.links = art,default
+namespace.conscrypt.link.art.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
namespace.conscrypt.link.default.shared_libs += liblog.so
+namespace.conscrypt.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# "resolv" APEX namespace
@@ -173,6 +174,7 @@
namespace.resolv.link.default.shared_libs += libbinder_ndk.so
namespace.resolv.link.default.shared_libs += liblog.so
namespace.resolv.link.default.shared_libs += libvndksupport.so
+namespace.resolv.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# "sphal" namespace
@@ -347,7 +349,7 @@
namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
namespace.neuralnetworks.link.default.shared_libs += libsync.so
namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
+namespace.neuralnetworks.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
@@ -356,7 +358,7 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-additional.namespaces = runtime,neuralnetworks
+additional.namespaces = art,neuralnetworks
namespace.default.isolated = false
@@ -398,36 +400,35 @@
namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
namespace.default.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
-namespace.default.links = runtime,neuralnetworks
-namespace.default.link.runtime.shared_libs = libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
+namespace.default.links = art,neuralnetworks
+namespace.default.link.art.shared_libs = libdexfile_external.so
+namespace.default.link.art.shared_libs += libdexfiled_external.so
# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.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
+namespace.default.link.art.shared_libs += libicui18n.so
+namespace.default.link.art.shared_libs += libicuuc.so
+namespace.default.link.art.shared_libs += libnativebridge.so
+namespace.default.link.art.shared_libs += libnativehelper.so
+namespace.default.link.art.shared_libs += libnativeloader.so
# Workaround for b/124772622
-namespace.default.link.runtime.shared_libs += libandroidicu.so
+namespace.default.link.art.shared_libs += libandroidicu.so
# LLNDK library moved into apex
namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
###############################################################################
-# "runtime" APEX namespace
+# "art" APEX namespace
#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
+# This namespace exposes externally accessible libraries from the ART APEX.
+# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
+namespace.art.isolated = true
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
+namespace.art.search.paths = /apex/com.android.art/${LIB}
+namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
+namespace.art.links = default
# TODO(b/130340935): Use a dynamically created linker namespace similar to
# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
+namespace.art.link.default.allow_all_shared_libs = true
###############################################################################
# "neuralnetworks" APEX namespace
@@ -449,7 +450,7 @@
namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
namespace.neuralnetworks.link.default.shared_libs += libsync.so
namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
+namespace.neuralnetworks.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# Namespace config for native tests that need access to both system and vendor
@@ -458,7 +459,7 @@
# includes the requisite namespace setup for APEXes.
###############################################################################
[unrestricted]
-additional.namespaces = runtime,media,conscrypt,resolv,neuralnetworks
+additional.namespaces = art,media,conscrypt,resolv,neuralnetworks
# Visible to allow links to be created at runtime, e.g. through
# android_link_namespaces in libnativeloader.
@@ -476,20 +477,19 @@
namespace.default.asan.search.paths += /vendor/${LIB}
# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-namespace.default.links = runtime,resolv,neuralnetworks
-namespace.default.link.runtime.shared_libs = libandroidicu.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
+namespace.default.links = art,resolv,neuralnetworks
+namespace.default.link.art.shared_libs = libandroidicu.so
+namespace.default.link.art.shared_libs += libdexfile_external.so
+namespace.default.link.art.shared_libs += libdexfiled_external.so
# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.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
+namespace.default.link.art.shared_libs += libicui18n.so
+namespace.default.link.art.shared_libs += libicuuc.so
+namespace.default.link.art.shared_libs += libnativebridge.so
+namespace.default.link.art.shared_libs += libnativehelper.so
+namespace.default.link.art.shared_libs += libnativeloader.so
# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.runtime.shared_libs += libpac.so
-namespace.default.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.default.link.art.shared_libs += libpac.so
namespace.default.link.resolv.shared_libs = libnetd_resolv.so
@@ -497,22 +497,22 @@
namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
###############################################################################
-# "runtime" APEX namespace
+# "art" APEX namespace
#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
+# This namespace exposes externally accessible libraries from the ART APEX.
+# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
+namespace.art.isolated = true
# Visible to allow links to be created at runtime, e.g. through
# android_link_namespaces in libnativeloader.
-namespace.runtime.visible = true
+namespace.art.visible = true
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
+namespace.art.search.paths = /apex/com.android.art/${LIB}
+namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
+namespace.art.links = default
# TODO(b/130340935): Use a dynamically created linker namespace similar to
# classloader-namespace for oat files, and tighten this up.
+namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
# "media" APEX namespace
@@ -547,11 +547,12 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
+namespace.conscrypt.links = art,default
+namespace.conscrypt.link.art.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
+namespace.conscrypt.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# "resolv" APEX namespace
@@ -569,6 +570,7 @@
namespace.resolv.link.default.shared_libs += libm.so
namespace.resolv.link.default.shared_libs += libdl.so
namespace.resolv.link.default.shared_libs += libbinder_ndk.so
+namespace.resolv.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# "neuralnetworks" APEX namespace
@@ -590,7 +592,7 @@
namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
namespace.neuralnetworks.link.default.shared_libs += libsync.so
namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
+namespace.neuralnetworks.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# Namespace config for binaries under /postinstall.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index bad0642..4f9b93e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -918,6 +918,14 @@
on init && property:ro.debuggable=1
start console
-service flash_recovery /system/bin/install-recovery.sh
- class main
- oneshot
+on userspace-reboot:
+ # TODO(b/135984674): reset all necessary properties here.
+ setprop sys.init.userspace_reboot_in_progress 1
+
+on userspace-reboot-resume:
+ # TODO(b/135984674): remount userdata and reset checkpointing
+ trigger nonencrypted
+ trigger post-fs-data
+ trigger zygote-start
+ trigger early-boot
+ trigger boot
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index c4b8e4e..44f7b65 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -38,8 +38,8 @@
llndk_libraries_file := $(library_lists_dir)/llndk.libraries.$(vndk_version).txt
vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt
-vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.txt
-vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.txt
+vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.$(vndk_version).txt
+vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.$(vndk_version).txt
llndk_moved_to_apex_libraries_file := $(library_lists_dir)/llndkinapex.libraries.txt
ifeq ($(my_vndk_use_core_variant),true)
vndk_using_core_variant_libraries_file := $(library_lists_dir)/vndk_using_core_variant.libraries.$(vndk_version).txt