Merge "[vts-core] Add vts_core_liblp_test to vts-core"
diff --git a/adb/Android.bp b/adb/Android.bp
index 57872b0..9ef82bf 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -629,6 +629,7 @@
"libselinux",
],
test_suites: ["device-tests"],
+ require_root: true,
}
python_test_host {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index dd24aac..d08a59f 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -311,6 +311,7 @@
{"shutdown,userrequested,recovery", 182},
{"reboot,unknown[0-9]*", 183},
{"reboot,longkey,.*", 184},
+ {"reboot,boringssl-self-check-failed", 185},
};
// Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index c86a018..c9a193c 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -176,7 +176,7 @@
if (crasher_pid != -1) {
kill(crasher_pid, SIGKILL);
int status;
- waitpid(crasher_pid, &status, WUNTRACED);
+ TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
}
android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
@@ -195,8 +195,7 @@
void CrasherTest::FinishIntercept(int* result) {
InterceptResponse response;
- // Timeout for tombstoned intercept is 10 seconds.
- ssize_t rc = TIMEOUT(20, read(intercept_fd.get(), &response, sizeof(response)));
+ ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
if (rc == -1) {
FAIL() << "failed to read response from tombstoned: " << strerror(errno);
} else if (rc == 0) {
@@ -233,7 +232,7 @@
FAIL() << "crasher pipe uninitialized";
}
- ssize_t rc = write(crasher_pipe.get(), "\n", 1);
+ ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
if (rc == -1) {
FAIL() << "failed to write to crasher pipe: " << strerror(errno);
} else if (rc == 0) {
@@ -243,7 +242,7 @@
void CrasherTest::AssertDeath(int signo) {
int status;
- pid_t pid = TIMEOUT(10, waitpid(crasher_pid, &status, 0));
+ pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
if (pid != crasher_pid) {
printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
strerror(errno));
@@ -441,7 +440,7 @@
FinishCrasher();
int status;
- ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, WUNTRACED));
+ ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
ASSERT_TRUE(WIFSTOPPED(status));
ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
@@ -611,7 +610,7 @@
PLOG(FATAL) << "tmpfile failed";
}
- unique_fd tmp_fd(dup(fileno(tmp_file)));
+ unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
PLOG(FATAL) << "failed to write policy to tmpfile";
}
@@ -824,7 +823,7 @@
FinishCrasher();
int status;
- ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
+ ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
ASSERT_TRUE(WIFSTOPPED(status));
ASSERT_EQ(SIGABRT, WSTOPSIG(status));
@@ -839,7 +838,7 @@
regex += R"( \(.+debuggerd_test)";
ASSERT_MATCH(result, regex.c_str());
- ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
+ ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
ASSERT_TRUE(WIFSTOPPED(status));
ASSERT_EQ(SIGABRT, WSTOPSIG(status));
@@ -853,7 +852,7 @@
StartProcess([]() {
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
- unique_fd fd(open("/dev/null", O_RDONLY | O_CLOEXEC));
+ unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
abort();
}
@@ -888,13 +887,13 @@
raise(DEBUGGER_SIGNAL);
errno = 0;
- rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
+ rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
if (rc != -1 || errno != ECHILD) {
errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
}
_exit(0);
} else {
- rc = waitpid(forkpid, &status, 0);
+ rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
ASSERT_EQ(forkpid, rc);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(0, WEXITSTATUS(status));
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 4dbacd7..e50f7c3 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -36,6 +36,7 @@
#include "fs_mgr_priv.h"
+using android::base::EndsWith;
using android::base::ParseByteCount;
using android::base::ParseInt;
using android::base::ReadFileToString;
@@ -598,7 +599,7 @@
return boot_devices;
}
-FstabEntry BuildGsiUserdataFstabEntry() {
+FstabEntry BuildDsuUserdataFstabEntry() {
constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV;
FstabEntry userdata = {
@@ -627,7 +628,12 @@
return false;
}
-void TransformFstabForGsi(Fstab* fstab) {
+} // namespace
+
+void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
+ static constexpr char kGsiKeys[] =
+ "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey";
+ // Convert userdata
// Inherit fstab properties for userdata.
FstabEntry userdata;
if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) {
@@ -639,19 +645,75 @@
userdata.key_dir += "/gsi";
}
} else {
- userdata = BuildGsiUserdataFstabEntry();
- }
-
- if (EraseFstabEntry(fstab, "/system")) {
- fstab->emplace_back(BuildGsiSystemFstabEntry());
+ userdata = BuildDsuUserdataFstabEntry();
}
if (EraseFstabEntry(fstab, "/data")) {
fstab->emplace_back(userdata);
}
-}
-} // namespace
+ // Convert others
+ for (auto&& partition : dsu_partitions) {
+ if (!EndsWith(partition, gsi::kDsuPostfix)) {
+ continue;
+ }
+ // userdata has been handled
+ if (StartsWith(partition, "user")) {
+ continue;
+ }
+ // dsu_partition_name = corresponding_partition_name + kDsuPostfix
+ // e.g.
+ // system_gsi for system
+ // product_gsi for product
+ // vendor_gsi for vendor
+ std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
+ std::string mount_point = "/" + lp_name;
+ std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point);
+ if (entries.empty()) {
+ FstabEntry entry = {
+ .blk_device = partition,
+ .mount_point = mount_point,
+ .fs_type = "ext4",
+ .flags = MS_RDONLY,
+ .fs_options = "barrier=1",
+ .avb_keys = kGsiKeys,
+ // .logical_partition_name is required to look up AVB Hashtree descriptors.
+ .logical_partition_name = "system"};
+ entry.fs_mgr_flags.wait = true;
+ entry.fs_mgr_flags.logical = true;
+ entry.fs_mgr_flags.first_stage_mount = true;
+ // Use the system key which may be in the vbmeta or vbmeta_system
+ // TODO: b/141284191
+ entry.vbmeta_partition = "vbmeta";
+ fstab->emplace_back(entry);
+ entry.vbmeta_partition = "vbmeta_system";
+ fstab->emplace_back(entry);
+ } else {
+ // If the corresponding partition exists, transform all its Fstab
+ // by pointing .blk_device to the DSU partition.
+ for (auto&& entry : entries) {
+ entry->blk_device = partition;
+ if (entry->avb_keys.size() > 0) {
+ entry->avb_keys += ":";
+ }
+ // If the DSU is signed by OEM, the original Fstab already has the information
+ // required by avb, otherwise the DSU is GSI and will need the avb_keys as listed
+ // below.
+ entry->avb_keys += kGsiKeys;
+ }
+ // Make sure the ext4 is included to support GSI.
+ auto partition_ext4 =
+ std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) {
+ return entry.mount_point == mount_point && entry.fs_type == "ext4";
+ });
+ if (partition_ext4 == fstab->end()) {
+ auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
+ new_entry.fs_type = "ext4";
+ fstab->emplace_back(new_entry);
+ }
+ }
+ }
+}
bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
@@ -667,7 +729,9 @@
return false;
}
if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
- TransformFstabForGsi(fstab);
+ std::string lp_names;
+ ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
+ TransformFstabForDsu(fstab, Split(lp_names, ","));
}
SkipMountingPartitions(fstab);
@@ -779,6 +843,21 @@
return nullptr;
}
+std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) {
+ std::vector<FstabEntry*> entries;
+ if (fstab == nullptr) {
+ return entries;
+ }
+
+ for (auto& entry : *fstab) {
+ if (entry.mount_point == path) {
+ entries.emplace_back(&entry);
+ }
+ }
+
+ return entries;
+}
+
std::set<std::string> GetBootDevices() {
// First check the kernel commandline, then try the device tree otherwise
std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
@@ -798,23 +877,6 @@
return ExtraBootDevices(fstab);
}
-FstabEntry BuildGsiSystemFstabEntry() {
- // .logical_partition_name is required to look up AVB Hashtree descriptors.
- FstabEntry system = {
- .blk_device = "system_gsi",
- .mount_point = "/system",
- .fs_type = "ext4",
- .flags = MS_RDONLY,
- .fs_options = "barrier=1",
- // could add more keys separated by ':'.
- .avb_keys = "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey",
- .logical_partition_name = "system"};
- system.fs_mgr_flags.wait = true;
- system.fs_mgr_flags.logical = true;
- system.fs_mgr_flags.first_stage_mount = true;
- return system;
-}
-
std::string GetVerityDeviceName(const FstabEntry& entry) {
std::string base_device;
if (entry.mount_point == "/") {
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index c7193ab..d999ae1 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -101,9 +101,18 @@
bool SkipMountingPartitions(Fstab* fstab);
FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
+// The Fstab can contain multiple entries for the same mount point with different configurations.
+std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path);
-// Helper method to build a GSI fstab entry for mounting /system.
-FstabEntry BuildGsiSystemFstabEntry();
+// This method builds DSU fstab entries and transfer the fstab.
+//
+// fstab points to the unmodified fstab.
+//
+// dsu_partitions contains partition names, e.g.
+// dsu_partitions[0] = "system_gsi"
+// dsu_partitions[1] = "userdata_gsi"
+// dsu_partitions[2] = ...
+void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions);
std::set<std::string> GetBootDevices();
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 4cdea71..449a170 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -44,9 +44,24 @@
},
}
-cc_test {
- name: "libdm_test",
- defaults: ["fs_mgr_defaults"],
+filegroup {
+ name: "libdm_test_srcs",
+ srcs: [
+ "dm_test.cpp",
+ "loop_control_test.cpp",
+ "test_util.cpp",
+ ],
+}
+
+cc_defaults {
+ name: "libdm_defaults",
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
static_libs: [
"libdm",
"libbase",
@@ -54,9 +69,10 @@
"libfs_mgr",
"liblog",
],
- srcs: [
- "dm_test.cpp",
- "loop_control_test.cpp",
- "test_util.cpp",
- ]
+ srcs: [":libdm_test_srcs"],
+}
+
+cc_test {
+ name: "libdm_test",
+ defaults: ["libdm_defaults"],
}
diff --git a/fs_mgr/libdm/vts_core/Android.bp b/fs_mgr/libdm/vts_core/Android.bp
new file mode 100644
index 0000000..2eceb28
--- /dev/null
+++ b/fs_mgr/libdm/vts_core/Android.bp
@@ -0,0 +1,23 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "vts_libdm_test",
+ defaults: ["libdm_defaults"],
+ test_suites: ["vts-core"],
+ require_root: true,
+ test_min_api_level: 29,
+}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index bb941dd..a012099 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -114,3 +114,29 @@
"libstorage_literals_headers",
],
}
+
+cc_binary {
+ name: "snapshotctl",
+ srcs: [
+ "snapshotctl.cpp",
+ ],
+ static_libs: [
+ "libdm",
+ "libext2_uuid",
+ "libfiemap_binder",
+ "libfstab",
+ "libsnapshot",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libext4_utils",
+ "libfs_mgr",
+ "libutils",
+ "liblog",
+ "liblp",
+ ],
+ init_rc: [
+ "snapshotctl.rc",
+ ],
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index aeeb4aa..0dd275a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -19,6 +19,7 @@
#include <chrono>
#include <map>
#include <memory>
+#include <ostream>
#include <string>
#include <string_view>
#include <vector>
@@ -84,6 +85,7 @@
// operation via fastboot. This state can only be returned by WaitForMerge.
Cancelled
};
+std::ostream& operator<<(std::ostream& os, UpdateState state);
class SnapshotManager final {
using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
@@ -125,8 +127,9 @@
// will fail if GetUpdateState() != None.
bool BeginUpdate();
- // Cancel an update; any snapshots will be deleted. This will fail if the
- // state != Initiated or None.
+ // Cancel an update; any snapshots will be deleted. This is allowed if the
+ // state == Initiated, None, or Unverified (before rebooting to the new
+ // slot).
bool CancelUpdate();
// Mark snapshot writes as having completed. After this, new snapshots cannot
@@ -189,6 +192,9 @@
// call to CreateLogicalPartitions when snapshots are present.
bool CreateLogicalAndSnapshotPartitions(const std::string& super_device);
+ // Dump debug information.
+ bool Dump(std::ostream& os);
+
private:
FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
FRIEND_TEST(SnapshotTest, CreateSnapshot);
@@ -393,6 +399,13 @@
// The reverse of MapPartitionWithSnapshot.
bool UnmapPartitionWithSnapshot(LockedFile* lock, const std::string& target_partition_name);
+ // If there isn't a previous update, return true. |needs_merge| is set to false.
+ // If there is a previous update but the device has not boot into it, tries to cancel the
+ // update and delete any snapshots. Return true if successful. |needs_merge| is set to false.
+ // If there is a previous update and the device has boot into it, do nothing and return true.
+ // |needs_merge| is set to true.
+ bool TryCancelUpdate(bool* needs_merge);
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index b5b3af3..9d0272b 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -131,6 +131,16 @@
}
bool SnapshotManager::BeginUpdate() {
+ bool needs_merge = false;
+ if (!TryCancelUpdate(&needs_merge)) {
+ return false;
+ }
+ if (needs_merge) {
+ LOG(INFO) << "Wait for merge (if any) before beginning a new update.";
+ auto state = ProcessUpdateState();
+ LOG(INFO) << "Merged with state = " << state;
+ }
+
auto file = LockExclusive();
if (!file) return false;
@@ -143,6 +153,19 @@
}
bool SnapshotManager::CancelUpdate() {
+ bool needs_merge = false;
+ if (!TryCancelUpdate(&needs_merge)) {
+ return false;
+ }
+ if (needs_merge) {
+ LOG(ERROR) << "Cannot cancel update after it has completed or started merging";
+ }
+ return !needs_merge;
+}
+
+bool SnapshotManager::TryCancelUpdate(bool* needs_merge) {
+ *needs_merge = false;
+
auto file = LockExclusive();
if (!file) return false;
@@ -167,8 +190,8 @@
return RemoveAllUpdateState(file.get());
}
}
- LOG(ERROR) << "Cannot cancel update after it has completed or started merging";
- return false;
+ *needs_merge = true;
+ return true;
}
bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
@@ -1459,7 +1482,7 @@
PLOG(ERROR) << "Open failed: " << file;
return nullptr;
}
- if (flock(fd, lock_flags) < 0) {
+ if (lock_flags != 0 && flock(fd, lock_flags) < 0) {
PLOG(ERROR) << "Acquire flock failed: " << file;
return nullptr;
}
@@ -1526,34 +1549,33 @@
}
}
-bool SnapshotManager::WriteUpdateState(LockedFile* file, UpdateState state) {
- std::string contents;
+std::ostream& operator<<(std::ostream& os, UpdateState state) {
switch (state) {
case UpdateState::None:
- contents = "none";
- break;
+ return os << "none";
case UpdateState::Initiated:
- contents = "initiated";
- break;
+ return os << "initiated";
case UpdateState::Unverified:
- contents = "unverified";
- break;
+ return os << "unverified";
case UpdateState::Merging:
- contents = "merging";
- break;
+ return os << "merging";
case UpdateState::MergeCompleted:
- contents = "merge-completed";
- break;
+ return os << "merge-completed";
case UpdateState::MergeNeedsReboot:
- contents = "merge-needs-reboot";
- break;
+ return os << "merge-needs-reboot";
case UpdateState::MergeFailed:
- contents = "merge-failed";
- break;
+ return os << "merge-failed";
default:
LOG(ERROR) << "Unknown update state";
- return false;
+ return os;
}
+}
+
+bool SnapshotManager::WriteUpdateState(LockedFile* file, UpdateState state) {
+ std::stringstream ss;
+ ss << state;
+ std::string contents = ss.str();
+ if (contents.empty()) return false;
if (!Truncate(file)) return false;
if (!android::base::WriteStringToFd(contents, file->fd())) {
@@ -1940,5 +1962,47 @@
return UnmapPartitionWithSnapshot(lock.get(), target_partition_name);
}
+bool SnapshotManager::Dump(std::ostream& os) {
+ // Don't actually lock. Dump() is for debugging purposes only, so it is okay
+ // if it is racy.
+ auto file = OpenStateFile(O_RDONLY, 0);
+ if (!file) return false;
+
+ std::stringstream ss;
+
+ ss << "Update state: " << ReadUpdateState(file.get()) << std::endl;
+
+ auto boot_file = GetSnapshotBootIndicatorPath();
+ std::string boot_indicator;
+ if (android::base::ReadFileToString(boot_file, &boot_indicator)) {
+ ss << "Boot indicator: old slot = " << boot_indicator << std::endl;
+ }
+
+ bool ok = true;
+ std::vector<std::string> snapshots;
+ if (!ListSnapshots(file.get(), &snapshots)) {
+ LOG(ERROR) << "Could not list snapshots";
+ snapshots.clear();
+ ok = false;
+ }
+ for (const auto& name : snapshots) {
+ ss << "Snapshot: " << name << std::endl;
+ SnapshotStatus status;
+ if (!ReadSnapshotStatus(file.get(), name, &status)) {
+ 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;
+ }
+ os << ss.rdbuf();
+ return ok;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 36982a9..bc764fd 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -761,8 +761,7 @@
// Also test UnmapUpdateSnapshot unmaps everything.
// Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
- // OTA client calls CancelUpdate then BeginUpdate before doing anything.
- ASSERT_TRUE(sm->CancelUpdate());
+ // OTA client calls BeginUpdate before doing anything.
ASSERT_TRUE(sm->BeginUpdate());
// OTA client blindly unmaps all partitions that are possibly mapped.
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
new file mode 100644
index 0000000..d65320c
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -0,0 +1,115 @@
+//
+// 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.
+//
+
+#include <sysexits.h>
+
+#include <chrono>
+#include <iostream>
+#include <map>
+
+#include <android-base/logging.h>
+#include <libsnapshot/snapshot.h>
+
+using namespace std::string_literals;
+
+int Usage() {
+ std::cerr << "snapshotctl: Control snapshots.\n"
+ "Usage: snapshotctl [action] [flags]\n"
+ "Actions:\n"
+ " dump\n"
+ " Print snapshot states.\n"
+ " merge [--logcat]\n"
+ " Initialize merge and wait for it to be completed.\n"
+ " If --logcat is specified, log to logcat. Otherwise, log to stdout.\n";
+ return EX_USAGE;
+}
+
+namespace android {
+namespace snapshot {
+
+bool DumpCmdHandler(int /*argc*/, char** argv) {
+ android::base::InitLogging(argv, &android::base::StderrLogger);
+ return SnapshotManager::New()->Dump(std::cout);
+}
+
+bool MergeCmdHandler(int argc, char** argv) {
+ auto begin = std::chrono::steady_clock::now();
+
+ bool log_to_logcat = false;
+ for (int i = 2; i < argc; ++i) {
+ if (argv[i] == "--logcat"s) {
+ log_to_logcat = true;
+ }
+ }
+ if (log_to_logcat) {
+ android::base::InitLogging(argv);
+ } else {
+ android::base::InitLogging(argv, &android::base::StdioLogger);
+ }
+
+ auto sm = SnapshotManager::New();
+
+ auto state = sm->GetUpdateState();
+ if (state == UpdateState::None) {
+ LOG(INFO) << "Can't find any snapshot to merge.";
+ return true;
+ }
+ if (state == UpdateState::Unverified) {
+ if (!sm->InitiateMerge()) {
+ LOG(ERROR) << "Failed to initiate merge.";
+ return false;
+ }
+ }
+
+ // All other states can be handled by ProcessUpdateState.
+ LOG(INFO) << "Waiting for any merge to complete. This can take up to 1 minute.";
+ state = SnapshotManager::New()->ProcessUpdateState();
+
+ if (state == UpdateState::MergeCompleted) {
+ auto end = std::chrono::steady_clock::now();
+ auto passed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
+ LOG(INFO) << "Snapshot merged in " << passed << " ms.";
+ return true;
+ }
+
+ LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\".";
+ return false;
+}
+
+static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = {
+ // clang-format off
+ {"dump", DumpCmdHandler},
+ {"merge", MergeCmdHandler},
+ // clang-format on
+};
+
+} // namespace snapshot
+} // namespace android
+
+int main(int argc, char** argv) {
+ using namespace android::snapshot;
+ if (argc < 2) {
+ return Usage();
+ }
+
+ for (const auto& cmd : kCmdMap) {
+ if (cmd.first == argv[1]) {
+ return cmd.second(argc, argv) ? EX_OK : EX_SOFTWARE;
+ }
+ }
+
+ return Usage();
+}
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
new file mode 100644
index 0000000..29707f1
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshotctl.rc
@@ -0,0 +1,2 @@
+on property:sys.boot_completed=1
+ exec - root root -- /system/bin/snapshotctl merge --logcat
diff --git a/fs_mgr/libvbmeta/Android.bp b/fs_mgr/libvbmeta/Android.bp
new file mode 100644
index 0000000..937e0f3
--- /dev/null
+++ b/fs_mgr/libvbmeta/Android.bp
@@ -0,0 +1,52 @@
+//
+// 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.
+//
+
+libvbmeta_lib_deps = [
+ "libbase",
+ "libcrypto",
+]
+
+cc_library {
+ name: "libvbmeta",
+ host_supported: true,
+ srcs: [
+ "builder.cpp",
+ "reader.cpp",
+ "utility.cpp",
+ "writer.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ ] + libvbmeta_lib_deps,
+ export_include_dirs: ["include"],
+}
+
+cc_test_host {
+ name: "libvbmeta_test",
+ static_libs: [
+ "libsparse",
+ "libvbmeta",
+ "libz",
+ ] + libvbmeta_lib_deps,
+ srcs: [
+ "builder_test.cpp",
+ "super_vbmeta_test.cpp",
+ ],
+ required: [
+ "avbtool",
+ "vbmake",
+ ],
+}
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/builder.cpp b/fs_mgr/libvbmeta/builder.cpp
new file mode 100644
index 0000000..a901a4f
--- /dev/null
+++ b/fs_mgr/libvbmeta/builder.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+
+#include "builder.h"
+
+#include <android-base/file.h>
+#include <openssl/sha.h>
+
+#include "reader.h"
+#include "utility.h"
+#include "writer.h"
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+using android::base::unique_fd;
+
+namespace android {
+namespace fs_mgr {
+
+SuperVBMetaBuilder::SuperVBMetaBuilder() {}
+
+SuperVBMetaBuilder::SuperVBMetaBuilder(const int super_vbmeta_fd,
+ const std::map<std::string, std::string>& images_path)
+ : super_vbmeta_fd_(super_vbmeta_fd), images_path_(images_path) {}
+
+Result<void> SuperVBMetaBuilder::Build() {
+ for (const auto& [vbmeta_name, file_path] : images_path_) {
+ Result<std::string> content = ReadVBMetaImageFromFile(file_path);
+ if (!content) {
+ return content.error();
+ }
+
+ Result<uint8_t> vbmeta_index = AddVBMetaImage(vbmeta_name);
+ if (!vbmeta_index) {
+ return vbmeta_index.error();
+ }
+
+ Result<void> rv_export_vbmeta_image =
+ ExportVBMetaImageToFile(vbmeta_index.value(), content.value());
+ if (!rv_export_vbmeta_image) {
+ return rv_export_vbmeta_image;
+ }
+ }
+ return {};
+}
+
+Result<std::string> SuperVBMetaBuilder::ReadVBMetaImageFromFile(const std::string& file) {
+ unique_fd source_fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (source_fd < 0) {
+ return ErrnoError() << "Couldn't open vbmeta image file " << file;
+ }
+
+ Result<uint64_t> file_size = GetFileSize(source_fd);
+ if (!file_size) {
+ return file_size.error();
+ }
+
+ if (file_size.value() > VBMETA_IMAGE_MAX_SIZE) {
+ return Error() << "vbmeta image file size " << file_size.value() << " is too large";
+ }
+
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
+ if (!android::base::ReadFully(source_fd, buffer.get(), file_size.value())) {
+ return ErrnoError() << "Couldn't read vbmeta image file " << file;
+ }
+
+ return std::string(reinterpret_cast<const char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
+}
+
+Result<uint8_t> SuperVBMetaBuilder::GetEmptySlot() {
+ for (uint8_t i = 0; i < VBMETA_IMAGE_MAX_NUM; ++i) {
+ if ((table_.header.in_use & (1 << i)) == 0) return i;
+ }
+ return Error() << "There isn't empty slot in super vbmeta";
+}
+
+Result<uint8_t> SuperVBMetaBuilder::AddVBMetaImage(const std::string& vbmeta_name) {
+ auto desc = std::find_if(
+ table_.descriptors.begin(), table_.descriptors.end(),
+ [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });
+
+ uint8_t slot_number = 0;
+ if (desc != table_.descriptors.end()) {
+ slot_number = desc->vbmeta_index;
+ } else {
+ Result<uint8_t> new_slot = GetEmptySlot();
+ if (!new_slot) {
+ return new_slot;
+ }
+ slot_number = new_slot.value();
+
+ // insert new descriptor into table
+ InternalVBMetaDescriptor new_desc;
+ new_desc.vbmeta_index = slot_number;
+ new_desc.vbmeta_name_length = vbmeta_name.length();
+ new_desc.vbmeta_name = vbmeta_name;
+ memset(new_desc.reserved, 0, sizeof(new_desc.reserved));
+ table_.descriptors.emplace_back(std::move(new_desc));
+
+ // mark slot as in use
+ table_.header.in_use |= (1 << slot_number);
+ }
+
+ return slot_number;
+}
+
+void SuperVBMetaBuilder::DeleteVBMetaImage(const std::string& vbmeta_name) {
+ auto desc = std::find_if(
+ table_.descriptors.begin(), table_.descriptors.end(),
+ [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });
+
+ if (desc != table_.descriptors.end()) {
+ // mark slot as not in use
+ table_.header.in_use &= ~(1 << desc->vbmeta_index);
+
+ // erase descriptor in table
+ table_.descriptors.erase(desc);
+ }
+}
+
+std::unique_ptr<VBMetaTable> SuperVBMetaBuilder::ExportVBMetaTable() {
+ // calculate descriptors size
+ uint32_t descriptors_size = 0;
+ for (const auto& desc : table_.descriptors) {
+ descriptors_size += SUPER_VBMETA_DESCRIPTOR_SIZE + desc.vbmeta_name_length * sizeof(char);
+ }
+
+ // export header
+ table_.header.magic = SUPER_VBMETA_MAGIC;
+ table_.header.major_version = SUPER_VBMETA_MAJOR_VERSION;
+ table_.header.minor_version = SUPER_VBMETA_MINOR_VERSION;
+ table_.header.header_size = SUPER_VBMETA_HEADER_SIZE;
+ table_.header.total_size = SUPER_VBMETA_HEADER_SIZE + descriptors_size;
+ memset(table_.header.checksum, 0, sizeof(table_.header.checksum));
+ table_.header.descriptors_size = descriptors_size;
+ memset(table_.header.reserved, 0, sizeof(table_.header.reserved));
+ std::string serialized_table = SerializeVBMetaTable(table_);
+ ::SHA256(reinterpret_cast<const uint8_t*>(serialized_table.c_str()), table_.header.total_size,
+ &table_.header.checksum[0]);
+
+ return std::make_unique<VBMetaTable>(table_);
+}
+
+Result<void> SuperVBMetaBuilder::ExportVBMetaTableToFile() {
+ std::unique_ptr<VBMetaTable> table = ExportVBMetaTable();
+
+ std::string serialized_table = SerializeVBMetaTable(*table);
+
+ android::base::Result<void> rv_write_primary_vbmeta_table =
+ WritePrimaryVBMetaTable(super_vbmeta_fd_, serialized_table);
+ if (!rv_write_primary_vbmeta_table) {
+ return rv_write_primary_vbmeta_table;
+ }
+
+ android::base::Result<void> rv_write_backup_vbmeta_table =
+ WriteBackupVBMetaTable(super_vbmeta_fd_, serialized_table);
+ return rv_write_backup_vbmeta_table;
+}
+
+Result<void> SuperVBMetaBuilder::ExportVBMetaImageToFile(const uint8_t vbmeta_index,
+ const std::string& vbmeta_image) {
+ Result<void> rv_write_vbmeta_image =
+ WriteVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
+ if (!rv_write_vbmeta_image) {
+ return rv_write_vbmeta_image;
+ }
+
+ Result<void> rv_validate_vbmeta_image =
+ ValidateVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
+ return rv_validate_vbmeta_image;
+}
+
+bool WriteToSuperVBMetaFile(const std::string& super_vbmeta_file,
+ const std::map<std::string, std::string>& images_path) {
+ unique_fd super_vbmeta_fd(TEMP_FAILURE_RETRY(
+ open(super_vbmeta_file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644)));
+ if (super_vbmeta_fd < 0) {
+ PERROR << "Couldn't open super vbmeta file " << super_vbmeta_file;
+ return false;
+ }
+
+ SuperVBMetaBuilder builder(super_vbmeta_fd, images_path);
+
+ Result<void> rv_build = builder.Build();
+ if (!rv_build) {
+ LERROR << rv_build.error();
+ return false;
+ }
+
+ Result<void> rv_export = builder.ExportVBMetaTableToFile();
+ if (!rv_export) {
+ LERROR << rv_export.error();
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace fs_mgr
+} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/builder.h b/fs_mgr/libvbmeta/builder.h
new file mode 100644
index 0000000..58ea36a
--- /dev/null
+++ b/fs_mgr/libvbmeta/builder.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <android-base/result.h>
+
+#include "super_vbmeta_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+class SuperVBMetaBuilder {
+ public:
+ SuperVBMetaBuilder();
+ SuperVBMetaBuilder(const int super_vbmeta_fd,
+ const std::map<std::string, std::string>& images_path);
+ android::base::Result<void> Build();
+ android::base::Result<std::string> ReadVBMetaImageFromFile(const std::string& file);
+ // It adds the vbmeta image in super_vbmeta and returns the index
+ // (which has the same meaning with vbmeta_index of VBMetaDescriptor).
+ android::base::Result<uint8_t> AddVBMetaImage(const std::string& vbmeta_name);
+ void DeleteVBMetaImage(const std::string& vbmeta_name);
+ std::unique_ptr<VBMetaTable> ExportVBMetaTable();
+ android::base::Result<void> ExportVBMetaTableToFile();
+ android::base::Result<void> ExportVBMetaImageToFile(const uint8_t vbmeta_index,
+ const std::string& vbmeta_image);
+
+ private:
+ android::base::Result<uint8_t> GetEmptySlot();
+
+ int super_vbmeta_fd_;
+ VBMetaTable table_;
+ // Maps vbmeta image name to vbmeta image file path.
+ std::map<std::string, std::string> images_path_;
+};
+
+} // namespace fs_mgr
+} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/builder_test.cpp b/fs_mgr/libvbmeta/builder_test.cpp
new file mode 100644
index 0000000..9a015fd
--- /dev/null
+++ b/fs_mgr/libvbmeta/builder_test.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "builder.h"
+#include "super_vbmeta_format.h"
+
+using android::base::Result;
+using android::fs_mgr::SuperVBMetaBuilder;
+
+TEST(BuilderTest, VBMetaTableBasic) {
+ std::unique_ptr<SuperVBMetaBuilder> builder = std::make_unique<SuperVBMetaBuilder>();
+ ASSERT_NE(builder, nullptr);
+
+ Result<uint8_t> vbmeta_index = builder->AddVBMetaImage("vbmeta" /* vbmeta_name */
+ );
+ EXPECT_TRUE(vbmeta_index);
+
+ Result<uint8_t> vbmeta_system_slot = builder->AddVBMetaImage("vbmeta_system" /* vbmeta_name */
+ );
+ EXPECT_TRUE(vbmeta_system_slot);
+
+ Result<uint8_t> vbmeta_vendor_slot = builder->AddVBMetaImage("vbmeta_vendor" /* vbmeta_name */
+ );
+ EXPECT_TRUE(vbmeta_vendor_slot);
+
+ builder->DeleteVBMetaImage("vbmeta_system" /* vbmeta_name */
+ );
+
+ Result<uint8_t> vbmeta_product_slot = builder->AddVBMetaImage("vbmeta_product" /* vbmeta_name */
+ );
+ EXPECT_TRUE(vbmeta_product_slot);
+
+ std::unique_ptr<VBMetaTable> table = builder->ExportVBMetaTable();
+ ASSERT_NE(table, nullptr);
+
+ // check for vbmeta table header
+ EXPECT_EQ(table->header.magic, SUPER_VBMETA_MAGIC);
+ EXPECT_EQ(table->header.major_version, SUPER_VBMETA_MAJOR_VERSION);
+ EXPECT_EQ(table->header.minor_version, SUPER_VBMETA_MINOR_VERSION);
+ EXPECT_EQ(table->header.header_size, SUPER_VBMETA_HEADER_SIZE);
+ EXPECT_EQ(table->header.total_size,
+ SUPER_VBMETA_HEADER_SIZE + SUPER_VBMETA_DESCRIPTOR_SIZE * 3 + 33);
+ EXPECT_EQ(table->header.descriptors_size, SUPER_VBMETA_DESCRIPTOR_SIZE * 3 + 33);
+
+ // Test for vbmeta table descriptors
+ EXPECT_EQ(table->descriptors.size(), 3);
+
+ EXPECT_EQ(table->descriptors[0].vbmeta_index, 0);
+ EXPECT_EQ(table->descriptors[0].vbmeta_name_length, 6);
+ for (int i = 0; i < sizeof(table->descriptors[0].reserved); i++)
+ EXPECT_EQ(table->descriptors[0].reserved[i], 0);
+ EXPECT_EQ(table->descriptors[0].vbmeta_name, "vbmeta");
+
+ EXPECT_EQ(table->descriptors[1].vbmeta_index, 2);
+ EXPECT_EQ(table->descriptors[1].vbmeta_name_length, 13);
+ for (int i = 0; i < sizeof(table->descriptors[1].reserved); i++)
+ EXPECT_EQ(table->descriptors[1].reserved[i], 0);
+ EXPECT_EQ(table->descriptors[1].vbmeta_name, "vbmeta_vendor");
+
+ EXPECT_EQ(table->descriptors[2].vbmeta_index, 1);
+ EXPECT_EQ(table->descriptors[2].vbmeta_name_length, 14);
+ for (int i = 0; i < sizeof(table->descriptors[2].reserved); i++)
+ EXPECT_EQ(table->descriptors[2].reserved[i], 0);
+ EXPECT_EQ(table->descriptors[2].vbmeta_name, "vbmeta_product");
+}
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h b/fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h
new file mode 100644
index 0000000..ab7ba73
--- /dev/null
+++ b/fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+
+namespace android {
+namespace fs_mgr {
+
+bool WriteToSuperVBMetaFile(const std::string& super_vbmeta_file,
+ const std::map<std::string, std::string>& images_path);
+
+} // namespace fs_mgr
+} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/reader.cpp b/fs_mgr/libvbmeta/reader.cpp
new file mode 100644
index 0000000..212d186
--- /dev/null
+++ b/fs_mgr/libvbmeta/reader.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#include "reader.h"
+
+#include <android-base/file.h>
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+namespace android {
+namespace fs_mgr {
+
+Result<void> LoadAndVerifySuperVBMetaHeader(const void* buffer, SuperVBMetaHeader* header) {
+ memcpy(header, buffer, sizeof(*header));
+
+ // Do basic validation of super vbmeta.
+ if (header->magic != SUPER_VBMETA_MAGIC) {
+ return Error() << "Super VBMeta has invalid magic value";
+ }
+
+ // Check that the version is compatible.
+ if (header->major_version != SUPER_VBMETA_MAJOR_VERSION ||
+ header->minor_version > SUPER_VBMETA_MINOR_VERSION) {
+ return Error() << "Super VBMeta has incompatible version";
+ }
+ return {};
+}
+
+void LoadVBMetaDescriptors(const void* buffer, uint32_t size,
+ std::vector<InternalVBMetaDescriptor>* descriptors) {
+ for (int p = 0; p < size;) {
+ InternalVBMetaDescriptor descriptor;
+ memcpy(&descriptor, (char*)buffer + p, SUPER_VBMETA_DESCRIPTOR_SIZE);
+ p += SUPER_VBMETA_DESCRIPTOR_SIZE;
+
+ descriptor.vbmeta_name = std::string((char*)buffer + p, descriptor.vbmeta_name_length);
+ p += descriptor.vbmeta_name_length;
+
+ descriptors->emplace_back(std::move(descriptor));
+ }
+}
+
+Result<void> ReadVBMetaTable(int fd, uint64_t offset, VBMetaTable* table) {
+ std::unique_ptr<uint8_t[]> header_buffer =
+ std::make_unique<uint8_t[]>(SUPER_VBMETA_HEADER_SIZE);
+ if (!android::base::ReadFullyAtOffset(fd, header_buffer.get(), SUPER_VBMETA_HEADER_SIZE,
+ offset)) {
+ return ErrnoError() << "Couldn't read super vbmeta header at offset " << offset;
+ }
+
+ Result<void> rv_header = LoadAndVerifySuperVBMetaHeader(header_buffer.get(), &table->header);
+ if (!rv_header) {
+ return rv_header;
+ }
+
+ const uint64_t descriptors_offset = offset + table->header.header_size;
+ std::unique_ptr<uint8_t[]> descriptors_buffer =
+ std::make_unique<uint8_t[]>(table->header.descriptors_size);
+ if (!android::base::ReadFullyAtOffset(fd, descriptors_buffer.get(),
+ table->header.descriptors_size, descriptors_offset)) {
+ return ErrnoError() << "Couldn't read super vbmeta descriptors at offset "
+ << descriptors_offset;
+ }
+
+ LoadVBMetaDescriptors(descriptors_buffer.get(), table->header.descriptors_size,
+ &table->descriptors);
+ return {};
+}
+
+Result<void> ReadPrimaryVBMetaTable(int fd, VBMetaTable* table) {
+ uint64_t offset = PRIMARY_SUPER_VBMETA_TABLE_OFFSET;
+ return ReadVBMetaTable(fd, offset, table);
+}
+
+Result<void> ReadBackupVBMetaTable(int fd, VBMetaTable* table) {
+ uint64_t offset = BACKUP_SUPER_VBMETA_TABLE_OFFSET;
+ return ReadVBMetaTable(fd, offset, table);
+}
+
+Result<std::string> ReadVBMetaImage(int fd, int slot) {
+ const uint64_t offset = 2 * SUPER_VBMETA_TABLE_MAX_SIZE + slot * VBMETA_IMAGE_MAX_SIZE;
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
+ if (!android::base::ReadFullyAtOffset(fd, buffer.get(), VBMETA_IMAGE_MAX_SIZE, offset)) {
+ return ErrnoError() << "Couldn't read vbmeta image at offset " << offset;
+ }
+ return std::string(reinterpret_cast<char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
+}
+
+Result<void> ValidateVBMetaImage(int super_vbmeta_fd, int vbmeta_index,
+ const std::string& vbmeta_image) {
+ Result<std::string> content = ReadVBMetaImage(super_vbmeta_fd, vbmeta_index);
+ if (!content) {
+ return content.error();
+ }
+
+ if (vbmeta_image != content.value()) {
+ return Error() << "VBMeta Image in Super VBMeta differ from the original one.";
+ }
+ return {};
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/libvbmeta/reader.h b/fs_mgr/libvbmeta/reader.h
new file mode 100644
index 0000000..f0997ff
--- /dev/null
+++ b/fs_mgr/libvbmeta/reader.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/result.h>
+
+#include "super_vbmeta_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+android::base::Result<void> ReadPrimaryVBMetaTable(int fd, VBMetaTable* table);
+android::base::Result<void> ReadBackupVBMetaTable(int fd, VBMetaTable* table);
+android::base::Result<std::string> ReadVBMetaImage(int fd, int slot);
+
+android::base::Result<void> ValidateVBMetaImage(int super_vbmeta_fd, int vbmeta_index,
+ const std::string& vbmeta_image);
+
+} // namespace fs_mgr
+} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/super_vbmeta_format.h b/fs_mgr/libvbmeta/super_vbmeta_format.h
new file mode 100644
index 0000000..c62a2dd
--- /dev/null
+++ b/fs_mgr/libvbmeta/super_vbmeta_format.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/* This .h file is intended for CPP clients (usually fastbootd, recovery and update_engine) */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "super_vbmeta_format_c.h"
+
+struct InternalVBMetaDescriptor : VBMetaDescriptor {
+ /* 64: The vbmeta image's name */
+ std::string vbmeta_name;
+};
+
+struct VBMetaTable {
+ SuperVBMetaHeader header;
+ std::vector<InternalVBMetaDescriptor> descriptors;
+};
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/super_vbmeta_format_c.h b/fs_mgr/libvbmeta/super_vbmeta_format_c.h
new file mode 100644
index 0000000..6d79801
--- /dev/null
+++ b/fs_mgr/libvbmeta/super_vbmeta_format_c.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+/* This .h file is intended for C clients (usually bootloader). */
+
+#pragma once
+
+#include <stdint.h>
+
+/* Magic signature for super vbmeta. */
+#define SUPER_VBMETA_MAGIC 0x5356424d
+
+/* Current super vbmeta version. */
+#define SUPER_VBMETA_MAJOR_VERSION 1
+#define SUPER_VBMETA_MINOR_VERSION 0
+
+/* super vbmeta size. */
+#define SUPER_VBMETA_HEADER_SIZE sizeof(SuperVBMetaHeader)
+#define SUPER_VBMETA_DESCRIPTOR_SIZE sizeof(VBMetaDescriptor)
+#define SUPER_VBMETA_TABLE_MAX_SIZE 2048
+
+/* super vbmeta offset. */
+#define PRIMARY_SUPER_VBMETA_TABLE_OFFSET 0
+#define BACKUP_SUPER_VBMETA_TABLE_OFFSET SUPER_VBMETA_TABLE_MAX_SIZE
+
+/* restriction of vbmeta image */
+#define VBMETA_IMAGE_MAX_NUM 32
+#define VBMETA_IMAGE_MAX_SIZE 64 * 1024
+
+/* Binary format of the super vbmeta image.
+ *
+ * The super vbmeta image consists of two blocks:
+ *
+ * +------------------------------------------+
+ * | Super VBMeta Table - fixed size |
+ * +------------------------------------------+
+ * | Backup Super VBMeta Table - fixed size |
+ * +------------------------------------------+
+ * | VBMeta Images - fixed size |
+ * +------------------------------------------+
+ *
+ * The "Super VBMeta Table" records the offset
+ * and the size of each vbmeta_partition within
+ * /super_vbmeta.
+ *
+ * The "VBMeta Image" is copied from each vbmeta_partition
+ * and filled with 0 until 64K bytes.
+ *
+ * The super vbmeta table consists of two blocks:
+ *
+ * +-----------------------------------------+
+ * | Header data - fixed size |
+ * +-----------------------------------------+
+ * | VBMeta descriptors - variable size |
+ * +-----------------------------------------+
+ *
+ * The "Header data" block is described by the following struct and
+ * is always 128 bytes long.
+ *
+ * The "VBMeta descriptor" is |descriptors_size| + |vbmeta_name_length|
+ * bytes long. It contains the offset and size for each vbmeta image
+ * and is followed by |vbmeta_name_length| bytes of the partition name
+ * (UTF-8 encoded).
+ */
+
+typedef struct SuperVBMetaHeader {
+ /* 0: Magic signature (SUPER_VBMETA_MAGIC). */
+ uint32_t magic;
+
+ /* 4: Major version. Version number required to read this super vbmeta. If the version is not
+ * equal to the library version, the super vbmeta should be considered incompatible.
+ */
+ uint16_t major_version;
+
+ /* 6: Minor version. A library supporting newer features should be able to
+ * read super vbmeta with an older minor version. However, an older library
+ * should not support reading super vbmeta if its minor version is higher.
+ */
+ uint16_t minor_version;
+
+ /* 8: The size of this header struct. */
+ uint32_t header_size;
+
+ /* 12: The size of this super vbmeta table. */
+ uint32_t total_size;
+
+ /* 16: SHA256 checksum of this super vbmeta table, with this field set to 0. */
+ uint8_t checksum[32];
+
+ /* 48: The size of the vbmeta table descriptors. */
+ uint32_t descriptors_size;
+
+ /* 52: mark which slot is in use. */
+ uint32_t in_use = 0;
+
+ /* 56: reserved for other usage, filled with 0. */
+ uint8_t reserved[72];
+} __attribute__((packed)) SuperVBMetaHeader;
+
+typedef struct VBMetaDescriptor {
+ /* 0: The slot number of the vbmeta image. */
+ uint8_t vbmeta_index;
+
+ /* 12: The length of the vbmeta image name. */
+ uint32_t vbmeta_name_length;
+
+ /* 16: Space reserved for other usage, filled with 0. */
+ uint8_t reserved[48];
+} __attribute__((packed)) VBMetaDescriptor;
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/super_vbmeta_test.cpp b/fs_mgr/libvbmeta/super_vbmeta_test.cpp
new file mode 100644
index 0000000..6b4fc5d
--- /dev/null
+++ b/fs_mgr/libvbmeta/super_vbmeta_test.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+#include <openssl/sha.h>
+#include <sparse/sparse.h>
+
+#include "reader.h"
+#include "super_vbmeta_format.h"
+#include "utility.h"
+#include "writer.h"
+
+#define FAKE_DATA_SIZE 40960
+#define FAKE_PARTITION_SIZE FAKE_DATA_SIZE * 25
+
+using android::base::Result;
+using android::fs_mgr::GetFileSize;
+using android::fs_mgr::ReadVBMetaImage;
+using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
+
+void GeneratePartitionImage(int fd, const std::string& file_name,
+ const std::string& partition_name) {
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(FAKE_DATA_SIZE);
+ for (size_t c = 0; c < FAKE_DATA_SIZE; c++) {
+ buffer[c] = uint8_t(c);
+ }
+
+ SparsePtr file(sparse_file_new(512 /* block size */, FAKE_DATA_SIZE), sparse_file_destroy);
+ EXPECT_TRUE(file);
+ EXPECT_EQ(0, sparse_file_add_data(file.get(), buffer.get(), FAKE_DATA_SIZE,
+ 0 /* offset in blocks */));
+ EXPECT_EQ(0, sparse_file_write(file.get(), fd, false /* gz */, true /* sparse */,
+ false /* crc */));
+
+ std::stringstream cmd;
+ cmd << "avbtool add_hashtree_footer"
+ << " --image " << file_name << " --partition_name " << partition_name
+ << " --partition_size " << FAKE_PARTITION_SIZE << " --algorithm SHA256_RSA2048"
+ << " --key external/avb/test/data/testkey_rsa2048.pem";
+
+ int rc = system(cmd.str().c_str());
+ EXPECT_TRUE(WIFEXITED(rc));
+ EXPECT_EQ(WEXITSTATUS(rc), 0);
+}
+
+void GenerateVBMetaImage(const std::string& vbmeta_file_name,
+ const std::string& include_file_name) {
+ std::stringstream cmd;
+ cmd << "avbtool make_vbmeta_image"
+ << " --output " << vbmeta_file_name << " --include_descriptors_from_image "
+ << include_file_name;
+
+ int rc = system(cmd.str().c_str());
+ EXPECT_TRUE(WIFEXITED(rc));
+ EXPECT_EQ(WEXITSTATUS(rc), 0);
+}
+
+std::string ReadVBMetaImageFromFile(const std::string& file) {
+ android::base::unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
+ EXPECT_GT(fd, 0);
+ Result<uint64_t> file_size = GetFileSize(fd);
+ EXPECT_TRUE(file_size);
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
+ EXPECT_TRUE(android::base::ReadFully(fd, buffer.get(), file_size.value()));
+ return std::string(reinterpret_cast<char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
+}
+
+TEST(VBMetaTableTest, VBMetaTableBasic) {
+ TemporaryDir td;
+
+ // Generate Partition Image
+ TemporaryFile system_tf(std::string(td.path));
+ std::string system_path(system_tf.path);
+ GeneratePartitionImage(system_tf.fd, system_path, "system");
+ system_tf.release();
+
+ TemporaryFile vendor_tf(std::string(td.path));
+ std::string vendor_path(vendor_tf.path);
+ GeneratePartitionImage(vendor_tf.fd, vendor_path, "vendor");
+ vendor_tf.release();
+
+ TemporaryFile product_tf(std::string(td.path));
+ std::string product_path(product_tf.path);
+ GeneratePartitionImage(product_tf.fd, product_path, "product");
+ product_tf.release();
+
+ // Generate VBMeta Image
+ std::string vbmeta_system_path(td.path);
+ vbmeta_system_path.append("/vbmeta_system.img");
+ GenerateVBMetaImage(vbmeta_system_path, system_path);
+
+ std::string vbmeta_vendor_path(td.path);
+ vbmeta_vendor_path.append("/vbmeta_vendor.img");
+ GenerateVBMetaImage(vbmeta_vendor_path, vendor_path);
+
+ std::string vbmeta_product_path(td.path);
+ vbmeta_product_path.append("/vbmeta_product.img");
+ GenerateVBMetaImage(vbmeta_product_path, product_path);
+
+ // Generate Super VBMeta Image
+ std::string super_vbmeta_path(td.path);
+ super_vbmeta_path.append("/super_vbmeta.img");
+
+ std::stringstream cmd;
+ cmd << "vbmake"
+ << " --image "
+ << "vbmeta_system"
+ << "=" << vbmeta_system_path << " --image "
+ << "vbmeta_vendor"
+ << "=" << vbmeta_vendor_path << " --image "
+ << "vbmeta_product"
+ << "=" << vbmeta_product_path << " --output=" << super_vbmeta_path;
+
+ int rc = system(cmd.str().c_str());
+ ASSERT_TRUE(WIFEXITED(rc));
+ ASSERT_EQ(WEXITSTATUS(rc), 0);
+
+ android::base::unique_fd fd(open(super_vbmeta_path.c_str(), O_RDONLY | O_CLOEXEC));
+ EXPECT_GT(fd, 0);
+
+ // Check the size of vbmeta table
+ Result<uint64_t> super_vbmeta_size = GetFileSize(fd);
+ EXPECT_TRUE(super_vbmeta_size);
+ EXPECT_EQ(super_vbmeta_size.value(),
+ SUPER_VBMETA_TABLE_MAX_SIZE * 2 + VBMETA_IMAGE_MAX_SIZE * 3);
+
+ // Check Primary vbmeta table is equal to Backup one
+ VBMetaTable table;
+ EXPECT_TRUE(android::fs_mgr::ReadPrimaryVBMetaTable(fd, &table));
+ VBMetaTable table_backup;
+ EXPECT_TRUE(android::fs_mgr::ReadBackupVBMetaTable(fd, &table_backup));
+ EXPECT_EQ(android::fs_mgr::SerializeVBMetaTable(table),
+ android::fs_mgr::SerializeVBMetaTable(table_backup));
+
+ // Check vbmeta table Header Checksum
+ std::string serial_table = android::fs_mgr::SerializeVBMetaTable(table);
+ std::string serial_removed_checksum(serial_table);
+ // Replace checksum 32 bytes (starts at 16th byte) with 0
+ serial_removed_checksum.replace(16, 32, 32, 0);
+ uint8_t test_checksum[32];
+ ::SHA256(reinterpret_cast<const uint8_t*>(serial_removed_checksum.c_str()),
+ table.header.total_size, &test_checksum[0]);
+ EXPECT_EQ(memcmp(table.header.checksum, test_checksum, 32), 0);
+
+ // Check vbmeta table descriptors and vbmeta images
+ EXPECT_EQ(table.descriptors.size(), 3);
+
+ EXPECT_EQ(table.descriptors[0].vbmeta_index, 0);
+ EXPECT_EQ(table.descriptors[0].vbmeta_name_length, 14);
+ EXPECT_EQ(table.descriptors[0].vbmeta_name, "vbmeta_product");
+ Result<std::string> vbmeta_product_content = ReadVBMetaImage(fd, 0);
+ EXPECT_TRUE(vbmeta_product_content);
+ EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_product_path), vbmeta_product_content.value());
+
+ EXPECT_EQ(table.descriptors[1].vbmeta_index, 1);
+ EXPECT_EQ(table.descriptors[1].vbmeta_name_length, 13);
+ EXPECT_EQ(table.descriptors[1].vbmeta_name, "vbmeta_system");
+ Result<std::string> vbmeta_system_content = ReadVBMetaImage(fd, 1);
+ EXPECT_TRUE(vbmeta_system_content);
+ EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_system_path), vbmeta_system_content.value());
+
+ EXPECT_EQ(table.descriptors[2].vbmeta_index, 2);
+ EXPECT_EQ(table.descriptors[2].vbmeta_name_length, 13);
+ EXPECT_EQ(table.descriptors[2].vbmeta_name, "vbmeta_vendor");
+ Result<std::string> vbmeta_vendor_content = ReadVBMetaImage(fd, 2);
+ EXPECT_TRUE(vbmeta_vendor_content);
+ EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_vendor_path), vbmeta_vendor_content.value());
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/utility.cpp b/fs_mgr/libvbmeta/utility.cpp
new file mode 100644
index 0000000..c184227
--- /dev/null
+++ b/fs_mgr/libvbmeta/utility.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#include "utility.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "super_vbmeta_format.h"
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+namespace android {
+namespace fs_mgr {
+
+Result<uint64_t> GetFileSize(int fd) {
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ return ErrnoError() << "Couldn't get the file size";
+ }
+ return sb.st_size;
+}
+
+uint64_t IndexOffset(const uint8_t vbmeta_index) {
+ /* There are primary and backup vbmeta table in super_vbmeta,
+ so SUPER_VBMETA_TABLE_MAX_SIZE is counted twice. */
+ return 2 * SUPER_VBMETA_TABLE_MAX_SIZE + vbmeta_index * VBMETA_IMAGE_MAX_SIZE;
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/libvbmeta/utility.h b/fs_mgr/libvbmeta/utility.h
new file mode 100644
index 0000000..91db0ad
--- /dev/null
+++ b/fs_mgr/libvbmeta/utility.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/result.h>
+
+#define VBMETA_TAG "[libvbmeta]"
+#define LWARN LOG(WARNING) << VBMETA_TAG
+#define LINFO LOG(INFO) << VBMETA_TAG
+#define LERROR LOG(ERROR) << VBMETA_TAG
+#define PWARNING PLOG(WARNING) << VBMETA_TAG
+#define PERROR PLOG(ERROR) << VBMETA_TAG
+
+namespace android {
+namespace fs_mgr {
+
+android::base::Result<uint64_t> GetFileSize(int fd);
+
+uint64_t IndexOffset(const uint8_t vbmeta_index);
+
+} // namespace fs_mgr
+} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/writer.cpp b/fs_mgr/libvbmeta/writer.cpp
new file mode 100644
index 0000000..fc0e0fb
--- /dev/null
+++ b/fs_mgr/libvbmeta/writer.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#include "writer.h"
+
+#include <android-base/file.h>
+
+#include "utility.h"
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+namespace fs_mgr {
+
+std::string SerializeVBMetaTable(const VBMetaTable& input) {
+ std::string table;
+ table.append(reinterpret_cast<const char*>(&input.header), SUPER_VBMETA_HEADER_SIZE);
+
+ for (const auto& desc : input.descriptors) {
+ table.append(reinterpret_cast<const char*>(&desc), SUPER_VBMETA_DESCRIPTOR_SIZE);
+ table.append(desc.vbmeta_name);
+ }
+
+ // Ensure the size of vbmeta table is SUPER_VBMETA_TABLE_MAX_SIZE
+ table.resize(SUPER_VBMETA_TABLE_MAX_SIZE, '\0');
+
+ return table;
+}
+
+Result<void> WritePrimaryVBMetaTable(int fd, const std::string& table) {
+ const uint64_t offset = PRIMARY_SUPER_VBMETA_TABLE_OFFSET;
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
+ }
+
+ if (!android::base::WriteFully(fd, table.data(), table.size())) {
+ return ErrnoError() << "Failed to write primary vbmeta table at offset " << offset;
+ }
+ return {};
+}
+
+Result<void> WriteBackupVBMetaTable(int fd, const std::string& table) {
+ const uint64_t offset = BACKUP_SUPER_VBMETA_TABLE_OFFSET;
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
+ }
+
+ if (!android::base::WriteFully(fd, table.data(), table.size())) {
+ return ErrnoError() << "Failed to write backup vbmeta table at offset " << offset;
+ }
+ return {};
+}
+
+Result<void> WriteVBMetaImage(int fd, const uint8_t slot_number, const std::string& vbmeta_image) {
+ const uint64_t offset = IndexOffset(slot_number);
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
+ }
+
+ if (!android::base::WriteFully(fd, vbmeta_image.data(), vbmeta_image.size())) {
+ return ErrnoError() << "Failed to write vbmeta image at offset " << offset;
+ }
+ return {};
+}
+
+} // namespace fs_mgr
+} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/writer.h b/fs_mgr/libvbmeta/writer.h
new file mode 100644
index 0000000..f8eed36
--- /dev/null
+++ b/fs_mgr/libvbmeta/writer.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <android-base/result.h>
+
+#include "super_vbmeta_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::string SerializeVBMetaTable(const VBMetaTable& input);
+
+android::base::Result<void> WritePrimaryVBMetaTable(int fd, const std::string& table);
+android::base::Result<void> WriteBackupVBMetaTable(int fd, const std::string& table);
+android::base::Result<void> WriteVBMetaImage(int fd, const uint8_t slot_number,
+ const std::string& vbmeta_image);
+
+} // namespace fs_mgr
+} // namespace android
\ No newline at end of file
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index ff20e43..9736824 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -121,13 +121,8 @@
}
Subcontext* action_subcontext = nullptr;
- if (subcontexts_) {
- for (auto& subcontext : *subcontexts_) {
- if (StartsWith(filename, subcontext.path_prefix())) {
- action_subcontext = &subcontext;
- break;
- }
- }
+ if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
+ action_subcontext = subcontext_;
}
std::string event_trigger;
diff --git a/init/action_parser.h b/init/action_parser.h
index 2fe9983..3000132 100644
--- a/init/action_parser.h
+++ b/init/action_parser.h
@@ -30,8 +30,8 @@
class ActionParser : public SectionParser {
public:
- ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
- : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
+ ActionParser(ActionManager* action_manager, Subcontext* subcontext)
+ : action_manager_(action_manager), subcontext_(subcontext), action_(nullptr) {}
Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<void> ParseLineSection(std::vector<std::string>&& args, int line) override;
@@ -39,7 +39,7 @@
private:
ActionManager* action_manager_;
- std::vector<Subcontext>* subcontexts_;
+ Subcontext* subcontext_;
std::unique_ptr<Action> action_;
};
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 4a1bc5a..9121bac 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -50,12 +50,13 @@
using android::fs_mgr::AvbHandleStatus;
using android::fs_mgr::AvbHashtreeResult;
using android::fs_mgr::AvbUniquePtr;
-using android::fs_mgr::BuildGsiSystemFstabEntry;
using android::fs_mgr::Fstab;
using android::fs_mgr::FstabEntry;
using android::fs_mgr::ReadDefaultFstab;
using android::fs_mgr::ReadFstabFromDt;
using android::fs_mgr::SkipMountingPartitions;
+using android::fs_mgr::TransformFstabForDsu;
+using android::init::WriteFile;
using android::snapshot::SnapshotManager;
using namespace std::literals;
@@ -596,14 +597,14 @@
}
void FirstStageMount::UseGsiIfPresent() {
- std::string metadata_file, error;
+ std::string error;
- if (!android::gsi::CanBootIntoGsi(&metadata_file, &error)) {
+ if (!android::gsi::CanBootIntoGsi(&error)) {
LOG(INFO) << "GSI " << error << ", proceeding with normal boot";
return;
}
- auto metadata = android::fs_mgr::ReadFromImageFile(metadata_file.c_str());
+ auto metadata = android::fs_mgr::ReadFromImageFile(gsi::kDsuLpMetadataFile);
if (!metadata) {
LOG(ERROR) << "GSI partition layout could not be read";
return;
@@ -627,14 +628,16 @@
return;
}
- // Replace the existing system fstab entry.
- auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
- return entry.mount_point == "/system";
- });
- if (system_partition != fstab_.end()) {
- fstab_.erase(system_partition);
+ std::string lp_names = "";
+ std::vector<std::string> dsu_partitions;
+ for (auto&& partition : metadata->partitions) {
+ auto name = fs_mgr::GetPartitionName(partition);
+ dsu_partitions.push_back(name);
+ lp_names += name + ",";
}
- fstab_.emplace_back(BuildGsiSystemFstabEntry());
+ // Publish the logical partition names for TransformFstabForDsu
+ WriteFile(gsi::kGsiLpNamesFile, lp_names);
+ TransformFstabForDsu(&fstab_, dsu_partitions);
gsi_not_on_userdata_ = (super_name != "userdata");
}
diff --git a/init/init.cpp b/init/init.cpp
index 8326466..ad31fa0 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -103,7 +103,7 @@
static bool do_shutdown = false;
static bool load_debug_prop = false;
-static std::vector<Subcontext>* subcontexts;
+static std::unique_ptr<Subcontext> subcontext;
void DumpState() {
ServiceList::GetInstance().DumpState();
@@ -113,9 +113,10 @@
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
- parser.AddSectionParser(
- "service", std::make_unique<ServiceParser>(&service_list, subcontexts, std::nullopt));
- parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(
+ &service_list, subcontext.get(), std::nullopt));
+ parser.AddSectionParser("on",
+ std::make_unique<ActionParser>(&action_manager, subcontext.get()));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
return parser;
@@ -125,8 +126,8 @@
Parser CreateServiceOnlyParser(ServiceList& service_list) {
Parser parser;
- parser.AddSectionParser(
- "service", std::make_unique<ServiceParser>(&service_list, subcontexts, std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(
+ &service_list, subcontext.get(), std::nullopt));
return parser;
}
@@ -749,7 +750,7 @@
PLOG(FATAL) << "SetupMountNamespaces failed";
}
- subcontexts = InitializeSubcontexts();
+ subcontext = InitializeSubcontext();
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c18decc..f5d1143 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -530,7 +530,7 @@
uint32_t result = 0;
ucred cr = {.pid = 1, .uid = 0, .gid = 0};
std::string error;
- result = HandlePropertySet(name, value, kInitContext.c_str(), cr, nullptr, &error);
+ result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
if (result != PROP_SUCCESS) {
LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
}
@@ -645,11 +645,16 @@
char *key, *value, *eol, *sol, *tmp, *fn;
size_t flen = 0;
- const char* context = kInitContext.c_str();
+ static constexpr const char* const kVendorPathPrefixes[2] = {
+ "/vendor",
+ "/odm",
+ };
+
+ const char* context = kInitContext;
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
- for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
- if (StartsWith(filename, path_prefix)) {
- context = secontext;
+ for (const auto& vendor_path_prefix : kVendorPathPrefixes) {
+ if (StartsWith(filename, vendor_path_prefix)) {
+ context = kVendorContext;
}
}
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 786a084..2cf0f5c 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -60,6 +60,8 @@
#define PROC_SYSRQ "/proc/sysrq-trigger"
+using namespace std::literals;
+
using android::base::GetBoolProperty;
using android::base::Split;
using android::base::Timer;
@@ -170,9 +172,23 @@
<< stat;
}
-/* Find all read+write block devices and emulated devices in /proc/mounts
- * and add them to correpsponding list.
- */
+static bool IsDataMounted() {
+ std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
+ if (fp == nullptr) {
+ PLOG(ERROR) << "Failed to open /proc/mounts";
+ return false;
+ }
+ mntent* mentry;
+ while ((mentry = getmntent(fp.get())) != nullptr) {
+ if (mentry->mnt_dir == "/data"s) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Find all read+write block devices and emulated devices in /proc/mounts and add them to
+// the correpsponding list.
static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
std::vector<MountEntry>* emulatedPartitions, bool dump) {
std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
@@ -295,12 +311,15 @@
LOG(ERROR) << "Reboot thread timed out";
if (android::base::GetBoolProperty("ro.debuggable", false) == true) {
- LOG(INFO) << "Try to dump init process call trace:";
- const char* vdc_argv[] = {"/system/bin/debuggerd", "-b", "1"};
- int status;
- android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true,
- LOG_KLOG, true, nullptr, nullptr, 0);
-
+ if (false) {
+ // SEPolicy will block debuggerd from running and this is intentional.
+ // But these lines are left to be enabled during debugging.
+ LOG(INFO) << "Try to dump init process call trace:";
+ const char* vdc_argv[] = {"/system/bin/debuggerd", "-b", "1"};
+ int status;
+ android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true,
+ LOG_KLOG, true, nullptr, nullptr, 0);
+ }
LOG(INFO) << "Show stack for all active CPU:";
WriteStringToFile("l", PROC_SYSRQ);
@@ -436,6 +455,14 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
+ // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
+ // worry about unmounting it.
+ if (!IsDataMounted()) {
+ sync();
+ RebootSystem(cmd, rebootTarget);
+ abort();
+ }
+
// Ensure last reboot reason is reduced to canonical
// alias reported in bootloader or system boot reason.
size_t skip = 0;
diff --git a/init/service.cpp b/init/service.cpp
index 793a2b2..e8b75d4 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -441,6 +441,23 @@
LOG(INFO) << "starting service '" << name_ << "'...";
+ std::vector<Descriptor> descriptors;
+ for (const auto& socket : sockets_) {
+ if (auto result = socket.Create(scon)) {
+ descriptors.emplace_back(std::move(*result));
+ } else {
+ LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
+ }
+ }
+
+ for (const auto& file : files_) {
+ if (auto result = file.Create()) {
+ descriptors.emplace_back(std::move(*result));
+ } else {
+ LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
+ }
+ }
+
pid_t pid = -1;
if (namespaces_.flags) {
pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
@@ -460,16 +477,8 @@
setenv(key.c_str(), value.c_str(), 1);
}
- for (const auto& socket : sockets_) {
- if (auto result = socket.CreateAndPublish(scon); !result) {
- LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
- }
- }
-
- for (const auto& file : files_) {
- if (auto result = file.CreateAndPublish(); !result) {
- LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
- }
+ for (const auto& descriptor : descriptors) {
+ descriptor.Publish();
}
if (auto result = WritePidToFiles(&writepid_files_); !result) {
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 4322dc7..45d1852 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -537,13 +537,8 @@
filename_ = filename;
Subcontext* restart_action_subcontext = nullptr;
- if (subcontexts_) {
- for (auto& subcontext : *subcontexts_) {
- if (StartsWith(filename, subcontext.path_prefix())) {
- restart_action_subcontext = &subcontext;
- break;
- }
- }
+ if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
+ restart_action_subcontext = subcontext_;
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
diff --git a/init/service_parser.h b/init/service_parser.h
index ace4d70..f063102 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -30,10 +30,10 @@
class ServiceParser : public SectionParser {
public:
ServiceParser(
- ServiceList* service_list, std::vector<Subcontext>* subcontexts,
+ ServiceList* service_list, Subcontext* subcontext,
const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
: service_list_(service_list),
- subcontexts_(subcontexts),
+ subcontext_(subcontext),
interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
service_(nullptr) {}
Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
@@ -84,7 +84,7 @@
bool IsValidName(const std::string& name) const;
ServiceList* service_list_;
- std::vector<Subcontext>* subcontexts_;
+ Subcontext* subcontext_;
std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
std::unique_ptr<Service> service_;
std::string filename_;
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 836145d..35f2acf 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -26,7 +26,6 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
#include <processgroup/processgroup.h>
@@ -138,37 +137,44 @@
dup2(fd, 2);
}
-void PublishDescriptor(const std::string& key, const std::string& name, int fd) {
- std::string published_name = key + name;
+} // namespace
+
+void Descriptor::Publish() const {
+ auto published_name = name_;
+
for (auto& c : published_name) {
c = isalnum(c) ? c : '_';
}
+ int fd = fd_.get();
+ // For safety, the FD is created as CLOEXEC, so that must be removed before publishing.
+ auto fd_flags = fcntl(fd, F_GETFD);
+ fd_flags &= ~FD_CLOEXEC;
+ if (fcntl(fd, F_SETFD, fd_flags) != 0) {
+ PLOG(ERROR) << "Failed to remove CLOEXEC from '" << published_name << "'";
+ }
+
std::string val = std::to_string(fd);
setenv(published_name.c_str(), val.c_str(), 1);
}
-} // namespace
-
-Result<void> SocketDescriptor::CreateAndPublish(const std::string& global_context) const {
+Result<Descriptor> SocketDescriptor::Create(const std::string& global_context) const {
const auto& socket_context = context.empty() ? global_context : context;
- auto result = CreateSocket(name, type, passcred, perm, uid, gid, socket_context);
+ auto result = CreateSocket(name, type | SOCK_CLOEXEC, passcred, perm, uid, gid, socket_context);
if (!result) {
return result.error();
}
- PublishDescriptor(ANDROID_SOCKET_ENV_PREFIX, name, *result);
-
- return {};
+ return Descriptor(ANDROID_SOCKET_ENV_PREFIX + name, unique_fd(*result));
}
-Result<void> FileDescriptor::CreateAndPublish() const {
+Result<Descriptor> FileDescriptor::Create() const {
int flags = (type == "r") ? O_RDONLY : (type == "w") ? O_WRONLY : O_RDWR;
// Make sure we do not block on open (eg: devices can chose to block on carrier detect). Our
// intention is never to delay launch of a service for such a condition. The service can
// perform its own blocking on carrier detect.
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK)));
+ unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK | O_CLOEXEC)));
if (fd < 0) {
return ErrnoError() << "Failed to open file '" << name << "'";
@@ -179,9 +185,7 @@
LOG(INFO) << "Opened file '" << name << "', flags " << flags;
- PublishDescriptor(ANDROID_FILE_ENV_PREFIX, name, fd.release());
-
- return {};
+ return Descriptor(ANDROID_FILE_ENV_PREFIX + name, std::move(fd));
}
Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
diff --git a/init/service_utils.h b/init/service_utils.h
index befce25..d2e69d9 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -22,6 +22,7 @@
#include <string>
#include <vector>
+#include <android-base/unique_fd.h>
#include <cutils/iosched_policy.h>
#include "result.h"
@@ -29,6 +30,18 @@
namespace android {
namespace init {
+class Descriptor {
+ public:
+ Descriptor(const std::string& name, android::base::unique_fd fd)
+ : name_(name), fd_(std::move(fd)){};
+
+ void Publish() const;
+
+ private:
+ std::string name_;
+ android::base::unique_fd fd_;
+};
+
struct SocketDescriptor {
std::string name;
int type = 0;
@@ -38,14 +51,14 @@
std::string context;
bool passcred = false;
- Result<void> CreateAndPublish(const std::string& global_context) const;
+ Result<Descriptor> Create(const std::string& global_context) const;
};
struct FileDescriptor {
std::string name;
std::string type;
- Result<void> CreateAndPublish() const;
+ Result<Descriptor> Create() const;
};
struct NamespaceInfo {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index ec93b58..79fc372 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -49,15 +49,6 @@
namespace android {
namespace init {
-
-const std::string kInitContext = "u:r:init:s0";
-const std::string kVendorContext = "u:r:vendor_init:s0";
-
-const char* const paths_and_secontexts[2][2] = {
- {"/vendor", kVendorContext.c_str()},
- {"/odm", kVendorContext.c_str()},
-};
-
namespace {
class SubcontextProcess {
@@ -237,6 +228,15 @@
Fork();
}
+bool Subcontext::PathMatchesSubcontext(const std::string& path) {
+ for (const auto& prefix : path_prefixes_) {
+ if (StartsWith(path, prefix)) {
+ return true;
+ }
+ }
+ return false;
+}
+
Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
if (auto result = SendMessage(socket_, subcontext_command); !result) {
Restart();
@@ -313,13 +313,12 @@
static std::vector<Subcontext> subcontexts;
static bool shutting_down;
-std::vector<Subcontext>* InitializeSubcontexts() {
+std::unique_ptr<Subcontext> InitializeSubcontext() {
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
- for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
- subcontexts.emplace_back(path_prefix, secontext);
- }
+ return std::make_unique<Subcontext>(std::vector<std::string>{"/vendor", "/odm"},
+ kVendorContext);
}
- return &subcontexts;
+ return nullptr;
}
bool SubcontextChildReap(pid_t pid) {
diff --git a/init/subcontext.h b/init/subcontext.h
index 591521f..bcaad29 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _INIT_SUBCONTEXT_H
-#define _INIT_SUBCONTEXT_H
+#pragma once
#include <signal.h>
@@ -31,22 +30,21 @@
namespace android {
namespace init {
-extern const std::string kInitContext;
-extern const std::string kVendorContext;
-extern const char* const paths_and_secontexts[2][2];
+static constexpr const char kInitContext[] = "u:r:init:s0";
+static constexpr const char kVendorContext[] = "u:r:vendor_init:s0";
class Subcontext {
public:
- Subcontext(std::string path_prefix, std::string context)
- : path_prefix_(std::move(path_prefix)), context_(std::move(context)), pid_(0) {
+ Subcontext(std::vector<std::string> path_prefixes, std::string context)
+ : path_prefixes_(std::move(path_prefixes)), context_(std::move(context)), pid_(0) {
Fork();
}
Result<void> Execute(const std::vector<std::string>& args);
Result<std::vector<std::string>> ExpandArgs(const std::vector<std::string>& args);
void Restart();
+ bool PathMatchesSubcontext(const std::string& path);
- const std::string& path_prefix() const { return path_prefix_; }
const std::string& context() const { return context_; }
pid_t pid() const { return pid_; }
@@ -54,18 +52,16 @@
void Fork();
Result<SubcontextReply> TransmitMessage(const SubcontextCommand& subcontext_command);
- std::string path_prefix_;
+ std::vector<std::string> path_prefixes_;
std::string context_;
pid_t pid_;
android::base::unique_fd socket_;
};
int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map);
-std::vector<Subcontext>* InitializeSubcontexts();
+std::unique_ptr<Subcontext> InitializeSubcontext();
bool SubcontextChildReap(pid_t pid);
void SubcontextTerminate();
} // namespace init
} // namespace android
-
-#endif
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
index f6fee8a..ccef2f3 100644
--- a/init/subcontext_benchmark.cpp
+++ b/init/subcontext_benchmark.cpp
@@ -33,7 +33,7 @@
return;
}
- auto subcontext = Subcontext("path", context);
+ auto subcontext = Subcontext({"path"}, context);
free(context);
while (state.KeepRunning()) {
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 7565eb6..9cac35e 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -52,7 +52,7 @@
auto context_string = std::string(context);
free(context);
- auto subcontext = Subcontext("dummy_path", context_string);
+ auto subcontext = Subcontext({"dummy_path"}, context_string);
ASSERT_NE(0, subcontext.pid());
test_function(subcontext, context_string);
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index ac633776..416d942 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -171,7 +171,7 @@
return RegenerateUeventsForDir(d.get(), callback);
}
-static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
+static const char* kRegenerationPaths[] = {"/sys/devices"};
void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
for (const auto path : kRegenerationPaths) {
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 4c2be91..cf5341d 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -31,6 +31,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
using namespace std;
using namespace android::meminfo;
@@ -334,7 +335,9 @@
// Check for names
EXPECT_EQ(vmas[0].name, "[anon:dalvik-zygote-jit-code-cache]");
EXPECT_EQ(vmas[1].name, "/system/framework/x86_64/boot-framework.art");
- EXPECT_EQ(vmas[2].name, "[anon:libc_malloc]");
+ EXPECT_TRUE(vmas[2].name == "[anon:libc_malloc]" ||
+ android::base::StartsWith(vmas[2].name, "[anon:scudo:"))
+ << "Unknown map name " << vmas[2].name;
EXPECT_EQ(vmas[3].name, "/system/priv-app/SettingsProvider/oat/x86_64/SettingsProvider.odex");
EXPECT_EQ(vmas[4].name, "/system/lib64/libhwui.so");
EXPECT_EQ(vmas[5].name, "[vsyscall]");
@@ -432,7 +435,9 @@
// Check for names
EXPECT_EQ(vmas[0].name, "[anon:dalvik-zygote-jit-code-cache]");
EXPECT_EQ(vmas[1].name, "/system/framework/x86_64/boot-framework.art");
- EXPECT_EQ(vmas[2].name, "[anon:libc_malloc]");
+ EXPECT_TRUE(vmas[2].name == "[anon:libc_malloc]" ||
+ android::base::StartsWith(vmas[2].name, "[anon:scudo:"))
+ << "Unknown map name " << vmas[2].name;
EXPECT_EQ(vmas[3].name, "/system/priv-app/SettingsProvider/oat/x86_64/SettingsProvider.odex");
EXPECT_EQ(vmas[4].name, "/system/lib64/libhwui.so");
EXPECT_EQ(vmas[5].name, "[vsyscall]");
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index ce937fd..c4add19 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -25,6 +25,7 @@
#include <unordered_map>
#include <android-base/macros.h>
+#include <android-base/strings.h>
#include <backtrace.h>
#include "Allocator.h"
@@ -250,7 +251,8 @@
} else if (mapping_name == current_lib) {
// .rodata or .data section
globals_mappings.emplace_back(*it);
- } else if (mapping_name == "[anon:libc_malloc]") {
+ } else if (mapping_name == "[anon:libc_malloc]" ||
+ android::base::StartsWith(mapping_name, "[anon:scudo:")) {
// named malloc mapping
heap_mappings.emplace_back(*it);
} else if (has_prefix(mapping_name, "[anon:dalvik-")) {
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index b860db9..939bdd7 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -63,14 +63,6 @@
export_include_dirs: ["include"],
}
-// TODO(jiyong) Remove this when its use in the internal master is
-// switched to libnativeloader-headers
-cc_library_headers {
- name: "libnativeloader-dummy-headers",
- host_supported: true,
- export_include_dirs: ["include"],
-}
-
cc_test {
name: "libnativeloader_test",
srcs: [
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index 0740e7d..b56dcdb 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -19,4 +19,5 @@
"libpackagelistparser",
],
test_suites: ["device-tests"],
+ require_root: true,
}
diff --git a/libutils/Looper_test.cpp b/libutils/Looper_test.cpp
index 6fdc0ed..37bdf05 100644
--- a/libutils/Looper_test.cpp
+++ b/libutils/Looper_test.cpp
@@ -11,8 +11,9 @@
#include <utils/threads.h>
+// b/141212746 - increased for virtual platforms with higher volatility
// # of milliseconds to fudge stopwatch measurements
-#define TIMING_TOLERANCE_MS 25
+#define TIMING_TOLERANCE_MS 100
namespace android {
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index c3641ef..1172ae7 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -22,7 +22,8 @@
#include <limits.h>
#include <time.h>
-#if defined(__ANDROID__)
+// host linux support requires Linux 2.6.39+
+#if defined(__linux__)
nsecs_t systemTime(int clock)
{
static const clockid_t clocks[] = {
@@ -41,8 +42,7 @@
nsecs_t systemTime(int /*clock*/)
{
// Clock support varies widely across hosts. Mac OS doesn't support
- // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
- // is windows.
+ // CLOCK_BOOTTIME, and Windows is windows.
struct timeval t;
t.tv_sec = t.tv_usec = 0;
gettimeofday(&t, nullptr);
diff --git a/libutils/include/utils/ByteOrder.h b/libutils/include/utils/ByteOrder.h
index 44ea13d..9b940e6 100644
--- a/libutils/include/utils/ByteOrder.h
+++ b/libutils/include/utils/ByteOrder.h
@@ -14,10 +14,17 @@
* limitations under the License.
*/
-//
+#pragma once
-#ifndef _LIBS_UTILS_BYTE_ORDER_H
-#define _LIBS_UTILS_BYTE_ORDER_H
+/*
+ * If you're looking for a portable <endian.h> that's available on Android,
+ * Linux, macOS, and Windows, see <android-base/endian.h> instead.
+ *
+ * Nothing in this file is useful because all supported Android ABIs are
+ * little-endian and all our code that runs on the host assumes that the host is
+ * also little-endian. What pretense at big-endian support exists is completely
+ * untested and unlikely to actually work.
+ */
#include <stdint.h>
#include <sys/types.h>
@@ -27,55 +34,12 @@
#include <netinet/in.h>
#endif
-/*
- * These macros are like the hton/ntoh byte swapping macros,
- * except they allow you to swap to and from the "device" byte
- * order. The device byte order is the endianness of the target
- * device -- for the ARM CPUs we use today, this is little endian.
- *
- * Note that the byte swapping functions have not been optimized
- * much; performance is currently not an issue for them since the
- * intent is to allow us to avoid byte swapping on the device.
- */
+/* TODO: move this cruft to frameworks/. */
-static inline uint32_t android_swap_long(uint32_t v)
-{
- return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
-}
+#define dtohl(x) (x)
+#define dtohs(x) (x)
+#define htodl(x) (x)
+#define htods(x) (x)
-static inline uint16_t android_swap_short(uint16_t v)
-{
- return (v<<8) | (v>>8);
-}
-
-#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
-
-#if BYTE_ORDER == DEVICE_BYTE_ORDER
-
-#define dtohl(x) (x)
-#define dtohs(x) (x)
-#define htodl(x) (x)
-#define htods(x) (x)
-
-#else
-
-#define dtohl(x) (android_swap_long(x))
-#define dtohs(x) (android_swap_short(x))
-#define htodl(x) (android_swap_long(x))
-#define htods(x) (android_swap_short(x))
-
-#endif
-
-#if BYTE_ORDER == LITTLE_ENDIAN
#define fromlel(x) (x)
-#define fromles(x) (x)
#define tolel(x) (x)
-#define toles(x) (x)
-#else
-#define fromlel(x) (android_swap_long(x))
-#define fromles(x) (android_swap_short(x))
-#define tolel(x) (android_swap_long(x))
-#define toles(x) (android_swap_short(x))
-#endif
-
-#endif // _LIBS_UTILS_BYTE_ORDER_H
diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h
index 4b9c91e..fec0ffa 100644
--- a/libutils/include/utils/Trace.h
+++ b/libutils/include/utils/Trace.h
@@ -17,7 +17,12 @@
#ifndef ANDROID_TRACE_H
#define ANDROID_TRACE_H
-#if defined(__ANDROID__)
+#if defined(_WIN32)
+
+#define ATRACE_NAME(...)
+#define ATRACE_CALL()
+
+#else // !_WIN32
#include <stdint.h>
@@ -51,11 +56,6 @@
} // namespace android
-#else // !__ANDROID__
-
-#define ATRACE_NAME(...)
-#define ATRACE_CALL()
-
-#endif // __ANDROID__
+#endif // _WIN32
#endif // ANDROID_TRACE_H
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 5a375ec..665bd38 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -160,7 +160,7 @@
}
auto search = denial_to_bug.find(scontext + tcontext + tclass);
if (search != denial_to_bug.end()) {
- bug_num->assign(" b/" + search->second);
+ bug_num->assign(" " + search->second);
} else {
bug_num->assign("");
}
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 51c1226..aa02a3a 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -1,7 +1,6 @@
cc_defaults {
name: "propertyinfoserializer_defaults",
host_supported: true,
- vendor_available: true,
cpp_std: "experimental",
cppflags: [
"-Wall",
@@ -9,8 +8,8 @@
"-Werror",
],
static_libs: [
- "libpropertyinfoparser",
"libbase",
+ "libpropertyinfoparser",
],
}
diff --git a/rootdir/avb/Android.bp b/rootdir/avb/Android.bp
new file mode 100644
index 0000000..85d2786
--- /dev/null
+++ b/rootdir/avb/Android.bp
@@ -0,0 +1,20 @@
+filegroup {
+ name: "q-gsi_avbpubkey",
+ srcs: [
+ "q-gsi.avbpubkey",
+ ],
+}
+
+filegroup {
+ name: "r-gsi_avbpubkey",
+ srcs: [
+ "r-gsi.avbpubkey",
+ ],
+}
+
+filegroup {
+ name: "s-gsi_avbpubkey",
+ srcs: [
+ "s-gsi.avbpubkey",
+ ],
+}
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index e598f05..bb8d4d0 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -80,16 +80,14 @@
# 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
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+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.
@@ -181,6 +179,7 @@
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
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index e1da587..60035aa 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -161,16 +161,14 @@
# 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
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+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.
@@ -422,6 +420,7 @@
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
@@ -490,13 +489,11 @@
# 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
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+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.
@@ -645,6 +642,7 @@
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
@@ -697,16 +695,14 @@
# 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
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+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.
@@ -788,6 +784,7 @@
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
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 4beabd6..b9b95a6 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -100,16 +100,14 @@
# 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.
###############################################################################
+# 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
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+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.
@@ -346,6 +344,7 @@
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
@@ -420,13 +419,11 @@
# 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
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+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.
@@ -449,6 +446,7 @@
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
@@ -504,16 +502,14 @@
# 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
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+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.
@@ -591,6 +587,7 @@
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
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 17f6596..50005d9 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -5,7 +5,7 @@
export ANDROID_ASSETS /system/app
export ANDROID_DATA /data
export ANDROID_STORAGE /storage
- export ANDROID_RUNTIME_ROOT /apex/com.android.art
+ export ANDROID_ART_ROOT /apex/com.android.art
export ANDROID_I18N_ROOT /apex/com.android.i18n
export ANDROID_TZDATA_ROOT /apex/com.android.tzdata
export EXTERNAL_STORAGE /sdcard
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a15b501..0fa6efc 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -68,19 +68,19 @@
service boringssl_self_test32 /system/bin/boringssl_self_test32
setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
- reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+ reboot_on_failure reboot,boringssl-self-check-failed
service boringssl_self_test64 /system/bin/boringssl_self_test64
setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
- reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+ reboot_on_failure reboot,boringssl-self-check-failed
service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32
setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
- reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+ reboot_on_failure reboot,boringssl-self-check-failed
service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64
setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
- reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+ reboot_on_failure reboot,boringssl-self-check-failed
on init
sysclktz 0
@@ -154,6 +154,14 @@
mkdir /mnt/user/0/self 0755 root root
mkdir /mnt/user/0/emulated 0755 root root
mkdir /mnt/user/0/emulated/0 0755 root root
+
+ # Prepare directories for pass through processes
+ mkdir /mnt/pass_through 0755 root root
+ mkdir /mnt/pass_through/0 0755 root root
+ mkdir /mnt/pass_through/0/self 0755 root root
+ mkdir /mnt/pass_through/0/emulated 0755 root root
+ mkdir /mnt/pass_through/0/emulated/0 0755 root root
+
mkdir /mnt/expand 0771 system system
mkdir /mnt/appfuse 0711 root root
@@ -678,6 +686,8 @@
# Mount default storage into root namespace
mount none /mnt/user/0 /storage bind rec
mount none none /storage slave rec
+ # Bootstrap the emulated volume for the pass_through directory for user 0
+ mount none /data/media /mnt/pass_through/0/emulated bind rec
on zygote-start && property:persist.sys.fuse=false
# Mount default storage into root namespace
mount none /mnt/runtime/default /storage bind rec
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 9d131dc..c4b8e4e 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -128,7 +128,7 @@
deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
$(vndkprivate_libraries_file)
ifeq ($(check_backward_compatibility),true)
-deps += $(compatibility_check_script)
+deps += $(compatibility_check_script) $(wildcard prebuilts/vndk/*/*/configs/ld.config.*.txt)
endif
ifeq ($(my_vndk_use_core_variant),true)
$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE := $(vndk_using_core_variant_libraries_file)