Merge "Add ANDROID_RUNTIME_ROOT environment variable"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c47230f..f9c3b4a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,30 @@
"presubmit": [
{
"name": "adbd_test"
+ },
+ {
+ "name": "debuggerd_test"
+ },
+ {
+ "name": "init_tests"
+ },
+ {
+ "name": "libbase_test"
+ },
+ {
+ "name": "libprocinfo_test"
+ },
+ {
+ "name": "memunreachable_test"
+ },
+ {
+ "name": "memunreachable_binder_test"
+ },
+ {
+ "name": "propertyinfoserializer_tests"
+ },
+ {
+ "name": "ziparchive-tests"
}
]
}
diff --git a/adb/Android.bp b/adb/Android.bp
index e994075..ae8e386 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -25,7 +25,6 @@
"-Wvla",
],
rtti: true,
- cpp_std: "gnu++17",
use_version_lib: true,
@@ -72,7 +71,7 @@
"-DUNICODE=1",
"-D_UNICODE=1",
- // -std=gnu++11 doesn't set _GNU_SOURCE on Windows.
+ // Unlike on Linux, -std=gnu++ doesn't set _GNU_SOURCE on Windows.
"-D_GNU_SOURCE",
// MinGW hides some things behind _POSIX_SOURCE.
diff --git a/adb/NOTICE b/adb/NOTICE
index ff47c95..9ffcc08 100644
--- a/adb/NOTICE
+++ b/adb/NOTICE
@@ -189,63 +189,3 @@
END OF TERMS AND CONDITIONS
-------------------------------------------------------------
-libwinpthread license:
-------------------------------------------------------------
-Copyright (c) 2011 mingw-w64 project
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-
-/*
- * Parts of this library are derived by:
- *
- * Posix Threads library for Microsoft Windows
- *
- * Use at own risk, there is no implied warranty to this code.
- * It uses undocumented features of Microsoft Windows that can change
- * at any time in the future.
- *
- * (C) 2010 Lockless Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * * Neither the name of Lockless Inc. nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 715e04f..2fc8478 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -36,6 +36,7 @@
void adb_auth_init();
int adb_auth_keygen(const char* filename);
+int adb_auth_pubkey(const char* filename);
std::string adb_auth_get_userkey();
std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 71c19b8..bcb829b 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -43,6 +43,7 @@
#include "adb.h"
#include "adb_auth.h"
+#include "adb_io.h"
#include "adb_utils.h"
#include "sysdeps.h"
#include "transport.h"
@@ -52,30 +53,7 @@
*new std::map<std::string, std::shared_ptr<RSA>>;
static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
-static std::string get_user_info() {
- LOG(INFO) << "get_user_info...";
-
- std::string hostname;
- if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
- char buf[64];
- if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
- if (hostname.empty()) hostname = "unknown";
-
- std::string username;
- if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
- if (username.empty() && getlogin()) username = getlogin();
-#endif
- if (username.empty()) hostname = "unknown";
-
- return " " + username + "@" + hostname;
-}
-
-static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
- LOG(INFO) << "write_public_keyfile...";
-
+static bool calculate_public_key(std::string* out, RSA* private_key) {
uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
LOG(ERROR) << "Failed to convert to public key";
@@ -88,20 +66,10 @@
return false;
}
- std::string content;
- content.resize(expected_length);
- size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(&content[0]), binary_key_data,
+ out->resize(expected_length);
+ size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
sizeof(binary_key_data));
- content.resize(actual_length);
-
- content += get_user_info();
-
- std::string path(private_key_path + ".pub");
- if (!android::base::WriteStringToFile(content, path)) {
- PLOG(ERROR) << "Failed to write public key to '" << path << "'";
- return false;
- }
-
+ out->resize(actual_length);
return true;
}
@@ -140,11 +108,6 @@
goto out;
}
- if (!write_public_keyfile(rsa, file)) {
- D("Failed to write public key");
- goto out;
- }
-
ret = 1;
out:
@@ -170,36 +133,41 @@
return result;
}
-static bool read_key_file(const std::string& file) {
- LOG(INFO) << "read_key_file '" << file << "'...";
-
+static std::shared_ptr<RSA> read_key_file(const std::string& file) {
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose);
if (!fp) {
PLOG(ERROR) << "Failed to open '" << file << "'";
- return false;
+ return nullptr;
}
RSA* key = RSA_new();
if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
LOG(ERROR) << "Failed to read key";
RSA_free(key);
+ return nullptr;
+ }
+
+ return std::shared_ptr<RSA>(key, RSA_free);
+}
+
+static bool load_key(const std::string& file) {
+ std::shared_ptr<RSA> key = read_key_file(file);
+ if (!key) {
return false;
}
std::lock_guard<std::mutex> lock(g_keys_mutex);
- std::string fingerprint = hash_key(key);
+ std::string fingerprint = hash_key(key.get());
if (g_keys.find(fingerprint) != g_keys.end()) {
LOG(INFO) << "ignoring already-loaded key: " << file;
- RSA_free(key);
} else {
- g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free);
+ g_keys[fingerprint] = std::move(key);
}
-
return true;
}
-static bool read_keys(const std::string& path, bool allow_dir = true) {
- LOG(INFO) << "read_keys '" << path << "'...";
+static bool load_keys(const std::string& path, bool allow_dir = true) {
+ LOG(INFO) << "load_keys '" << path << "'...";
struct stat st;
if (stat(path.c_str(), &st) != 0) {
@@ -208,7 +176,7 @@
}
if (S_ISREG(st.st_mode)) {
- return read_key_file(path);
+ return load_key(path);
} else if (S_ISDIR(st.st_mode)) {
if (!allow_dir) {
// inotify isn't recursive. It would break expectations to load keys in nested
@@ -237,7 +205,7 @@
continue;
}
- result |= read_key_file((path + OS_PATH_SEPARATOR + name));
+ result |= load_key((path + OS_PATH_SEPARATOR + name));
}
return result;
}
@@ -250,7 +218,7 @@
return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
}
-static bool get_user_key() {
+static bool generate_userkey() {
std::string path = get_user_key_path();
if (path.empty()) {
PLOG(ERROR) << "Error getting user key filename";
@@ -266,7 +234,7 @@
}
}
- return read_key_file(path);
+ return load_key(path);
}
static std::set<std::string> get_vendor_keys() {
@@ -320,26 +288,42 @@
return result;
}
+static bool pubkey_from_privkey(std::string* out, const std::string& path) {
+ std::shared_ptr<RSA> privkey = read_key_file(path);
+ if (!privkey) {
+ return false;
+ }
+ return calculate_public_key(out, privkey.get());
+}
+
std::string adb_auth_get_userkey() {
std::string path = get_user_key_path();
if (path.empty()) {
PLOG(ERROR) << "Error getting user key filename";
return "";
}
- path += ".pub";
- std::string content;
- if (!android::base::ReadFileToString(path, &content)) {
- PLOG(ERROR) << "Can't load '" << path << "'";
+ std::string result;
+ if (!pubkey_from_privkey(&result, path)) {
return "";
}
- return content;
+ return result;
}
int adb_auth_keygen(const char* filename) {
return (generate_key(filename) == 0);
}
+int adb_auth_pubkey(const char* filename) {
+ std::string pubkey;
+ if (!pubkey_from_privkey(&pubkey, filename)) {
+ return 1;
+ }
+ pubkey.push_back('\n');
+
+ return WriteFdExactly(STDOUT_FILENO, pubkey.data(), pubkey.size()) ? 0 : 1;
+}
+
#if defined(__linux__)
static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) {
LOG(INFO) << "adb_auth_inotify_update called";
@@ -380,7 +364,7 @@
LOG(INFO) << "ignoring new directory at '" << path << "'";
} else {
LOG(INFO) << "observed new file at '" << path << "'";
- read_keys(path, false);
+ load_keys(path, false);
}
} else {
LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex
@@ -420,8 +404,8 @@
void adb_auth_init() {
LOG(INFO) << "adb_auth_init...";
- if (!get_user_key()) {
- LOG(ERROR) << "Failed to get user key";
+ if (!generate_userkey()) {
+ LOG(ERROR) << "Failed to generate user key";
return;
}
@@ -432,7 +416,7 @@
#endif
for (const std::string& path : key_paths) {
- read_keys(path.c_str());
+ load_keys(path.c_str());
}
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index b5bed28..c11052d 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -185,7 +185,6 @@
" enable-verity re-enable dm-verity checking on userdebug builds\n"
" keygen FILE\n"
" generate adb public/private key; private key stored in FILE,\n"
- " public key stored in FILE.pub (existing files overwritten)\n"
"\n"
"scripting:\n"
" wait-for[-TRANSPORT]-STATE\n"
@@ -1756,14 +1755,14 @@
// Always print key generation information for keygen command.
adb_trace_enable(AUTH);
return adb_auth_keygen(argv[1]);
- }
- else if (!strcmp(argv[0], "jdwp")) {
+ } else if (!strcmp(argv[0], "pubkey")) {
+ if (argc != 2) error_exit("pubkey requires an argument");
+ return adb_auth_pubkey(argv[1]);
+ } else if (!strcmp(argv[0], "jdwp")) {
return adb_connect_command("jdwp");
- }
- else if (!strcmp(argv[0], "track-jdwp")) {
+ } else if (!strcmp(argv[0], "track-jdwp")) {
return adb_connect_command("track-jdwp");
- }
- else if (!strcmp(argv[0], "track-devices")) {
+ } else if (!strcmp(argv[0], "track-devices")) {
return adb_connect_command("host:track-devices");
} else if (!strcmp(argv[0], "raw")) {
if (argc != 2) {
@@ -1772,13 +1771,11 @@
return adb_connect_command(argv[1]);
}
-
/* "adb /?" is a common idiom under Windows */
else if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
help();
return 0;
- }
- else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
+ } else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
fprintf(stdout, "%s", adb_version().c_str());
return 0;
} else if (!strcmp(argv[0], "features")) {
diff --git a/adb/fastdeploy/OWNERS b/adb/fastdeploy/OWNERS
new file mode 100644
index 0000000..d145834
--- /dev/null
+++ b/adb/fastdeploy/OWNERS
@@ -0,0 +1 @@
+idries@google.com
diff --git a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
index cd6f168..17845e2 100644
--- a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
+++ b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
@@ -142,14 +142,21 @@
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String packagePrefix = "package:";
+ String packageSuffix = "=" + packageName;
String line = "";
while ((line = reader.readLine()) != null) {
- int packageIndex = line.indexOf(packagePrefix);
- int equalsIndex = line.indexOf("=" + packageName);
- return new File(line.substring(packageIndex + packagePrefix.length(), equalsIndex));
+ if (line.endsWith(packageSuffix)) {
+ int packageIndex = line.indexOf(packagePrefix);
+ if (packageIndex == -1) {
+ throw new IOException("error reading package list");
+ }
+ int equalsIndex = line.lastIndexOf(packageSuffix);
+ String fileName =
+ line.substring(packageIndex + packagePrefix.length(), equalsIndex);
+ return new File(fileName);
+ }
}
-
- return null;
+ throw new IOException("package not found");
}
private static void extractMetaData(String packageName) throws IOException {
diff --git a/adb/fastdeploy/deploypatchgenerator/src/com/android/fastdeploy/DeployPatchGenerator.java b/adb/fastdeploy/deploypatchgenerator/src/com/android/fastdeploy/DeployPatchGenerator.java
index 5577364..24b2eab 100644
--- a/adb/fastdeploy/deploypatchgenerator/src/com/android/fastdeploy/DeployPatchGenerator.java
+++ b/adb/fastdeploy/deploypatchgenerator/src/com/android/fastdeploy/DeployPatchGenerator.java
@@ -61,22 +61,22 @@
File hostFile = new File(apkPath);
List<APKEntry> deviceZipEntries = getMetadataFromFile(deviceMetadataPath);
+ System.err.println("Device Entries (" + deviceZipEntries.size() + ")");
if (verbose) {
sb = new StringBuilder();
for (APKEntry entry : deviceZipEntries) {
APKEntryToString(entry, sb);
}
- System.err.println("Device Entries (" + deviceZipEntries.size() + ")");
System.err.println(sb.toString());
}
List<APKEntry> hostFileEntries = PatchUtils.getAPKMetaData(hostFile).getEntriesList();
+ System.err.println("Host Entries (" + hostFileEntries.size() + ")");
if (verbose) {
sb = new StringBuilder();
for (APKEntry entry : hostFileEntries) {
APKEntryToString(entry, sb);
}
- System.err.println("Host Entries (" + hostFileEntries.size() + ")");
System.err.println(sb.toString());
}
@@ -130,7 +130,8 @@
for (APKEntry deviceZipEntry : deviceZipEntries) {
for (APKEntry hostZipEntry : hostZipEntries) {
- if (deviceZipEntry.getCrc32() == hostZipEntry.getCrc32()) {
+ if (deviceZipEntry.getCrc32() == hostZipEntry.getCrc32() &&
+ deviceZipEntry.getFileName().equals(hostZipEntry.getFileName())) {
identicalContents.add(new SimpleEntry(deviceZipEntry, hostZipEntry));
}
}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index c2d4917..76a31ce 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1009,14 +1009,11 @@
const FeatureSet& supported_features() {
// Local static allocation to avoid global non-POD variables.
static const FeatureSet* features = new FeatureSet{
- kFeatureShell2, kFeatureCmd, kFeatureStat2, kFeatureFixedPushMkdir,
-#if ADB_HOST
- kFeatureApex
-#endif
- // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
- // to know about. Otherwise, the client can be stuck running an old
- // version of the server even after upgrading their copy of adb.
- // (http://b/24370690)
+ kFeatureShell2, kFeatureCmd, kFeatureStat2, kFeatureFixedPushMkdir, kFeatureApex
+ // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
+ // to know about. Otherwise, the client can be stuck running an old
+ // version of the server even after upgrading their copy of adb.
+ // (http://b/24370690)
};
return *features;
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 4e3879b..4e6c879 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -16,6 +16,7 @@
#pragma once
+#include <dirent.h>
#include <fcntl.h>
#if !defined(_WIN32)
@@ -231,3 +232,13 @@
template <typename T>
int close(const android::base::unique_fd_impl<T>&)
__attribute__((__unavailable__("close called on unique_fd")));
+
+template <typename T>
+FILE* fdopen(const android::base::unique_fd_impl<T>&, const char* mode)
+ __attribute__((__unavailable__("fdopen takes ownership of the fd passed in; either dup the "
+ "unique_fd, or use android::base::Fdopen to pass ownership")));
+
+template <typename T>
+DIR* fdopendir(const android::base::unique_fd_impl<T>&) __attribute__((
+ __unavailable__("fdopendir takes ownership of the fd passed in; either dup the "
+ "unique_fd, or use android::base::Fdopendir to pass ownership")));
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 03b3287..d9fae52 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -9,7 +9,6 @@
"-Wno-nullability-completeness",
"-Os",
],
- cpp_std: "gnu++17",
local_include_dirs: ["include"],
}
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 577e336..d79d20b 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -348,8 +348,16 @@
return vm_pid;
}
+static void InstallSigPipeHandler() {
+ struct sigaction action = {};
+ action.sa_handler = SIG_IGN;
+ action.sa_flags = SA_RESTART;
+ sigaction(SIGPIPE, &action, nullptr);
+}
+
int main(int argc, char** argv) {
DefuseSignalHandlers();
+ InstallSigPipeHandler();
atrace_begin(ATRACE_TAG, "before reparent");
pid_t target_process = getppid();
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 0b8a936..1179263 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -78,7 +78,7 @@
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
-static void dump_probable_cause(log_t* log, const siginfo_t* si) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
std::string cause;
if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -94,6 +94,14 @@
} else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
cause = "call to kuser_cmpxchg64";
}
+ } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
+ for (auto it = map->begin(); it != map->end(); ++it) {
+ const backtrace_map_t* entry = *it;
+ if (si->si_addr >= reinterpret_cast<void*>(entry->start) &&
+ si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) {
+ cause = "execute-only (no-read) memory access error; likely due to data in .text.";
+ }
+ }
} else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
si->si_syscall);
@@ -125,8 +133,6 @@
_LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
-
- dump_probable_cause(log, thread_info.siginfo);
}
static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
@@ -426,6 +432,7 @@
if (thread_info.siginfo) {
dump_signal_info(log, thread_info, process_memory);
+ dump_probable_cause(log, thread_info.siginfo, map);
}
if (primary_thread) {
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 8006c41..ead2105 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -144,8 +144,6 @@
static_libs: [
"libhealthhalutils",
],
-
- cpp_std: "c++17",
}
cc_defaults {
@@ -212,7 +210,6 @@
name: "libfastboot",
defaults: ["fastboot_host_defaults"],
- cpp_std: "c++17",
srcs: [
"bootimg_utils.cpp",
"fastboot.cpp",
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 7b99884..fbba631 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -153,6 +153,7 @@
if (!FlashPartitionTable(super_name, *new_metadata.get())) {
return device->WriteFail("Unable to flash new partition table");
}
+ fs_mgr_overlayfs_teardown();
return device->WriteOkay("Successfully flashed partition table");
}
@@ -186,5 +187,6 @@
if (!UpdateAllPartitionMetadata(super_name, *new_metadata.get())) {
return device->WriteFail("Unable to write new partition table");
}
+ fs_mgr_overlayfs_teardown();
return device->WriteOkay("Successfully updated partition table");
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e066bff..fee0857 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -46,6 +46,7 @@
#include <chrono>
#include <functional>
#include <regex>
+#include <string>
#include <thread>
#include <utility>
#include <vector>
@@ -78,6 +79,7 @@
using android::base::Split;
using android::base::Trim;
using android::base::unique_fd;
+using namespace std::string_literals;
static const char* serial = nullptr;
@@ -162,9 +164,17 @@
// clang-format on
};
-static std::string find_item_given_name(const std::string& img_name) {
+static char* get_android_product_out() {
char* dir = getenv("ANDROID_PRODUCT_OUT");
if (dir == nullptr || dir[0] == '\0') {
+ return nullptr;
+ }
+ return dir;
+}
+
+static std::string find_item_given_name(const std::string& img_name) {
+ char* dir = get_android_product_out();
+ if (!dir) {
die("ANDROID_PRODUCT_OUT not set");
}
return std::string(dir) + "/" + img_name;
@@ -1098,6 +1108,14 @@
return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
}
+static bool is_retrofit_device() {
+ std::string value;
+ if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) {
+ return false;
+ }
+ return android::base::StartsWith(value, "system_");
+}
+
static void do_flash(const char* pname, const char* fname) {
struct fastboot_buffer buf;
@@ -1311,6 +1329,19 @@
command += ":wipe";
}
fb->RawCommand(command, "Updating super partition");
+
+ // Retrofit devices have two super partitions, named super_a and super_b.
+ // On these devices, secondary slots must be flashed as physical
+ // partitions (otherwise they would not mount on first boot). To enforce
+ // this, we delete any logical partitions for the "other" slot.
+ if (is_retrofit_device()) {
+ for (const auto& [image, slot] : os_images_) {
+ std::string partition_name = image->part_name + "_"s + slot;
+ if (image->IsSecondary() && is_logical(partition_name)) {
+ fb->DeletePartition(partition_name);
+ }
+ }
+ }
}
class ZipImageSource final : public ImageSource {
@@ -1466,15 +1497,13 @@
fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str());
return;
}
- fprintf(stderr, "Formatting is not supported for file system with type '%s'.\n",
- partition_type.c_str());
- return;
+ die("Formatting is not supported for file system with type '%s'.",
+ partition_type.c_str());
}
int64_t size;
if (!android::base::ParseInt(partition_size, &size)) {
- fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
- return;
+ die("Couldn't parse partition size '%s'.", partition_size.c_str());
}
unsigned eraseBlkSize, logicalBlkSize;
@@ -1484,17 +1513,14 @@
if (fs_generator_generate(gen, output.path, size, initial_dir,
eraseBlkSize, logicalBlkSize)) {
die("Cannot generate image for %s", partition.c_str());
- return;
}
fd.reset(open(output.path, O_RDONLY));
if (fd == -1) {
- fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
- return;
+ die("Cannot open generated image: %s", strerror(errno));
}
if (!load_buf_fd(fd.release(), &buf)) {
- fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
- return;
+ die("Cannot read image: %s", strerror(errno));
}
flash_buf(partition, &buf);
return;
@@ -1505,9 +1531,15 @@
if (errMsg) fprintf(stderr, "%s", errMsg);
}
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+ if (!skip_if_not_supported) {
+ die("Command failed");
+ }
}
static bool should_flash_in_userspace(const std::string& partition_name) {
+ if (!get_android_product_out()) {
+ return false;
+ }
auto path = find_item_given_name("super_empty.img");
if (path.empty()) {
return false;
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index fc6a16b..8c0aa6b 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -172,13 +172,8 @@
mkf2fs_args.push_back("-S");
std::string size_str = std::to_string(partSize);
mkf2fs_args.push_back(size_str.c_str());
- mkf2fs_args.push_back("-f");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("encrypt");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("quota");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("verity");
+ mkf2fs_args.push_back("-g");
+ mkf2fs_args.push_back("android");
mkf2fs_args.push_back(fileName);
mkf2fs_args.push_back(nullptr);
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 6c8a943..99231ac 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -25,9 +25,6 @@
"-Werror",
"-Wno-unused-variable",
],
- cppflags: [
- "-std=gnu++1z",
- ],
}
cc_library {
@@ -42,8 +39,6 @@
"fs_mgr.cpp",
"fs_mgr_format.cpp",
"fs_mgr_verity.cpp",
- "fs_mgr_avb.cpp",
- "fs_mgr_avb_ops.cpp",
"fs_mgr_dm_linear.cpp",
"fs_mgr_overlayfs.cpp",
"fs_mgr_vendor_overlay.cpp",
@@ -61,10 +56,12 @@
],
static_libs: [
"libavb",
+ "libfs_avb",
"libfstab",
"libdm",
],
export_static_lib_headers: [
+ "libfs_avb",
"libfstab",
"libdm",
],
@@ -104,3 +101,28 @@
export_include_dirs: ["include_fstab"],
header_libs: ["libbase_headers"],
}
+
+cc_library_static {
+ name: "libfs_avb",
+ defaults: ["fs_mgr_defaults"],
+ recovery_available: true,
+ export_include_dirs: ["libfs_avb/include"],
+ srcs: [
+ "libfs_avb/avb_ops.cpp",
+ "libfs_avb/fs_avb.cpp",
+ ],
+ static_libs: [
+ "libavb",
+ "libfstab",
+ "libdm",
+ ],
+ export_static_lib_headers: [
+ "libfstab",
+ ],
+ shared_libs: [
+ "libcrypto",
+ ],
+ header_libs: [
+ "libbase_headers",
+ ],
+}
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
new file mode 100644
index 0000000..d715d7b
--- /dev/null
+++ b/fs_mgr/README.overlayfs.md
@@ -0,0 +1,92 @@
+Android Overlayfs integration with adb remount
+==============================================
+
+Introduction
+------------
+
+Users working with userdebug or eng builds expect to be able to
+remount the system partition as read-write and then add or modify
+any number of files without reflashing the system image, which is
+understandably efficient for a development cycle.
+Limited memory systems that chose to use readonly filesystems like
+*squashfs*, or *Logical Resizable Android Partitions* which land
+system partition images right-sized, and with filesystem that have
+been deduped on the block level to compress the content; means that
+either a remount is not possible directly, or when done offers
+little or no utility because of remaining space limitations or
+support logistics.
+
+*Overlayfs* comes to the rescue for these debug scenarios, and logic
+will _automatically_ setup backing storage for a writable filesystem
+as an upper reference, and mount overtop the lower. These actions
+will be performed in the **adb disable-verity** and **adb remount**
+requests.
+
+Operations
+----------
+
+### Cookbook
+
+The typical action to utilize the remount facility is:
+
+ $ adb root
+ $ adb disable-verity
+ $ adb reboot
+ $ adb wait-for-device
+ $ adb root
+ $ adb remount
+
+Followed by one of the following:
+
+ $ adb stop
+ $ adb sync
+ $ adb start
+ $ adb reboot
+
+*or*
+
+ $ adb push <source> <destination>
+ $ adb reboot
+
+Note that the sequence above:
+
+ $ adb disable-verity
+ $ adb reboot
+
+can be replaced with:
+
+ $ adb reboot -R
+
+which will not reboot if everything is already prepared and ready
+to go.
+
+None of this changes if *overlayfs* needs to be engaged.
+The decisions whether to use traditional direct filesystem remount,
+or one wrapped by *overlayfs* is automatically determined based on
+a probe of the filesystem types and space remaining.
+
+### Backing Storage
+
+When *overlayfs* logic is feasible, it will use either the
+**/cache/overlay/** directory for non-A/B devices, or the
+**/mnt/scratch/overlay** directory for A/B devices that have
+access to *Logical Resizeable Android Partitions*.
+The backing store is used as soon as possible in the boot
+process and can occur at first stage init, or at the
+mount_all init rc commands.
+
+This early as possible attachment of *overlayfs* means that
+*sepolicy* or *init* itself can also be pushed and used after
+the exec phases that accompany each stage.
+
+Caveats
+-------
+
+- Space used in the backing storage is on a file by file basis
+ and will require more space than if updated in place.
+- Kernel must have CONFIG_OVERLAY_FS=y and will need to be patched
+ with "*overlayfs: override_creds=off option bypass creator_cred*"
+ if higher than 4.6.
+- *adb enable-verity* will free up overlayfs and as a bonus the
+ device will be reverted pristine to before any content was updated.
+- File bugs or submit fixes for review.
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8e57e1e..6f863ad 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -20,6 +20,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
@@ -34,6 +35,7 @@
#include <unistd.h>
#include <functional>
+#include <map>
#include <memory>
#include <string>
#include <thread>
@@ -53,6 +55,7 @@
#include <ext4_utils/ext4_sb.h>
#include <ext4_utils/ext4_utils.h>
#include <ext4_utils/wipe.h>
+#include <fs_avb/fs_avb.h>
#include <fs_mgr_overlayfs.h>
#include <libdm/dm.h>
#include <liblp/metadata_format.h>
@@ -62,7 +65,6 @@
#include <log/log_properties.h>
#include <logwrap/logwrap.h>
-#include "fs_mgr_avb.h"
#include "fs_mgr_priv.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
@@ -80,8 +82,12 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+using android::base::Realpath;
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
+using android::fs_mgr::AvbHandle;
+using android::fs_mgr::AvbHashtreeResult;
+using android::fs_mgr::AvbUniquePtr;
// record fs stat
enum FsStatFlags {
@@ -95,7 +101,7 @@
FS_STAT_FULL_MOUNT_FAILED = 0x0100,
FS_STAT_E2FSCK_FAILED = 0x0200,
FS_STAT_E2FSCK_FS_FIXED = 0x0400,
- FS_STAT_EXT4_INVALID_MAGIC = 0x0800,
+ FS_STAT_INVALID_MAGIC = 0x0800,
FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000,
@@ -138,6 +144,18 @@
return fs_type == "ext4" || fs_type == "ext3" || fs_type == "ext2";
}
+static bool is_f2fs(const std::string& fs_type) {
+ return fs_type == "f2fs";
+}
+
+static std::string realpath(const char* blk_device) {
+ std::string real_path;
+ if (!Realpath(blk_device, &real_path)) {
+ real_path = blk_device;
+ }
+ return real_path;
+}
+
static bool should_force_check(int fs_stat) {
return fs_stat &
(FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
@@ -155,11 +173,12 @@
const char* e2fsck_argv[] = {E2FSCK_BIN, "-y", blk_device};
const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device};
+ if (*fs_stat & FS_STAT_INVALID_MAGIC) { // will fail, so do not try
+ return;
+ }
+
/* Check for the types of filesystems we know how to check */
if (is_extfs(fs_type)) {
- if (*fs_stat & FS_STAT_EXT4_INVALID_MAGIC) { // will fail, so do not try
- return;
- }
/*
* First try to mount and unmount the filesystem. We do this because
* the kernel is more efficient than e2fsck in running the journal and
@@ -209,10 +228,10 @@
* (e.g. recent SDK system images). Detect these and skip the check.
*/
if (access(E2FSCK_BIN, X_OK)) {
- LINFO << "Not running " << E2FSCK_BIN << " on " << blk_device
+ LINFO << "Not running " << E2FSCK_BIN << " on " << realpath(blk_device)
<< " (executable not in system image)";
} else {
- LINFO << "Running " << E2FSCK_BIN << " on " << blk_device;
+ LINFO << "Running " << E2FSCK_BIN << " on " << realpath(blk_device);
if (should_force_check(*fs_stat)) {
ret = android_fork_execvp_ext(
ARRAY_SIZE(e2fsck_forced_argv), const_cast<char**>(e2fsck_forced_argv), &status,
@@ -232,13 +251,9 @@
*fs_stat |= FS_STAT_E2FSCK_FS_FIXED;
}
}
- } else if (!strcmp(fs_type, "f2fs")) {
- const char *f2fs_fsck_argv[] = {
- F2FS_FSCK_BIN,
- "-a",
- blk_device
- };
- LINFO << "Running " << F2FS_FSCK_BIN << " -a " << blk_device;
+ } else if (is_f2fs(fs_type)) {
+ const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN, "-a", blk_device};
+ LINFO << "Running " << F2FS_FSCK_BIN << " -a " << realpath(blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv),
const_cast<char **>(f2fs_fsck_argv),
@@ -272,7 +287,7 @@
}
// Read the primary superblock from an ext4 filesystem. On failure return
-// false. If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC.
+// false. If it's not an ext4 filesystem, also set FS_STAT_INVALID_MAGIC.
static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
@@ -289,7 +304,7 @@
if (!is_ext4_superblock_valid(sb)) {
LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
// not a valid fs, tune2fs, fsck, and mount will all fail.
- *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
+ *fs_stat |= FS_STAT_INVALID_MAGIC;
return false;
}
*fs_stat |= FS_STAT_IS_EXT4;
@@ -417,6 +432,36 @@
}
}
+// Read the primary superblock from an f2fs filesystem. On failure return
+// false. If it's not an f2fs filesystem, also set FS_STAT_INVALID_MAGIC.
+#define F2FS_BLKSIZE 4096
+#define F2FS_SUPER_OFFSET 1024
+static bool read_f2fs_superblock(const char* blk_device, int* fs_stat) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
+ __le32 sb1, sb2;
+
+ if (fd < 0) {
+ PERROR << "Failed to open '" << blk_device << "'";
+ return false;
+ }
+
+ if (pread(fd, &sb1, sizeof(sb1), F2FS_SUPER_OFFSET) != sizeof(sb1)) {
+ PERROR << "Can't read '" << blk_device << "' superblock1";
+ return false;
+ }
+ if (pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET) != sizeof(sb2)) {
+ PERROR << "Can't read '" << blk_device << "' superblock2";
+ return false;
+ }
+
+ if (sb1 != cpu_to_le32(F2FS_SUPER_MAGIC) && sb2 != cpu_to_le32(F2FS_SUPER_MAGIC)) {
+ LINFO << "Invalid f2fs superblock on '" << blk_device << "'";
+ *fs_stat |= FS_STAT_INVALID_MAGIC;
+ return false;
+ }
+ return true;
+}
+
//
// Prepare the filesystem on the given block device to be mounted.
//
@@ -446,6 +491,10 @@
} else {
return fs_stat;
}
+ } else if (is_f2fs(rec->fs_type)) {
+ if (!read_f2fs_superblock(blk_device, &fs_stat)) {
+ return fs_stat;
+ }
}
if ((rec->fs_mgr_flags & MF_CHECK) ||
@@ -612,9 +661,10 @@
}
int fs_stat = prepare_fs_for_mount(fstab->recs[i].blk_device, &fstab->recs[i]);
- if (fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {
- LERROR << __FUNCTION__ << "(): skipping mount, invalid ext4, mountpoint="
- << fstab->recs[i].mount_point << " rec[" << i
+ if (fs_stat & FS_STAT_INVALID_MAGIC) {
+ LERROR << __FUNCTION__ << "(): skipping mount due to invalid magic, mountpoint="
+ << fstab->recs[i].mount_point
+ << " blk_dev=" << realpath(fstab->recs[i].blk_device) << " rec[" << i
<< "].fs_type=" << fstab->recs[i].fs_type;
mount_errno = EINVAL; // continue bootup for FDE
continue;
@@ -906,7 +956,7 @@
private:
bool UpdateCheckpointPartition(struct fstab_rec* rec) {
if (fs_mgr_is_checkpoint_fs(rec)) {
- if (!strcmp(rec->fs_type, "f2fs")) {
+ if (is_f2fs(rec->fs_type)) {
std::string opts(rec->fs_options);
opts += ",checkpoint=disable";
@@ -973,7 +1023,7 @@
int mount_errno = 0;
int attempted_idx = -1;
CheckpointManager checkpoint_manager;
- FsManagerAvbUniquePtr avb_handle(nullptr);
+ AvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return FS_MGR_MNTALL_FAIL;
@@ -997,7 +1047,7 @@
/* Skip mounting the root partition, as it will already have been mounted */
if (!strcmp(fstab->recs[i].mount_point, "/") ||
!strcmp(fstab->recs[i].mount_point, "/system")) {
- if ((fstab->recs[i].fs_mgr_flags & MS_RDONLY) != 0) {
+ if ((fstab->recs[i].flags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(fstab->recs[i].blk_device);
}
continue;
@@ -1031,14 +1081,14 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open();
+ avb_handle = AvbHandle::Open();
if (!avb_handle) {
- LERROR << "Failed to open FsManagerAvbHandle";
+ LERROR << "Failed to open AvbHandle";
return FS_MGR_MNTALL_FAIL;
}
}
if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
- SetUpAvbHashtreeResult::kFail) {
+ AvbHashtreeResult::kFail) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -1099,10 +1149,9 @@
* at two different lines in the fstab. Use the top one for formatting
* as that is the preferred one.
*/
- LERROR << __FUNCTION__ << "(): " << fstab->recs[top_idx].blk_device
- << " is wiped and " << fstab->recs[top_idx].mount_point
- << " " << fstab->recs[top_idx].fs_type
- << " is formattable. Format it.";
+ LERROR << __FUNCTION__ << "(): " << realpath(fstab->recs[top_idx].blk_device)
+ << " is wiped and " << fstab->recs[top_idx].mount_point << " "
+ << fstab->recs[top_idx].fs_type << " is formattable. Format it.";
checkpoint_manager.Revert(&fstab->recs[top_idx]);
@@ -1232,7 +1281,7 @@
int first_mount_errno = 0;
char* mount_point;
CheckpointManager checkpoint_manager(needs_checkpoint);
- FsManagerAvbUniquePtr avb_handle(nullptr);
+ AvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return FS_MGR_DOMNT_FAILED;
@@ -1275,14 +1324,14 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open();
+ avb_handle = AvbHandle::Open();
if (!avb_handle) {
- LERROR << "Failed to open FsManagerAvbHandle";
+ LERROR << "Failed to open AvbHandle";
return FS_MGR_DOMNT_FAILED;
}
}
if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
- SetUpAvbHashtreeResult::kFail) {
+ AvbHashtreeResult::kFail) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -1410,7 +1459,7 @@
ret = -1;
continue;
}
- fprintf(zram_fp.get(), "%u\n", fstab->recs[i].zram_size);
+ fprintf(zram_fp.get(), "%" PRId64 "\n", fstab->recs[i].zram_size);
}
if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
@@ -1603,9 +1652,6 @@
} else if (slot == -1) {
suffix = fs_mgr_get_slot_suffix();
}
- if (suffix.empty()) {
- LFATAL << "Super partition name can only be overridden on A/B devices.";
- }
return super_partition + suffix;
}
return LP_METADATA_DEFAULT_PARTITION_NAME;
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 845cca9..0983663 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -117,12 +117,7 @@
// clang-format off
const char* const args[] = {
"/system/bin/make_f2fs",
- "-d1",
- "-f",
- "-O", "encrypt",
- "-O", "quota",
- "-O", "verity",
- "-w", "4096",
+ "-g", "android",
fs_blkdev,
size_str.c_str(),
nullptr
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index e89c91c..31b0944 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -38,26 +38,26 @@
const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
struct fs_mgr_flag_values {
- char *key_loc;
- char* key_dir;
- char *verity_loc;
- char *sysfs_path;
- long long part_length;
- char *label;
- int partnum;
- int swap_prio;
- int max_comp_streams;
- unsigned int zram_size;
- uint64_t reserved_size;
- unsigned int file_contents_mode;
- unsigned int file_names_mode;
- unsigned int erase_blk_size;
- unsigned int logical_blk_size;
+ std::string key_loc;
+ std::string key_dir;
+ std::string verity_loc;
+ std::string sysfs_path;
+ off64_t part_length = 0;
+ std::string label;
+ int partnum = -1;
+ int swap_prio = -1;
+ int max_comp_streams = 0;
+ off64_t zram_size = 0;
+ off64_t reserved_size = 0;
+ int file_contents_mode = 0;
+ int file_names_mode = 0;
+ off64_t erase_blk_size = 0;
+ off64_t logical_blk_size = 0;
};
struct flag_list {
const char *name;
- unsigned int flag;
+ int flag;
};
static struct flag_list mount_flags[] = {
@@ -133,9 +133,8 @@
{0, 0},
};
-static unsigned int encryption_mode_to_flag(const struct flag_list *list,
- const char *mode, const char *type)
-{
+static int encryption_mode_to_flag(const struct flag_list* list, const char* mode,
+ const char* type) {
const struct flag_list *j;
for (j = list; j->name; ++j) {
@@ -147,9 +146,7 @@
return 0;
}
-static const char *flag_to_encryption_mode(const struct flag_list *list,
- unsigned int flag)
-{
+static const char* flag_to_encryption_mode(const struct flag_list* list, int flag) {
const struct flag_list *j;
for (j = list; j->name; ++j) {
@@ -160,9 +157,8 @@
return nullptr;
}
-static uint64_t calculate_zram_size(unsigned int percentage)
-{
- uint64_t total;
+static off64_t calculate_zram_size(unsigned int percentage) {
+ off64_t total;
total = sysconf(_SC_PHYS_PAGES);
total *= percentage;
@@ -173,10 +169,9 @@
return total;
}
-static uint64_t parse_size(const char *arg)
-{
+static off64_t parse_size(const char* arg) {
char *endptr;
- uint64_t size = strtoull(arg, &endptr, 10);
+ off64_t size = strtoll(arg, &endptr, 10);
if (*endptr == 'k' || *endptr == 'K')
size *= 1024LL;
else if (*endptr == 'm' || *endptr == 'M')
@@ -214,14 +209,6 @@
char *p;
char *savep;
- /* initialize flag values. If we find a relevant flag, we'll
- * update the value */
- if (flag_vals) {
- memset(flag_vals, 0, sizeof(*flag_vals));
- flag_vals->partnum = -1;
- flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
- }
-
/* initialize fs_options to the null string */
if (fs_options && (fs_options_len > 0)) {
fs_options[0] = '\0';
@@ -247,22 +234,22 @@
/* The encryptable flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(arg);
+ flag_vals->key_loc = arg;
} else if (flag == MF_VERIFY) {
/* If the verify flag is followed by an = and the
* location for the verity state, get it and return it.
*/
- flag_vals->verity_loc = strdup(arg);
+ flag_vals->verity_loc = arg;
} else if (flag == MF_FORCECRYPT) {
/* The forceencrypt flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(arg);
+ flag_vals->key_loc = arg;
} else if (flag == MF_FORCEFDEORFBE) {
/* The forcefdeorfbe flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(arg);
+ flag_vals->key_loc = arg;
flag_vals->file_contents_mode = EM_AES_256_XTS;
flag_vals->file_names_mode = EM_AES_256_CTS;
} else if (flag == MF_FILEENCRYPTION) {
@@ -290,7 +277,7 @@
/* The metadata flag is followed by an = and the
* directory for the keys. Get it and return it.
*/
- flag_vals->key_dir = strdup(arg);
+ flag_vals->key_dir = arg;
} else if (flag == MF_LENGTH) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
@@ -307,8 +294,7 @@
auto label_end = strchr(label_start, ':');
if (label_end) {
- flag_vals->label = strndup(label_start,
- (int) (label_end - label_start));
+ flag_vals->label = std::string(label_start, (int)(label_end - label_start));
auto part_start = label_end + 1;
if (!strcmp(part_start, "auto")) {
flag_vals->partnum = -1;
@@ -339,7 +325,7 @@
* erase block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
- auto val = strtoul(arg, NULL, 0);
+ auto val = strtoll(arg, nullptr, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->erase_blk_size = val;
} else if (flag == MF_LOGICALBLKSIZE) {
@@ -347,12 +333,12 @@
* logical block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
- auto val = strtoul(arg, NULL, 0);
+ auto val = strtoll(arg, nullptr, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->logical_blk_size = val;
} else if (flag == MF_SYSFS) {
/* The path to trigger device gc by idle-maint of vold. */
- flag_vals->sysfs_path = strdup(arg);
+ flag_vals->sysfs_path = arg;
}
break;
}
@@ -509,49 +495,17 @@
return false;
}
-static struct fstab* fs_mgr_read_fstab_file(FILE* fstab_file, bool proc_mounts) {
- int cnt, entries;
+static bool fs_mgr_read_fstab_file(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
ssize_t len;
size_t alloc_len = 0;
char *line = NULL;
const char *delim = " \t";
char *save_ptr, *p;
- struct fstab *fstab = NULL;
+ Fstab fstab;
struct fs_mgr_flag_values flag_vals;
#define FS_OPTIONS_LEN 1024
char tmp_fs_options[FS_OPTIONS_LEN];
- entries = 0;
- while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
- /* if the last character is a newline, shorten the string by 1 byte */
- if (line[len - 1] == '\n') {
- line[len - 1] = '\0';
- }
- /* Skip any leading whitespace */
- p = line;
- while (isspace(*p)) {
- p++;
- }
- /* ignore comments or empty lines */
- if (*p == '#' || *p == '\0')
- continue;
- entries++;
- }
-
- if (!entries) {
- LERROR << "No entries found in fstab";
- goto err;
- }
-
- /* Allocate and init the fstab structure */
- fstab = static_cast<struct fstab *>(calloc(1, sizeof(struct fstab)));
- fstab->num_entries = entries;
- fstab->recs = static_cast<struct fstab_rec *>(
- calloc(fstab->num_entries, sizeof(struct fstab_rec)));
-
- fseek(fstab_file, 0, SEEK_SET);
-
- cnt = 0;
while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
/* if the last character is a newline, shorten the string by 1 byte */
if (line[len - 1] == '\n') {
@@ -567,46 +521,36 @@
if (*p == '#' || *p == '\0')
continue;
- /* If a non-comment entry is greater than the size we allocated, give an
- * error and quit. This can happen in the unlikely case the file changes
- * between the two reads.
- */
- if (cnt >= entries) {
- LERROR << "Tried to process more entries than counted";
- break;
- }
+ FstabEntry entry;
if (!(p = strtok_r(line, delim, &save_ptr))) {
LERROR << "Error parsing mount source";
goto err;
}
- fstab->recs[cnt].blk_device = strdup(p);
+ entry.blk_device = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_point";
goto err;
}
- fstab->recs[cnt].mount_point = strdup(p);
+ entry.mount_point = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_type";
goto err;
}
- fstab->recs[cnt].fs_type = strdup(p);
+ entry.fs_type = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_flags";
goto err;
}
tmp_fs_options[0] = '\0';
- fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
- tmp_fs_options, FS_OPTIONS_LEN);
+ entry.flags = parse_flags(p, mount_flags, NULL, tmp_fs_options, FS_OPTIONS_LEN);
/* fs_options are optional */
if (tmp_fs_options[0]) {
- fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
- } else {
- fstab->recs[cnt].fs_options = NULL;
+ entry.fs_options = tmp_fs_options;
}
// For /proc/mounts, ignore everything after mnt_freq and mnt_passno
@@ -616,78 +560,47 @@
LERROR << "Error parsing fs_mgr_options";
goto err;
}
- fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
- &flag_vals, NULL, 0);
- fstab->recs[cnt].key_loc = flag_vals.key_loc;
- fstab->recs[cnt].key_dir = flag_vals.key_dir;
- fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
- fstab->recs[cnt].length = flag_vals.part_length;
- fstab->recs[cnt].label = flag_vals.label;
- fstab->recs[cnt].partnum = flag_vals.partnum;
- fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
- fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
- fstab->recs[cnt].zram_size = flag_vals.zram_size;
- fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
- fstab->recs[cnt].file_contents_mode = flag_vals.file_contents_mode;
- fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode;
- fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
- fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
- fstab->recs[cnt].sysfs_path = flag_vals.sysfs_path;
- if (fstab->recs[cnt].fs_mgr_flags & MF_LOGICAL) {
- fstab->recs[cnt].logical_partition_name = strdup(fstab->recs[cnt].blk_device);
+ entry.fs_mgr_flags.val = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0);
+
+ entry.key_loc = std::move(flag_vals.key_loc);
+ entry.key_dir = std::move(flag_vals.key_dir);
+ entry.verity_loc = std::move(flag_vals.verity_loc);
+ entry.length = flag_vals.part_length;
+ entry.label = std::move(flag_vals.label);
+ entry.partnum = flag_vals.partnum;
+ entry.swap_prio = flag_vals.swap_prio;
+ entry.max_comp_streams = flag_vals.max_comp_streams;
+ entry.zram_size = flag_vals.zram_size;
+ entry.reserved_size = flag_vals.reserved_size;
+ entry.file_contents_mode = flag_vals.file_contents_mode;
+ entry.file_names_mode = flag_vals.file_names_mode;
+ entry.erase_blk_size = flag_vals.erase_blk_size;
+ entry.logical_blk_size = flag_vals.logical_blk_size;
+ entry.sysfs_path = std::move(flag_vals.sysfs_path);
+ if (entry.fs_mgr_flags.logical) {
+ entry.logical_partition_name = entry.blk_device;
}
- cnt++;
+ fstab.emplace_back(std::move(entry));
}
+
+ if (fstab.empty()) {
+ LERROR << "No entries found in fstab";
+ goto err;
+ }
+
/* If an A/B partition, modify block device to be the real block device */
- if (!fs_mgr_update_for_slotselect(fstab)) {
+ if (!fs_mgr_update_for_slotselect(&fstab)) {
LERROR << "Error updating for slotselect";
goto err;
}
free(line);
- return fstab;
+ *fstab_out = std::move(fstab);
+ return true;
err:
free(line);
- if (fstab)
- fs_mgr_free_fstab(fstab);
- return NULL;
-}
-
-/* merges fstab entries from both a and b, then returns the merged result.
- * note that the caller should only manage the return pointer without
- * doing further memory management for the two inputs, i.e. only need to
- * frees up memory of the return value without touching a and b. */
-static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
-{
- if (!a && !b) return nullptr;
- if (!a) return b;
- if (!b) return a;
-
- int total_entries = a->num_entries + b->num_entries;
- a->recs = static_cast<struct fstab_rec *>(realloc(
- a->recs, total_entries * (sizeof(struct fstab_rec))));
- if (!a->recs) {
- LERROR << __FUNCTION__ << "(): failed to allocate fstab recs";
- // If realloc() fails the original block is left untouched;
- // it is not freed or moved. So we have to free both a and b here.
- fs_mgr_free_fstab(a);
- fs_mgr_free_fstab(b);
- return nullptr;
- }
-
- for (int i = a->num_entries, j = 0; i < total_entries; i++, j++) {
- // Copy the structs by assignment.
- a->recs[i] = b->recs[j];
- }
-
- // We can't call fs_mgr_free_fstab because a->recs still references the
- // memory allocated by strdup.
- free(b->recs);
- free(b);
-
- a->num_entries = total_entries;
- return a;
+ return false;
}
/* Extracts <device>s from the by-name symlinks specified in a fstab:
@@ -700,11 +613,11 @@
* /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
* it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
*/
-static std::set<std::string> extract_boot_devices(const fstab& fstab) {
+static std::set<std::string> extract_boot_devices(const Fstab& fstab) {
std::set<std::string> boot_devices;
- for (int i = 0; i < fstab.num_entries; i++) {
- std::string blk_device(fstab.recs[i].blk_device);
+ for (const auto& entry : fstab) {
+ std::string blk_device = entry.blk_device;
// Skips blk_device that doesn't conform to the format.
if (!android::base::StartsWith(blk_device, "/dev/block") ||
android::base::StartsWith(blk_device, "/dev/block/by-name") ||
@@ -733,33 +646,36 @@
return boot_devices;
}
-struct fstab *fs_mgr_read_fstab(const char *fstab_path)
-{
- struct fstab *fstab;
-
- auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(fstab_path, "re"), fclose};
+bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
+ auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
if (!fstab_file) {
- PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
+ PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
+ return false;
+ }
+
+ if (!fs_mgr_read_fstab_file(fstab_file.get(), path == "/proc/mounts", fstab)) {
+ LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
+ return false;
+ }
+
+ return true;
+}
+
+struct fstab* fs_mgr_read_fstab(const char* fstab_path) {
+ Fstab fstab;
+ if (!ReadFstabFromFile(fstab_path, &fstab)) {
return nullptr;
}
- fstab = fs_mgr_read_fstab_file(fstab_file.get(), !strcmp("/proc/mounts", fstab_path));
- if (!fstab) {
- LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
- }
-
- return fstab;
+ return FstabToLegacyFstab(fstab);
}
-/* Returns fstab entries parsed from the device tree if they
- * exist
- */
-struct fstab *fs_mgr_read_fstab_dt()
-{
+// Returns fstab entries parsed from the device tree if they exist
+bool ReadFstabFromDt(Fstab* fstab) {
std::string fstab_buf = read_fstab_from_dt();
if (fstab_buf.empty()) {
LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
- return nullptr;
+ return false;
}
std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
@@ -767,16 +683,25 @@
fstab_buf.length(), "r"), fclose);
if (!fstab_file) {
PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+ return false;
+ }
+
+ if (!fs_mgr_read_fstab_file(fstab_file.get(), false, fstab)) {
+ LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
+ << std::endl << fstab_buf;
+ return false;
+ }
+
+ return true;
+}
+
+struct fstab* fs_mgr_read_fstab_dt() {
+ Fstab fstab;
+ if (!ReadFstabFromDt(&fstab)) {
return nullptr;
}
- struct fstab* fstab = fs_mgr_read_fstab_file(fstab_file.get(), false);
- if (!fstab) {
- LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
- << std::endl << fstab_buf;
- }
-
- return fstab;
+ return FstabToLegacyFstab(fstab);
}
/*
@@ -802,32 +727,42 @@
return std::string();
}
-/*
- * loads the fstab file and combines with fstab entries passed in from device tree.
- */
-struct fstab *fs_mgr_read_fstab_default()
-{
- std::string default_fstab;
+// Loads the fstab file and combines with fstab entries passed in from device tree.
+bool ReadDefaultFstab(Fstab* fstab) {
+ Fstab dt_fstab;
+ ReadFstabFromDt(&dt_fstab);
+ *fstab = std::move(dt_fstab);
+
+ std::string default_fstab_path;
// Use different fstab paths for normal boot and recovery boot, respectively
if (access("/system/bin/recovery", F_OK) == 0) {
- default_fstab = "/etc/recovery.fstab";
+ default_fstab_path = "/etc/recovery.fstab";
} else { // normal boot
- default_fstab = get_fstab_path();
+ default_fstab_path = get_fstab_path();
}
- struct fstab* fstab = nullptr;
- if (!default_fstab.empty()) {
- fstab = fs_mgr_read_fstab(default_fstab.c_str());
+ Fstab default_fstab;
+ if (!default_fstab_path.empty()) {
+ ReadFstabFromFile(default_fstab_path, &default_fstab);
} else {
LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
- struct fstab* fstab_dt = fs_mgr_read_fstab_dt();
+ for (auto&& entry : default_fstab) {
+ fstab->emplace_back(std::move(entry));
+ }
- // combines fstab entries passed in from device tree with
- // the ones found from default_fstab file
- return in_place_merge(fstab_dt, fstab);
+ return !fstab->empty();
+}
+
+struct fstab* fs_mgr_read_fstab_default() {
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ return nullptr;
+ }
+
+ return FstabToLegacyFstab(fstab);
}
void fs_mgr_free_fstab(struct fstab *fstab)
@@ -913,11 +848,83 @@
}
// Fallback to extract boot devices from fstab.
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
- if (fstab) return extract_boot_devices(*fstab);
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ return {};
+ }
- return {};
+ return extract_boot_devices(fstab);
+}
+
+FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec) {
+ FstabEntry entry;
+ entry.blk_device = fstab_rec->blk_device;
+ entry.logical_partition_name = fstab_rec->logical_partition_name;
+ entry.mount_point = fstab_rec->mount_point;
+ entry.fs_type = fstab_rec->fs_type;
+ entry.flags = fstab_rec->flags;
+ entry.fs_options = fstab_rec->fs_options;
+ entry.fs_mgr_flags.val = fstab_rec->fs_mgr_flags;
+ entry.key_loc = fstab_rec->key_loc;
+ entry.key_dir = fstab_rec->key_dir;
+ entry.verity_loc = fstab_rec->verity_loc;
+ entry.length = fstab_rec->length;
+ entry.label = fstab_rec->label;
+ entry.partnum = fstab_rec->partnum;
+ entry.swap_prio = fstab_rec->swap_prio;
+ entry.max_comp_streams = fstab_rec->max_comp_streams;
+ entry.zram_size = fstab_rec->zram_size;
+ entry.reserved_size = fstab_rec->reserved_size;
+ entry.file_contents_mode = fstab_rec->file_contents_mode;
+ entry.file_names_mode = fstab_rec->file_names_mode;
+ entry.erase_blk_size = fstab_rec->erase_blk_size;
+ entry.logical_blk_size = fstab_rec->logical_blk_size;
+ entry.sysfs_path = fstab_rec->sysfs_path;
+
+ return entry;
+}
+
+Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab) {
+ Fstab fstab;
+ for (int i = 0; i < legacy_fstab->num_entries; i++) {
+ fstab.emplace_back(FstabRecToFstabEntry(&legacy_fstab->recs[i]));
+ }
+
+ return fstab;
+}
+
+fstab* FstabToLegacyFstab(const Fstab& fstab) {
+ struct fstab* legacy_fstab = static_cast<struct fstab*>(calloc(1, sizeof(struct fstab)));
+ legacy_fstab->num_entries = fstab.size();
+ legacy_fstab->recs =
+ static_cast<fstab_rec*>(calloc(legacy_fstab->num_entries, sizeof(fstab_rec)));
+
+ for (int i = 0; i < legacy_fstab->num_entries; i++) {
+ legacy_fstab->recs[i].blk_device = strdup(fstab[i].blk_device.c_str());
+ legacy_fstab->recs[i].logical_partition_name =
+ strdup(fstab[i].logical_partition_name.c_str());
+ legacy_fstab->recs[i].mount_point = strdup(fstab[i].mount_point.c_str());
+ legacy_fstab->recs[i].fs_type = strdup(fstab[i].fs_type.c_str());
+ legacy_fstab->recs[i].flags = fstab[i].flags;
+ legacy_fstab->recs[i].fs_options = strdup(fstab[i].fs_options.c_str());
+ legacy_fstab->recs[i].fs_mgr_flags = fstab[i].fs_mgr_flags.val;
+ legacy_fstab->recs[i].key_loc = strdup(fstab[i].key_loc.c_str());
+ legacy_fstab->recs[i].key_dir = strdup(fstab[i].key_dir.c_str());
+ legacy_fstab->recs[i].verity_loc = strdup(fstab[i].verity_loc.c_str());
+ legacy_fstab->recs[i].length = fstab[i].length;
+ legacy_fstab->recs[i].label = strdup(fstab[i].label.c_str());
+ legacy_fstab->recs[i].partnum = fstab[i].partnum;
+ legacy_fstab->recs[i].swap_prio = fstab[i].swap_prio;
+ legacy_fstab->recs[i].max_comp_streams = fstab[i].max_comp_streams;
+ legacy_fstab->recs[i].zram_size = fstab[i].zram_size;
+ legacy_fstab->recs[i].reserved_size = fstab[i].reserved_size;
+ legacy_fstab->recs[i].file_contents_mode = fstab[i].file_contents_mode;
+ legacy_fstab->recs[i].file_names_mode = fstab[i].file_names_mode;
+ legacy_fstab->recs[i].erase_blk_size = fstab[i].erase_blk_size;
+ legacy_fstab->recs[i].logical_blk_size = fstab[i].logical_blk_size;
+ legacy_fstab->recs[i].sysfs_path = strdup(fstab[i].sysfs_path.c_str());
+ }
+ return legacy_fstab;
}
int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index a1de005..20652ad 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -395,6 +395,18 @@
return false;
}
+void fs_mgr_overlayfs_umount_scratch() {
+ // Lazy umount will allow us to move on and possibly later
+ // establish a new fresh mount without requiring a reboot should
+ // the developer wish to restart. Old references should melt
+ // away or have no data. Main goal is to shut the door on the
+ // current overrides with an expectation of a subsequent reboot,
+ // thus any errors here are ignored.
+ umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+ LINFO << "umount(" << kScratchMountPoint << ")";
+ rmdir(kScratchMountPoint.c_str());
+}
+
// reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise
std::string scratch_device_cache;
@@ -408,13 +420,7 @@
auto save_errno = errno;
if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
- // Lazy umount will allow us to move on and possibly later
- // establish a new fresh mount without requiring a reboot should
- // the developer wish to restart. Old references should melt
- // away or have no data. Main goal is to shut the door on the
- // current overrides with an expectation of a subsequent reboot,
- // thus any errors here are ignored.
- umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+ fs_mgr_overlayfs_umount_scratch();
}
auto builder = MetadataBuilder::New(super_device, slot_number);
if (!builder) {
@@ -432,7 +438,7 @@
if (change) *change = true;
if (!DestroyLogicalPartition(partition_name, 0s)) return false;
} else {
- PERROR << "delete partition " << overlay;
+ LERROR << "delete partition " << overlay;
return false;
}
errno = save_errno;
@@ -647,49 +653,65 @@
if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
auto scratch_device = fs_mgr_overlayfs_scratch_device();
- auto partition_exists = fs_mgr_rw_access(scratch_device);
+ auto partition_create = !fs_mgr_rw_access(scratch_device);
+ auto slot_number = fs_mgr_overlayfs_slot_number();
+ auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+ if (!fs_mgr_rw_access(super_device)) return false;
+ if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+ auto builder = MetadataBuilder::New(super_device, slot_number);
+ if (!builder) {
+ LERROR << "open " << super_device << " metadata";
+ return false;
+ }
+ const auto partition_name = android::base::Basename(kScratchMountPoint);
+ auto partition = builder->FindPartition(partition_name);
+ auto partition_exists = partition != nullptr;
+ auto changed = false;
if (!partition_exists) {
- auto slot_number = fs_mgr_overlayfs_slot_number();
- auto super_device = fs_mgr_overlayfs_super_device(slot_number);
- if (!fs_mgr_rw_access(super_device)) return false;
- if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
- auto builder = MetadataBuilder::New(super_device, slot_number);
- if (!builder) {
- PERROR << "open " << super_device << " metadata";
+ partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+ if (!partition) {
+ LERROR << "create " << partition_name;
return false;
}
- const auto partition_name = android::base::Basename(kScratchMountPoint);
- partition_exists = builder->FindPartition(partition_name) != nullptr;
- if (!partition_exists) {
- auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
- if (!partition) {
- PERROR << "create " << partition_name;
- return false;
+ changed = true;
+ }
+ // Take half of free space, minimum 512MB or free space - 256KB margin.
+ static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024);
+ static constexpr auto kMarginSize = uint64_t(256 * 1024);
+ if (partition->size() < kMinimumSize) {
+ auto partition_size =
+ builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
+ if ((partition_size > kMinimumSize) || !partition->size()) {
+ partition_size = std::max(std::min(kMinimumSize, partition_size - kMarginSize),
+ partition_size / 2);
+ if (partition_size > partition->size()) {
+ if (!builder->ResizePartition(partition, partition_size)) {
+ LERROR << "resize " << partition_name;
+ return false;
+ }
+ if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+ changed = true;
+ partition_exists = false;
}
- auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
- // 512MB or half the remaining available space, whichever is greater.
- partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
- if (!builder->ResizePartition(partition, partition_size)) {
- PERROR << "resize " << partition_name;
- return false;
- }
-
- auto metadata = builder->Export();
- if (!metadata) {
- LERROR << "generate new metadata " << partition_name;
- return false;
- }
- if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
- LERROR << "update " << partition_name;
- return false;
- }
-
- if (change) *change = true;
+ }
+ }
+ // land the update back on to the partition
+ if (changed) {
+ auto metadata = builder->Export();
+ if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+ LERROR << "add partition " << partition_name;
+ return false;
}
+ if (change) *change = true;
+ }
+
+ if (changed || partition_create) {
if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
&scratch_device))
return false;
+
+ if (change) *change = true;
}
if (partition_exists) {
@@ -709,6 +731,7 @@
} else if (mnt_type == "ext4") {
command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
} else {
+ errno = ESRCH;
LERROR << mnt_type << " has no mkfs cookbook";
return false;
}
@@ -736,14 +759,20 @@
return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr;
}
+bool fs_mgr_overlayfs_invalid(const fstab* fstab) {
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true;
+
+ // in recovery or fastbootd mode, not allowed!
+ if (fs_mgr_access("/system/bin/recovery")) return true;
+
+ return !fstab;
+}
+
} // namespace
bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
auto ret = false;
-
- if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
-
- if (!fstab) return ret;
+ if (fs_mgr_overlayfs_invalid(fstab)) return ret;
auto scratch_can_be_mounted = true;
for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
@@ -756,8 +785,7 @@
fs_mgr_overlayfs_mount_scratch(scratch_device,
fs_mgr_overlayfs_scratch_mount_type()) &&
!fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) {
- umount2(kScratchMountPoint.c_str(), MNT_DETACH);
- rmdir(kScratchMountPoint.c_str());
+ fs_mgr_overlayfs_umount_scratch();
}
}
if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
@@ -773,7 +801,9 @@
}
std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
- if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
+ if (fs_mgr_overlayfs_invalid(fstab)) return {};
+
+ if (fs_mgr_get_entry_for_mount_point(fstab, kScratchMountPoint)) {
return {};
}
@@ -848,6 +878,7 @@
auto ret = true;
// If scratch exists, but is not mounted, lets gain access to clean
// specific override entries.
+ auto mount_scratch = false;
if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
auto scratch_device = fs_mgr_overlayfs_scratch_device();
if (scratch_device.empty()) {
@@ -857,7 +888,8 @@
CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
&scratch_device);
}
- fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type());
+ mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
+ fs_mgr_overlayfs_scratch_mount_type());
}
for (const auto& overlay_mount_point : kOverlayMountPoints) {
ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
@@ -875,6 +907,8 @@
PERROR << "teardown";
ret = false;
}
+ if (mount_scratch) fs_mgr_overlayfs_umount_scratch();
+
return ret;
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 23a92d3..711446c 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -21,8 +21,9 @@
#include <string>
#include <android-base/logging.h>
+#include <fs_mgr.h>
+#include <fstab/fstab.h>
-#include "fs_mgr.h"
#include "fs_mgr_priv_boot_config.h"
/* The CHECK() in logging.h will use program invocation name as the tag.
@@ -130,7 +131,7 @@
FileWaitMode wait_mode = FileWaitMode::Exists);
int fs_mgr_set_blk_ro(const char* blockdev);
-bool fs_mgr_update_for_slotselect(fstab* fstab);
+bool fs_mgr_update_for_slotselect(Fstab* fstab);
bool fs_mgr_is_device_unlocked();
const std::string& get_android_dt_dir();
bool is_dt_compatible();
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 3b01d0e..20d60ae 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -31,36 +31,23 @@
}
// Updates |fstab| for slot_suffix. Returns true on success, false on error.
-bool fs_mgr_update_for_slotselect(struct fstab *fstab) {
+bool fs_mgr_update_for_slotselect(Fstab* fstab) {
int n;
std::string ab_suffix;
- for (n = 0; n < fstab->num_entries; n++) {
- fstab_rec& record = fstab->recs[n];
- if (record.fs_mgr_flags & MF_SLOTSELECT) {
- if (ab_suffix.empty()) {
- ab_suffix = fs_mgr_get_slot_suffix();
- // Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
- if (ab_suffix.empty()) return false;
- }
-
- char* new_blk_device;
- if (asprintf(&new_blk_device, "%s%s", record.blk_device, ab_suffix.c_str()) <= 0) {
- return false;
- }
- free(record.blk_device);
- record.blk_device = new_blk_device;
-
- char* new_partition_name;
- if (record.logical_partition_name) {
- if (asprintf(&new_partition_name, "%s%s", record.logical_partition_name,
- ab_suffix.c_str()) <= 0) {
- return false;
- }
- free(record.logical_partition_name);
- record.logical_partition_name = new_partition_name;
- }
+ for (auto& entry : *fstab) {
+ if (!entry.fs_mgr_flags.slot_select) {
+ continue;
}
+
+ if (ab_suffix.empty()) {
+ ab_suffix = fs_mgr_get_slot_suffix();
+ // Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
+ if (ab_suffix.empty()) return false;
+ }
+
+ entry.blk_device = entry.blk_device + ab_suffix;
+ entry.logical_partition_name = entry.logical_partition_name + ab_suffix;
}
return true;
}
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index e1815ff..830f0dd 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -35,43 +35,42 @@
namespace {
-const auto kVendorOverlaySourceDir = "/system/vendor_overlay/"s;
+// The order of the list means the priority to show the files in the directory.
+// The last one has the highest priority.
+const std::vector<const std::string> kVendorOverlaySourceDirs = {
+ "/system/vendor_overlay/",
+ "/product/vendor_overlay/",
+};
const auto kVndkVersionPropertyName = "ro.vndk.version"s;
const auto kVendorTopDir = "/vendor/"s;
const auto kLowerdirOption = "lowerdir="s;
-std::string fs_mgr_get_vendor_overlay_top_dir() {
- // VNDK version is provided by the /vendor/default.prop
- // To read the property, it must be called at the second init stage after the default
- // properties are loaded.
- std::string vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
- if (vndk_version.empty()) {
- return "";
- }
- return kVendorOverlaySourceDir + vndk_version;
-}
+std::vector<std::pair<std::string, std::string>> fs_mgr_get_vendor_overlay_dirs(
+ const std::string& vndk_version) {
+ std::vector<std::pair<std::string, std::string>> vendor_overlay_dirs;
+ for (const auto& vendor_overlay_source : kVendorOverlaySourceDirs) {
+ const auto overlay_top = vendor_overlay_source + vndk_version;
+ std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
+ closedir);
+ if (!vendor_overlay_top) continue;
-std::vector<std::string> fs_mgr_get_vendor_overlay_dirs(const std::string& overlay_top) {
- std::vector<std::string> vendor_overlay_dirs;
- std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
- closedir);
- if (!vendor_overlay_top) return vendor_overlay_dirs;
+ // Vendor overlay root for current vendor version found!
+ LINFO << "vendor overlay root: " << overlay_top;
- // Vendor overlay root for current vendor version found!
- LINFO << "vendor overlay root: " << overlay_top;
- struct dirent* dp;
- while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
- if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
- continue;
+ struct dirent* dp;
+ while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
+ if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
+ continue;
+ }
+ vendor_overlay_dirs.emplace_back(overlay_top, dp->d_name);
}
- vendor_overlay_dirs.push_back(dp->d_name);
}
-
return vendor_overlay_dirs;
}
-bool fs_mgr_vendor_overlay_mount(const std::string& overlay_top, const std::string& mount_point) {
- const auto vendor_mount_point = kVendorTopDir + mount_point;
+bool fs_mgr_vendor_overlay_mount(const std::pair<std::string, std::string>& mount_point) {
+ const auto [overlay_top, mount_dir] = mount_point;
+ const auto vendor_mount_point = kVendorTopDir + mount_dir;
LINFO << "vendor overlay mount on " << vendor_mount_point;
const auto target_context = fs_mgr_get_context(vendor_mount_point);
@@ -79,7 +78,7 @@
PERROR << " failed: cannot find the target vendor mount point";
return false;
}
- const auto source_directory = overlay_top + "/" + mount_point;
+ const auto source_directory = overlay_top + "/" + mount_dir;
const auto source_context = fs_mgr_get_context(source_directory);
if (target_context != source_context) {
LERROR << " failed: source and target contexts do not match (source:" << source_context
@@ -112,22 +111,25 @@
// To read the properties, vendor overlay must be mounted at the second stage, right
// after "property_load_boot_defaults()" is called.
bool fs_mgr_vendor_overlay_mount_all() {
- const auto overlay_top = fs_mgr_get_vendor_overlay_top_dir();
- if (overlay_top.empty()) {
+ // To read the property, it must be called at the second init stage after the default
+ // properties are loaded.
+ static const auto vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
+ if (vndk_version.empty()) {
LINFO << "vendor overlay: vndk version not defined";
return false;
}
- const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(overlay_top);
+
+ const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(vndk_version);
if (vendor_overlay_dirs.empty()) return true;
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
LINFO << "vendor overlay: kernel does not support overlayfs";
return false;
}
- // Mount each directory in /system/vendor_overlay/<ver> on /vendor
+ // Mount each directory in /(system|product)/vendor_overlay/<ver> on /vendor
auto ret = true;
for (const auto& vendor_overlay_dir : vendor_overlay_dirs) {
- if (!fs_mgr_vendor_overlay_mount(overlay_top, vendor_overlay_dir)) {
+ if (!fs_mgr_vendor_overlay_mount(vendor_overlay_dir)) {
ret = false;
}
}
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index bb40511..80bdb87 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-#ifndef __CORE_FS_TAB_H
-#define __CORE_FS_TAB_H
+#pragma once
#include <linux/dm-ioctl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
+#include <sys/types.h>
#include <set>
#include <string>
+#include <vector>
/*
* The entries must be kept in the same order as they were seen in the fstab.
@@ -46,17 +47,17 @@
char* key_loc;
char* key_dir;
char* verity_loc;
- long long length;
+ off64_t length;
char* label;
int partnum;
int swap_prio;
int max_comp_streams;
- unsigned int zram_size;
- uint64_t reserved_size;
- unsigned int file_contents_mode;
- unsigned int file_names_mode;
- unsigned int erase_blk_size;
- unsigned int logical_blk_size;
+ off64_t zram_size;
+ off64_t reserved_size;
+ int file_contents_mode;
+ int file_names_mode;
+ off64_t erase_blk_size;
+ off64_t logical_blk_size;
char* sysfs_path;
};
@@ -94,4 +95,82 @@
std::string fs_mgr_get_slot_suffix();
std::set<std::string> fs_mgr_get_boot_devices();
-#endif /* __CORE_FS_TAB_H */
+struct FstabEntry {
+ std::string blk_device;
+ std::string logical_partition_name;
+ std::string mount_point;
+ std::string fs_type;
+ unsigned long flags = 0;
+ std::string fs_options;
+ std::string key_loc;
+ std::string key_dir;
+ std::string verity_loc;
+ off64_t length = 0;
+ std::string label;
+ int partnum = -1;
+ int swap_prio = -1;
+ int max_comp_streams = 0;
+ off64_t zram_size = 0;
+ off64_t reserved_size = 0;
+ int file_contents_mode = 0;
+ int file_names_mode = 0;
+ off64_t erase_blk_size = 0;
+ off64_t logical_blk_size = 0;
+ std::string sysfs_path;
+
+ // TODO: Remove this union once fstab_rec is deprecated. It only serves as a
+ // convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
+ union {
+ int val;
+ struct {
+ bool wait : 1;
+ bool check : 1;
+ bool crypt : 1;
+ bool nonremovable : 1;
+ bool vold_managed : 1;
+ bool length : 1;
+ bool recovery_only : 1;
+ bool swap_prio : 1;
+ bool zram_size : 1;
+ bool verify : 1;
+ bool force_crypt : 1;
+ bool no_emulated_sd : 1; // No emulated sdcard daemon; sd card is the only external
+ // storage.
+ bool no_trim : 1;
+ bool file_encryption : 1;
+ bool formattable : 1;
+ bool slot_select : 1;
+ bool force_fde_or_fbe : 1;
+ bool late_mount : 1;
+ bool no_fail : 1;
+ bool verify_at_boot : 1;
+ bool max_comp_streams : 1;
+ bool reserved_size : 1;
+ bool quota : 1;
+ bool erase_blk_size : 1;
+ bool logical_blk_size : 1;
+ bool avb : 1;
+ bool key_directory : 1;
+ bool sysfs : 1;
+ bool logical : 1;
+ bool checkpoint_blk : 1;
+ bool checkpoint_fs : 1;
+ };
+ } fs_mgr_flags;
+
+ bool is_encryptable() const {
+ return fs_mgr_flags.crypt || fs_mgr_flags.force_crypt || fs_mgr_flags.force_fde_or_fbe;
+ }
+};
+
+// An Fstab is a collection of FstabEntry structs.
+using Fstab = std::vector<FstabEntry>;
+
+bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
+bool ReadFstabFromDt(Fstab* fstab);
+bool ReadDefaultFstab(Fstab* fstab);
+
+// Temporary conversion functions.
+FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec);
+Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab);
+fstab* FstabToLegacyFstab(const Fstab& fstab);
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
similarity index 93%
rename from fs_mgr/fs_mgr_avb_ops.cpp
rename to fs_mgr/libfs_avb/avb_ops.cpp
index 18efa22..f56a517 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-#include "fs_mgr_priv_avb_ops.h"
+#include "avb_ops.h"
#include <errno.h>
#include <fcntl.h>
@@ -37,15 +37,17 @@
#include <libavb/libavb.h>
#include <utils/Compat.h>
-#include "fs_mgr.h"
#include "fs_mgr_priv.h"
using namespace std::literals;
+namespace android {
+namespace fs_mgr {
+
static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
size_t num_bytes, void* buffer, size_t* out_num_read) {
return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
- partition, offset, num_bytes, buffer, out_num_read);
+ partition, offset, num_bytes, buffer, out_num_read);
}
static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
@@ -58,9 +60,10 @@
}
static AvbIOResult dummy_validate_vbmeta_public_key(
- AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
- size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
- size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
+ AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
+ size_t public_key_length ATTRIBUTE_UNUSED,
+ const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
+ size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
// vbmeta public key has been checked in bootloader phase.
// In user-space, returns true to pass the check.
//
@@ -178,3 +181,6 @@
return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, out_data);
}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_priv_avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h
similarity index 89%
rename from fs_mgr/fs_mgr_priv_avb_ops.h
rename to fs_mgr/libfs_avb/avb_ops.h
index 44eb1da..e6b33c2 100644
--- a/fs_mgr/fs_mgr_priv_avb_ops.h
+++ b/fs_mgr/libfs_avb/avb_ops.h
@@ -22,15 +22,14 @@
* SOFTWARE.
*/
-#ifndef __CORE_FS_MGR_PRIV_AVB_OPS_H
-#define __CORE_FS_MGR_PRIV_AVB_OPS_H
+#pragma once
-#include <map>
#include <string>
#include <libavb/libavb.h>
-#include "fs_mgr.h"
+namespace android {
+namespace fs_mgr {
// This class provides C++ bindings to interact with libavb, a small
// self-contained piece of code that's intended to be used in bootloaders.
@@ -42,7 +41,7 @@
// read and verify the metadata and store it into the out_data parameter.
// The caller MUST check the integrity of metadata against the
// androidboot.vbmeta.{hash_alg, size, digest} values from /proc/cmdline.
-// e.g., see class FsManagerAvbVerifier for more details.
+// e.g., see class AvbVerifier for more details.
//
class FsManagerAvbOps {
public:
@@ -60,6 +59,7 @@
private:
AvbOps avb_ops_;
- std::map<std::string, std::string> by_name_symlink_map_;
};
-#endif /* __CORE_FS_MGR_PRIV_AVB_OPS_H */
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
similarity index 86%
rename from fs_mgr/fs_mgr_avb.cpp
rename to fs_mgr/libfs_avb/fs_avb.cpp
index 6f94d45..c4accad 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "fs_mgr_avb.h"
+#include "fs_avb/fs_avb.h"
#include <fcntl.h>
#include <libgen.h>
@@ -35,10 +35,12 @@
#include <libavb/libavb.h>
#include <libdm/dm.h>
-#include "fs_mgr.h"
+#include "avb_ops.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_avb_ops.h"
-#include "fs_mgr_priv_sha.h"
+#include "sha.h"
+
+namespace android {
+namespace fs_mgr {
static inline bool nibble_value(const char& c, uint8_t* value) {
FS_MGR_CHECK(value != nullptr);
@@ -117,14 +119,14 @@
// - androidboot.vbmeta.hash_alg
// - androidboot.vbmeta.size
// - androidboot.vbmeta.digest
-class FsManagerAvbVerifier {
+class AvbVerifier {
public:
- // The factory method to return a unique_ptr<FsManagerAvbVerifier>
- static std::unique_ptr<FsManagerAvbVerifier> Create();
+ // The factory method to return a unique_ptr<AvbVerifier>
+ static std::unique_ptr<AvbVerifier> Create();
bool VerifyVbmetaImages(const AvbSlotVerifyData& verify_data);
protected:
- FsManagerAvbVerifier() = default;
+ AvbVerifier() = default;
private:
enum HashAlgorithm {
@@ -138,10 +140,10 @@
size_t vbmeta_size_;
};
-std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() {
- std::unique_ptr<FsManagerAvbVerifier> avb_verifier(new FsManagerAvbVerifier());
+std::unique_ptr<AvbVerifier> AvbVerifier::Create() {
+ std::unique_ptr<AvbVerifier> avb_verifier(new AvbVerifier());
if (!avb_verifier) {
- LERROR << "Failed to create unique_ptr<FsManagerAvbVerifier>";
+ LERROR << "Failed to create unique_ptr<AvbVerifier>";
return nullptr;
}
@@ -184,7 +186,7 @@
return avb_verifier;
}
-bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
+bool AvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
if (verify_data.num_vbmeta_images == 0) {
LERROR << "No vbmeta images";
return false;
@@ -195,10 +197,10 @@
if (hash_alg_ == kSHA256) {
std::tie(total_size, digest_matched) =
- verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
+ verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
} else if (hash_alg_ == kSHA512) {
std::tie(total_size, digest_matched) =
- verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
+ verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
}
if (total_size != vbmeta_size_) {
@@ -268,7 +270,8 @@
const std::string& salt, const std::string& root_digest,
bool wait_for_verity_dev) {
android::dm::DmTable table;
- if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) ||
+ if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device,
+ &table) ||
!table.valid()) {
LERROR << "Failed to construct verity table.";
return false;
@@ -314,9 +317,9 @@
// Get descriptors from vbmeta_images[i].
size_t num_descriptors;
std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
- avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
- verify_data.vbmeta_images[i].vbmeta_size, &num_descriptors),
- avb_free);
+ avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
+ verify_data.vbmeta_images[i].vbmeta_size, &num_descriptors),
+ avb_free);
if (!descriptors || num_descriptors < 1) {
continue;
@@ -329,9 +332,10 @@
continue;
}
if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
- desc_partition_name = (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
+ desc_partition_name =
+ (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
if (!avb_hashtree_descriptor_validate_and_byteswap(
- (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
+ (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
continue;
}
if (out_hashtree_desc->partition_name_len != partition_name.length()) {
@@ -361,12 +365,12 @@
return true;
}
-FsManagerAvbUniquePtr FsManagerAvbHandle::Open() {
+AvbUniquePtr AvbHandle::Open() {
bool is_device_unlocked = fs_mgr_is_device_unlocked();
- FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
+ AvbUniquePtr avb_handle(new AvbHandle());
if (!avb_handle) {
- LERROR << "Failed to allocate FsManagerAvbHandle";
+ LERROR << "Failed to allocate AvbHandle";
return nullptr;
}
@@ -406,7 +410,7 @@
// Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
avb_handle->avb_version_ =
- android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
+ android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
// Checks whether FLAGS_VERIFICATION_DISABLED is set:
// - Only the top-level vbmeta struct is read.
@@ -414,18 +418,18 @@
// and AVB HASHTREE descriptor(s).
AvbVBMetaImageHeader vbmeta_header;
avb_vbmeta_image_header_to_host_byte_order(
- (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
- &vbmeta_header);
- bool verification_disabled =
- ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+ (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
+ &vbmeta_header);
+ bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
+ AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
if (verification_disabled) {
avb_handle->status_ = kAvbHandleVerificationDisabled;
} else {
// Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline.
- std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
+ std::unique_ptr<AvbVerifier> avb_verifier = AvbVerifier::Create();
if (!avb_verifier) {
- LERROR << "Failed to create FsManagerAvbVerifier";
+ LERROR << "Failed to create AvbVerifier";
return nullptr;
}
if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
@@ -434,8 +438,8 @@
}
// Checks whether FLAGS_HASHTREE_DISABLED is set.
- bool hashtree_disabled =
- ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+ bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
+ AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
if (hashtree_disabled) {
avb_handle->status_ = kAvbHandleHashtreeDisabled;
}
@@ -445,16 +449,16 @@
return avb_handle;
}
-SetUpAvbHashtreeResult FsManagerAvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
- bool wait_for_verity_dev) {
+AvbHashtreeResult AvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
+ bool wait_for_verity_dev) {
if (!fstab_entry || status_ == kAvbHandleUninitialized || !avb_slot_data_ ||
avb_slot_data_->num_vbmeta_images < 1) {
- return SetUpAvbHashtreeResult::kFail;
+ return AvbHashtreeResult::kFail;
}
if (status_ == kAvbHandleHashtreeDisabled || status_ == kAvbHandleVerificationDisabled) {
LINFO << "AVB HASHTREE disabled on: " << fstab_entry->mount_point;
- return SetUpAvbHashtreeResult::kDisabled;
+ return AvbHashtreeResult::kDisabled;
}
// Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
@@ -478,14 +482,17 @@
std::string root_digest;
if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt,
&root_digest)) {
- return SetUpAvbHashtreeResult::kFail;
+ return AvbHashtreeResult::kFail;
}
// Converts HASHTREE descriptor to verity_table_params.
if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest,
wait_for_verity_dev)) {
- return SetUpAvbHashtreeResult::kFail;
+ return AvbHashtreeResult::kFail;
}
- return SetUpAvbHashtreeResult::kSuccess;
+ return AvbHashtreeResult::kSuccess;
}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
similarity index 75%
rename from fs_mgr/include/fs_mgr_avb.h
rename to fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index bb55a14..9adab3d 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-#ifndef __CORE_FS_MGR_AVB_H
-#define __CORE_FS_MGR_AVB_H
+#pragma once
-#include <map>
#include <memory>
#include <string>
+#include <fstab/fstab.h>
#include <libavb/libavb.h>
-#include "fs_mgr.h"
+namespace android {
+namespace fs_mgr {
-enum class SetUpAvbHashtreeResult {
+enum class AvbHashtreeResult {
kSuccess = 0,
kFail,
kDisabled,
@@ -33,17 +33,15 @@
class FsManagerAvbOps;
-class FsManagerAvbHandle;
-using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
-
-using ByNameSymlinkMap = std::map<std::string, std::string>;
+class AvbHandle;
+using AvbUniquePtr = std::unique_ptr<AvbHandle>;
// Provides a factory method to return a unique_ptr pointing to itself and the
// SetUpAvbHashtree() function to extract dm-verity parameters from AVB HASHTREE
// descriptors to load verity table into kernel through ioctl.
-class FsManagerAvbHandle {
+class AvbHandle {
public:
- // The factory method to return a FsManagerAvbUniquePtr that holds
+ // The factory method to return a AvbUniquePtr that holds
// the verified AVB (external/avb) metadata of all verified partitions
// in avb_slot_data_.vbmeta_images[].
//
@@ -51,7 +49,7 @@
// - androidboot.vbmeta.{hash_alg, size, digest}.
//
// A typical usage will be:
- // - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
+ // - AvbUniquePtr handle = AvbHandle::Open();
//
// Possible return values:
// - nullptr: any error when reading and verifying the metadata,
@@ -75,7 +73,7 @@
// - a valid unique_ptr with status kAvbHandleSuccess: the metadata
// is verified and can be trusted.
//
- static FsManagerAvbUniquePtr Open();
+ static AvbUniquePtr Open();
// Sets up dm-verity on the given fstab entry.
// The 'wait_for_verity_dev' parameter makes this function wait for the
@@ -87,17 +85,17 @@
// failed to get the HASHTREE descriptor, runtime error when set up
// device-mapper, etc.
// - kDisabled: hashtree is disabled.
- SetUpAvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
+ AvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
const std::string& avb_version() const { return avb_version_; }
- FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
- FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
+ AvbHandle(const AvbHandle&) = delete; // no copy
+ AvbHandle& operator=(const AvbHandle&) = delete; // no assignment
- FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move
- FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
+ AvbHandle(AvbHandle&&) noexcept = delete; // no move
+ AvbHandle& operator=(AvbHandle&&) noexcept = delete; // no move assignment
- ~FsManagerAvbHandle() {
+ ~AvbHandle() {
if (avb_slot_data_) {
avb_slot_verify_data_free(avb_slot_data_);
}
@@ -112,11 +110,12 @@
kAvbHandleVerificationError,
};
- FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
+ AvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
AvbSlotVerifyData* avb_slot_data_;
AvbHandleStatus status_;
std::string avb_version_;
};
-#endif /* __CORE_FS_MGR_AVB_H */
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/libfs_avb/sha.h
similarity index 92%
rename from fs_mgr/fs_mgr_priv_sha.h
rename to fs_mgr/libfs_avb/sha.h
index 5b53eea..2d3ca6d 100644
--- a/fs_mgr/fs_mgr_priv_sha.h
+++ b/fs_mgr/libfs_avb/sha.h
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#ifndef __CORE_FS_MGR_PRIV_SHA_H
-#define __CORE_FS_MGR_PRIV_SHA_H
+#pragma once
#include <openssl/sha.h>
+namespace android {
+namespace fs_mgr {
+
class SHA256Hasher {
private:
SHA256_CTX sha256_ctx;
@@ -59,4 +61,5 @@
}
};
-#endif /* __CORE_FS_MGR_PRIV_SHA_H */
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 7a00194..c7c86eb 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -27,6 +27,7 @@
GREEN="${ESCAPE}[38;5;40m"
RED="${ESCAPE}[38;5;196m"
ORANGE="${ESCAPE}[38;5;255:165:0m"
+BLUE="${ESCAPE}[35m"
NORMAL="${ESCAPE}[0m"
# Helper functions
@@ -63,6 +64,7 @@
Returns: the logcat output" ]
adb_logcat() {
+ echo "${RED}[ INFO ]${NORMAL} logcat ${@}" >&2 &&
adb logcat "${@}" </dev/null |
grep -v 'logd : logdr: UID=' |
sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
@@ -106,12 +108,13 @@
Returns: true if the reboot command succeeded" ]
adb_reboot() {
- adb reboot remount-test
+ adb reboot remount-test &&
+ sleep 2
}
[ "USAGE: adb_wait [timeout]
-Returns: waits until the device has returned or the optional timeout" ]
+Returns: waits until the device has returned for adb or optional timeout" ]
adb_wait() {
if [ -n "${1}" ]; then
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
@@ -120,24 +123,71 @@
fi
}
+[ "USAGE: fastboot_wait [timeout]
+
+Returns: waits until the device has returned for fastboot or optional timeout" ]
+fastboot_wait() {
+ # fastboot has no wait-for-device, but it does an automatic
+ # wait and requires (even a nonsensical) command to do so.
+ if [ -n "${1}" ]; then
+ timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
+ else
+ fastboot wait-for-device >/dev/null
+ fi >/dev/null 2>/dev/null ||
+ inFastboot
+}
+
[ "USAGE: adb_root
+NB: This can be flakey on devices due to USB state
+
Returns: true if device in root state" ]
adb_root() {
- adb root >/dev/null </dev/null 2>/dev/null &&
- sleep 1 &&
- adb_wait &&
- sleep 1
+ adb root >/dev/null </dev/null 2>/dev/null
+ sleep 2
+ adb_wait 2m &&
+ [ `adb_sh echo '${USER}'` = root ]
}
-[ "USAGE: die [-t <epoch>] [message] >/dev/stderr
+[ "USAGE: fastboot_getvar var expected
-If -t <epoch> argument is supplied, dump logcat.
+Returns: true if var output matches expected" ]
+fastboot_getvar() {
+ O=`fastboot getvar ${1} 2>&1`
+ err=${?}
+ O="${O#< waiting for * >?}"
+ O="${O%%?Finished. Total time: *}"
+ if [ 0 -ne ${err} ]; then
+ echo ${O} >&2
+ false
+ return
+ fi
+ if [ "${O}" != "${O#*FAILED}" ]; then
+ O="${1}: <empty>"
+ fi
+ if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
+ echo "${2} != ${O}" >&2
+ false
+ return
+ fi
+ echo ${O} >&2
+}
+
+[ "USAGE: die [-d|-t <epoch>] [message] >/dev/stderr
+
+If -d, or -t <epoch> argument is supplied, dump logcat.
Returns: exit failure, report status" ]
die() {
- if [ X"-t" = X"${1}" -a -n "${2}" ]; then
- adb_logcat -b all -v nsec -t ${2} >&2
+ if [ X"-d" = X"${1}" ]; then
+ adb_logcat -b all -v nsec -d >&2
+ shift
+ elif [ X"-t" = X"${1}" ]; then
+ if [ -n "${2}" ]; then
+ adb_logcat -b all -v nsec -t ${2} >&2
+ else
+ adb_logcat -b all -v nsec -d >&2
+ fi
shift 2
fi
echo "${RED}[ FAILED ]${NORMAL} ${@}" >&2
@@ -201,15 +251,20 @@
die "${@}"
}
-[ "USAGE: skip_administrative_mounts < /proc/mounts
+[ "USAGE: skip_administrative_mounts [data] < /proc/mounts
Filters out all administrative (eg: sysfs) mounts uninteresting to the test" ]
skip_administrative_mounts() {
+ if [ "data" = "${1}" ]; then
+ grep -v " /data "
+ else
+ cat -
+ fi |
grep -v \
-e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
-e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
-e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
- -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\|data\) "
+ -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\) "
}
if [ X"-s" = X"${1}" -a -n "${2}" ]; then
@@ -226,6 +281,9 @@
isDebuggable || die "device not a debug build"
# Do something
+
+echo "${GREEN}[ RUN ]${NORMAL} Testing kernel support for overlayfs" >&2
+
adb_wait || die "wait for device failed"
adb_sh ls -d /sys/module/overlay </dev/null >/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 ||
@@ -233,9 +291,11 @@
adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
die "overlay module can not be used on ANDROID"
-adb_root &&
- adb_wait ||
+adb_root ||
die "initial setup"
+
+echo "${GREEN}[ RUN ]${NORMAL} Checking current overlayfs status" >&2
+
reboot=false
OVERLAYFS_BACKING="cache mnt/scratch"
for d in ${OVERLAYFS_BACKING}; do
@@ -250,8 +310,7 @@
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
adb_reboot &&
adb_wait 2m &&
- adb_root &&
- adb_wait ||
+ adb_root ||
die "reboot after wipe"
fi
D=`adb_sh df -k </dev/null` &&
@@ -262,65 +321,90 @@
echo "${ORANGE}[ WARNING ]${NORMAL} overlays present before setup" >&2 ||
echo "${GREEN}[ OK ]${NORMAL} no overlay present before setup" >&2
adb_sh df -k `adb_sh cat /proc/mounts |
- skip_administrative_mounts |
+ skip_administrative_mounts data |
cut -s -d' ' -f1`
+echo "${GREEN}[ RUN ]${NORMAL} disable verity" >&2
+
T=`adb_date`
D=`adb disable-verity 2>&1`
err=${?}
-echo "${D}"
if [ ${err} != 0 -o X"${D}" != X"${D##*setup failed}" ]; then
+ echo "${D%?Now reboot your device for settings to take effect}"
die -t ${T} "setup for overlay"
fi
if [ X"${D}" != X"${D##*using overlayfs}" ]; then
echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
fi
-adb_reboot &&
- adb_wait &&
- D=`adb_sh df -k </dev/null` &&
- H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep "^overlay "` &&
- echo "${H}" &&
- echo "${D}" ||
- die "overlay takeover failed"
-echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
- echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover before remount not complete" >&2
-
-T=`adb_date`
-adb_root &&
- adb_wait &&
- adb remount &&
- D=`adb_sh df -k </dev/null` ||
- die -t ${T} "can not collect filesystem data"
-if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
- echo "${ORANGE}[ INFO ]${NORMAL} using scratch dynamic partition for overrides" >&2
- H=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
- [ -n "${H}" ] &&
- echo "${ORANGE}[ INFO ]${NORMAL} scratch filesystem ${H}"
+reboot=false
+if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
+ echo "${GREEN}[ OK ]${NORMAL} disabled verity" >&2
+ reboot=true
+else
+ echo "${ORANGE}[ WARNING ]${NORMAL} verity already disabled" >&2
fi
+D=`adb_sh df -k </dev/null` &&
+ H=`echo "${D}" | head -1` &&
+ D=`echo "${D}" | grep "^overlay " | true` &&
+ [ -n "${D}" ] &&
+ ( echo "${H}" && echo "${D}" && true ) &&
+ die -t ${T} "overlay takeover unexpected"
+L=
+if ${reboot}; then
+ L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
+ adb_reboot &&
+ adb_wait 2m ||
+ die "reboot after verity disabled failed"
+ T=
+fi
+
+echo "${GREEN}[ RUN ]${NORMAL} remount" >&2
+
+adb_root &&
+ adb remount ||
+ ( [ -n "${L}" ] && echo "${L}" && false ) ||
+ die -t "${T}" "adb remount failed"
+D=`adb_sh df -k </dev/null` &&
+ H=`echo "${D}" | head -1` &&
+ D=`echo "${D}" | grep "^overlay "` ||
+ ( [ -n "${L}" ] && echo "${L}" && false ) ||
+ die -t ${T} "overlay takeover failed"
+echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover not complete" >&2
+scratch_partition=scratch
+if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
+ echo "${BLUE}[ INFO ]${NORMAL} using ${scratch_partition} dynamic partition for overrides" >&2
+fi
+M=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
+[ -n "${M}" ] &&
+ echo "${BLUE}[ INFO ]${NORMAL} scratch filesystem ${M}"
+scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null |
+ while read device kblocks used available use mounted on; do
+ if [ "/mnt/scratch" = "\${mounted}" ]; then
+ echo \${kblocks}
+ fi
+ done` &&
+ [ -n "${scratch_size}" ] ||
+ die "scratch size"
+echo "${BLUE}[ INFO ]${NORMAL} scratch size ${scratch_size}KB" >&2
for d in ${OVERLAYFS_BACKING}; do
if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
- echo "${ORANGE}[ INFO ]${NORMAL} /${d}/overlay is setup" >&2
+ echo "${BLUE}[ INFO ]${NORMAL} /${d}/overlay is setup" >&2
fi
done
-H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep "^overlay "` &&
- echo "${H}" &&
+echo "${H}" &&
echo "${D}" &&
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay takeover after remount"
!(adb_sh grep "^overlay " /proc/mounts </dev/null | grep " overlay ro,") &&
- !(adb_sh grep " rw," /proc/mounts </dev/null | skip_administrative_mounts) ||
+ !(adb_sh grep " rw," /proc/mounts </dev/null | skip_administrative_mounts data) ||
die "remount overlayfs missed a spot (ro)"
-adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
- skip_administrative_mounts |
- grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
- echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
- echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
-
# Check something
+
+echo "${GREEN}[ RUN ]${NORMAL} push content to system and vendor" >&2
+
A="Hello World! $(date)"
echo "${A}" | adb_sh "cat - > /system/hello"
echo "${A}" | adb_sh "cat - > /vendor/hello"
@@ -330,9 +414,26 @@
B="`adb_cat /vendor/hello`" ||
die "vendor hello"
check_eq "${A}" "${B}" vendor before reboot
+
+echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2
+
adb_reboot &&
- adb_wait &&
- B="`adb_cat /system/hello`" ||
+ adb_wait 2m ||
+ die "reboot after override content added failed"
+
+D=`adb_su df -k </dev/null` &&
+ H=`echo "${D}" | head -1` &&
+ D=`echo "${D}" | grep "^overlay "` ||
+ ( echo "${L}" && false ) ||
+ die -d "overlay takeover failed after reboot"
+
+adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
+ skip_administrative_mounts |
+ grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
+ echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
+
+B="`adb_cat /system/hello`" ||
die "re-read system hello after reboot"
check_eq "${A}" "${B}" system after reboot
# Only root can read vendor if sepolicy permissions are as expected
@@ -340,19 +441,38 @@
die "re-read vendor hello after reboot w/o root"
check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
adb_root &&
- adb_wait &&
B="`adb_cat /vendor/hello`" ||
die "re-read vendor hello after reboot"
check_eq "${A}" "${B}" vendor after reboot
-adb reboot-fastboot &&
- fastboot flash vendor &&
- fastboot reboot ||
- die "fastbootd flash vendor"
+echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
+
+[ -n "${ANDROID_PRODUCT_OUT}" ] &&
+ adb reboot-fastboot &&
+ fastboot_wait 2m &&
+ fastboot flash vendor ||
+ ( fastboot reboot && false) ||
+ die "fastboot flash vendor"
+# check ${scratch_partition} via fastboot
+fastboot_getvar partition-type:${scratch_partition} raw &&
+ fastboot_getvar has-slot:${scratch_partition} no &&
+ fastboot_getvar is-logical:${scratch_partition} yes ||
+ ( fastboot reboot && false) ||
+ die "fastboot can not see ${scratch_partition} parameters"
+echo "${BLUE}[ INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2
+fastboot erase ${scratch_partition} &&
+ ( fastboot reboot || true) &&
+ die "fastboot can erase ${scratch_partition}"
+echo "${BLUE}[ INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2
+fastboot format ${scratch_partition} &&
+ ( fastboot reboot || true) &&
+ die "fastboot can format ${scratch_partition}"
+fastboot reboot ||
+ die "can not reboot out of fastboot"
+echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
adb_wait 2m ||
die "did not reboot after flash"
adb_root &&
- adb_wait &&
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` &&
@@ -365,13 +485,14 @@
B="`adb_cat /system/hello`" ||
die "re-read system hello after flash vendor"
check_eq "${A}" "${B}" system after flash vendor
-adb_root &&
- adb_wait ||
+adb_root ||
die "adb root"
B="`adb_cat /vendor/hello`" &&
die "re-read vendor hello after flash vendor"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2
+
T=`adb_date`
adb remount &&
( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
@@ -384,4 +505,31 @@
die "re-read vendor hello after rm"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
+echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2
+
+adb reboot-fastboot &&
+ dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null &&
+ fastboot_wait 2m ||
+ ( rm /tmp/adb-remount-test.img && false) ||
+ die "reboot into fastboot"
+fastboot flash ${scratch_partition} /tmp/adb-remount-test.img
+err=${?}
+rm /tmp/adb-remount-test.img
+fastboot reboot ||
+ die "can not reboot out of fastboot"
+[ 0 -eq ${err} ] ||
+ die "fastboot flash ${scratch_partition}"
+adb_wait 2m &&
+ adb_root ||
+ die "did not reboot after flash"
+T=`adb_date`
+D=`adb disable-verity 2>&1`
+err=${?}
+echo "${D}"
+[ ${err} = 0 ] &&
+ [ X"${D}" = X"${D##*setup failed}" ] &&
+ [ X"${D}" != X"${D##*using overlayfs}" ] &&
+ echo "${GREEN}[ OK ]${NORMAL} ${scratch_partition} recreated" >&2 ||
+ die -t ${T} "setup for overlayfs"
+
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/init/Android.bp b/init/Android.bp
index ff3b61f..ea66ac6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -71,6 +71,7 @@
"libbinder",
"libbootloader_message",
"libcutils",
+ "libcrypto",
"libdl",
"libext4_utils",
"libfs_mgr",
@@ -79,6 +80,7 @@
"libkeyutils",
"liblog",
"liblogwrap",
+ "liblp",
"libselinux",
"libutils",
],
@@ -92,6 +94,7 @@
"action.cpp",
"action_manager.cpp",
"action_parser.cpp",
+ "boringssl_self_test.cpp",
"bootchart.cpp",
"builtins.cpp",
"capabilities.cpp",
@@ -99,6 +102,7 @@
"devices.cpp",
"epoll.cpp",
"firmware_handler.cpp",
+ "first_stage_init.cpp",
"first_stage_mount.cpp",
"import_parser.cpp",
"init.cpp",
@@ -117,6 +121,7 @@
"sigchld_handler.cpp",
"subcontext.cpp",
"subcontext.proto",
+ "switch_root.cpp",
"rlimit_parser.cpp",
"tokenizer.cpp",
"uevent_listener.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index dc46d21..0e6ee0b 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -35,16 +35,18 @@
-Wall -Wextra \
-Wno-unused-parameter \
-Werror \
- -std=gnu++1z \
# --
+# Do not build this even with mmma if we're system-as-root, otherwise it will overwrite the symlink.
+ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES := \
devices.cpp \
+ first_stage_init.cpp \
+ first_stage_main.cpp \
first_stage_mount.cpp \
- init_first_stage.cpp \
reboot_utils.cpp \
selinux.cpp \
switch_root.cpp \
@@ -67,6 +69,7 @@
$(TARGET_RAMDISK_OUT)/sys \
LOCAL_STATIC_LIBRARIES := \
+ libfs_avb \
libfs_mgr \
libfec \
libfec_rs \
@@ -93,20 +96,15 @@
# First stage init is weird: it may start without stdout/stderr, and no /proc.
LOCAL_NOSANITIZE := hwaddress
include $(BUILD_EXECUTABLE)
+endif
include $(CLEAR_VARS)
LOCAL_MODULE := init_system
-ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-LOCAL_REQUIRED_MODULES := \
- init_first_stage \
- init_second_stage \
-
-else
LOCAL_REQUIRED_MODULES := \
init_second_stage \
-endif
+LOCAL_POST_INSTALL_CMD := ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init
include $(BUILD_PHONY_PACKAGE)
include $(CLEAR_VARS)
@@ -118,5 +116,3 @@
endif
include $(BUILD_PHONY_PACKAGE)
-
-
diff --git a/init/boringssl_self_test.cpp b/init/boringssl_self_test.cpp
new file mode 100644
index 0000000..0408d30
--- /dev/null
+++ b/init/boringssl_self_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "boringssl_self_test.h"
+
+#include <android-base/logging.h>
+#include <cutils/android_reboot.h>
+#include <openssl/crypto.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+namespace init {
+
+Result<Success> StartBoringSslSelfTest(const BuiltinArguments&) {
+ pid_t id = fork();
+
+ if (id == 0) {
+ if (BORINGSSL_self_test() != 1) {
+ LOG(INFO) << "BoringSSL crypto self tests failed";
+
+ // This check has failed, so the device should refuse
+ // to boot. Rebooting to bootloader to wait for
+ // further action from the user.
+
+ int result = android_reboot(ANDROID_RB_RESTART2, 0,
+ "bootloader,boringssl-self-check-failed");
+ if (result != 0) {
+ LOG(ERROR) << "Failed to reboot into bootloader";
+ }
+ }
+
+ _exit(0);
+ } else if (id == -1) {
+ // Failed to fork, so cannot run the test. Refuse to continue.
+ PLOG(FATAL) << "Failed to fork for BoringSSL self test";
+ }
+
+ return Success();
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/boringssl_self_test.h b/init/boringssl_self_test.h
new file mode 100644
index 0000000..b21fc78
--- /dev/null
+++ b/init/boringssl_self_test.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "builtin_arguments.h"
+#include "result.h"
+
+namespace android {
+namespace init {
+
+Result<Success> StartBoringSslSelfTest(const BuiltinArguments&);
+
+} // namespace init
+} // namespace android
diff --git a/init/init_first_stage.cpp b/init/first_stage_init.cpp
similarity index 97%
rename from init/init_first_stage.cpp
rename to init/first_stage_init.cpp
index c2c6868..e11d897 100644
--- a/init/init_first_stage.cpp
+++ b/init/first_stage_init.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "first_stage_init.h"
+
#include <dirent.h>
#include <fcntl.h>
#include <paths.h>
@@ -94,7 +96,7 @@
} // namespace
-int main(int argc, char** argv) {
+int FirstStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
@@ -214,7 +216,7 @@
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
const char* path = "/system/bin/init";
- const char* args[] = {path, nullptr};
+ const char* args[] = {path, "selinux_setup", nullptr};
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
@@ -226,7 +228,3 @@
} // namespace init
} // namespace android
-
-int main(int argc, char** argv) {
- return android::init::main(argc, argv);
-}
diff --git a/init/first_stage_init.h b/init/first_stage_init.h
new file mode 100644
index 0000000..0476e44
--- /dev/null
+++ b/init/first_stage_init.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+namespace init {
+
+int FirstStageMain(int argc, char** argv);
+
+} // namespace init
+} // namespace android
diff --git a/init/first_stage_main.cpp b/init/first_stage_main.cpp
new file mode 100644
index 0000000..7bae84c
--- /dev/null
+++ b/init/first_stage_main.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "first_stage_init.h"
+
+int main(int argc, char** argv) {
+ return android::init::FirstStageMain(argc, argv);
+}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 43b2ebf..d35329e 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -30,8 +30,8 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
+#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
-#include <fs_mgr_avb.h>
#include <fs_mgr_dm_linear.h>
#include <fs_mgr_overlayfs.h>
#include <liblp/liblp.h>
@@ -43,6 +43,9 @@
#include "util.h"
using android::base::Timer;
+using android::fs_mgr::AvbHandle;
+using android::fs_mgr::AvbHashtreeResult;
+using android::fs_mgr::AvbUniquePtr;
using namespace std::literals;
@@ -113,7 +116,7 @@
bool InitAvbHandle();
std::string device_tree_vbmeta_parts_;
- FsManagerAvbUniquePtr avb_handle_;
+ AvbUniquePtr avb_handle_;
};
// Static Functions
@@ -410,7 +413,14 @@
// heads up for instantiating required device(s) for overlayfs logic
const auto devices = fs_mgr_overlayfs_required_devices(device_tree_fstab_.get());
for (auto const& device : devices) {
- InitMappedDevice(device);
+ if (android::base::StartsWith(device, "/dev/block/by-name/")) {
+ required_devices_partition_names_.emplace(basename(device.c_str()));
+ auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
+ uevent_listener_.RegenerateUevents(uevent_callback);
+ uevent_listener_.Poll(uevent_callback, 10s);
+ } else {
+ InitMappedDevice(device);
+ }
}
fs_mgr_overlayfs_mount_all(device_tree_fstab_.get());
@@ -449,7 +459,9 @@
// Includes the partition names of fstab records and verity_loc_device (if any).
// Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
for (auto fstab_rec : mount_fstab_recs_) {
- required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ if (!fs_mgr_is_logical(fstab_rec)) {
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ }
}
if (!verity_loc_device.empty()) {
@@ -545,12 +557,12 @@
bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
if (fs_mgr_is_avb(fstab_rec)) {
if (!InitAvbHandle()) return false;
- SetUpAvbHashtreeResult hashtree_result =
+ AvbHashtreeResult hashtree_result =
avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
switch (hashtree_result) {
- case SetUpAvbHashtreeResult::kDisabled:
+ case AvbHashtreeResult::kDisabled:
return true; // Returns true to mount the partition.
- case SetUpAvbHashtreeResult::kSuccess:
+ case AvbHashtreeResult::kSuccess:
// The exact block device name (fstab_rec->blk_device) is changed to
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
// first stage.
@@ -565,10 +577,10 @@
bool FirstStageMountVBootV2::InitAvbHandle() {
if (avb_handle_) return true; // Returns true if the handle is already initialized.
- avb_handle_ = FsManagerAvbHandle::Open();
+ avb_handle_ = AvbHandle::Open();
if (!avb_handle_) {
- PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
+ PLOG(ERROR) << "Failed to open AvbHandle";
return false;
}
// Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
@@ -605,7 +617,7 @@
return;
}
- // Initializes required devices for the subsequent FsManagerAvbHandle::Open()
+ // Initializes required devices for the subsequent AvbHandle::Open()
// to verify AVB metadata on all partitions in the verified chain.
// We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
// Open() function returns a valid handle.
@@ -616,9 +628,9 @@
return;
}
- FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open();
+ AvbUniquePtr avb_handle = AvbHandle::Open();
if (!avb_handle) {
- PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
+ PLOG(ERROR) << "Failed to open AvbHandle for INIT_AVB_VERSION";
return;
}
setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
diff --git a/init/init.cpp b/init/init.cpp
index e7dbc11..dc46a82 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -49,6 +49,7 @@
#endif
#include "action_parser.h"
+#include "boringssl_self_test.h"
#include "epoll.h"
#include "first_stage_mount.h"
#include "import_parser.h"
@@ -59,13 +60,8 @@
#include "security.h"
#include "selinux.h"
#include "sigchld_handler.h"
-#include "ueventd.h"
#include "util.h"
-#if __has_feature(address_sanitizer)
-#include <sanitizer/asan_interface.h>
-#endif
-
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -79,25 +75,6 @@
namespace android {
namespace init {
-#if __has_feature(address_sanitizer)
-// Load asan.options if it exists since these are not yet in the environment.
-// Always ensure detect_container_overflow=0 as there are false positives with this check.
-// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
-extern "C" const char* __asan_default_options() {
- return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
-}
-
-__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
-__sanitizer_report_error_summary(const char* summary) {
- LOG(ERROR) << "Main stage (error summary): " << summary;
-}
-
-__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
-AsanReportCallback(const char* str) {
- LOG(ERROR) << "Main stage: " << str;
-}
-#endif
-
static int property_triggers_enabled = 0;
static char qemu[32];
@@ -622,57 +599,11 @@
});
}
-static void SetupSelinux(char** argv) {
- android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
- RebootSystem(ANDROID_RB_RESTART2, "bootloader");
- });
-
- // Set up SELinux, loading the SELinux policy.
- SelinuxSetupKernelLogging();
- SelinuxInitialize();
-
- // We're in the kernel domain and want to transition to the init domain. File systems that
- // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
- // but other file systems do. In particular, this is needed for ramdisks such as the
- // recovery image for A/B devices.
- if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
- PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
- }
-
- setenv("SELINUX_INITIALIZED", "true", 1);
-
- const char* path = "/system/bin/init";
- const char* args[] = {path, nullptr};
- execv(path, const_cast<char**>(args));
-
- // execv() only returns if an error happened, in which case we
- // panic and never return from this function.
- PLOG(FATAL) << "execv(\"" << path << "\") failed";
-}
-
-int main(int argc, char** argv) {
-#if __has_feature(address_sanitizer)
- __asan_set_error_report_callback(AsanReportCallback);
-#endif
-
- if (!strcmp(basename(argv[0]), "ueventd")) {
- return ueventd_main(argc, argv);
- }
-
- if (argc > 1 && !strcmp(argv[1], "subcontext")) {
- android::base::InitLogging(argv, &android::base::KernelLogger);
- const BuiltinFunctionMap function_map;
- return SubcontextMain(argc, argv, &function_map);
- }
-
+int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
- if (getenv("SELINUX_INITIALIZED") == nullptr) {
- SetupSelinux(argv);
- }
-
// We need to set up stdin/stdout/stderr again now that we're running in init's context.
InitKernelLogging(argv, InitAborter);
LOG(INFO) << "init second stage started!";
@@ -708,7 +639,6 @@
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// Clean up our environment.
- unsetenv("SELINUX_INITIALIZED");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
@@ -768,6 +698,9 @@
// Trigger all the boot actions to get us started.
am.QueueEventTrigger("init");
+ // Starting the BoringSSL self test, for NIAP certification compliance.
+ am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");
+
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
diff --git a/init/init.h b/init/init.h
index 65405aa..a76da20 100644
--- a/init/init.h
+++ b/init/init.h
@@ -50,7 +50,7 @@
void ResetWaitForProp();
-int main(int argc, char** argv);
+int SecondStageMain(int argc, char** argv);
} // namespace init
} // namespace android
diff --git a/init/main.cpp b/init/main.cpp
index 9ed451b..868c409 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -14,8 +14,70 @@
* limitations under the License.
*/
+#include "builtins.h"
+#include "first_stage_init.h"
#include "init.h"
+#include "selinux.h"
+#include "subcontext.h"
+#include "ueventd.h"
+
+#include <android-base/logging.h>
+
+#if __has_feature(address_sanitizer)
+#include <sanitizer/asan_interface.h>
+#endif
+
+#if __has_feature(address_sanitizer)
+// Load asan.options if it exists since these are not yet in the environment.
+// Always ensure detect_container_overflow=0 as there are false positives with this check.
+// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
+extern "C" const char* __asan_default_options() {
+ return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
+__sanitizer_report_error_summary(const char* summary) {
+ LOG(ERROR) << "Init (error summary): " << summary;
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
+AsanReportCallback(const char* str) {
+ LOG(ERROR) << "Init: " << str;
+}
+#endif
+
+using namespace android::init;
int main(int argc, char** argv) {
- android::init::main(argc, argv);
+#if __has_feature(address_sanitizer)
+ __asan_set_error_report_callback(AsanReportCallback);
+#endif
+
+ if (!strcmp(basename(argv[0]), "ueventd")) {
+ return ueventd_main(argc, argv);
+ }
+
+ if (argc < 2) {
+ return FirstStageMain(argc, argv);
+ }
+
+ if (!strcmp(argv[1], "subcontext")) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+ const BuiltinFunctionMap function_map;
+
+ return SubcontextMain(argc, argv, &function_map);
+ }
+
+ if (!strcmp(argv[1], "selinux_setup")) {
+ return SetupSelinux(argv);
+ }
+
+ if (!strcmp(argv[1], "second_stage")) {
+ return SecondStageMain(argc, argv);
+ }
+
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+
+ LOG(ERROR) << "Unknown argument passed to init '" << argv[1] << "'";
+ return 1;
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index fd7e86f..3a09096 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -18,8 +18,8 @@
// for SELinux operation for init.
// When the system boots, there is no SEPolicy present and init is running in the kernel domain.
-// Init loads the SEPolicy from the file system, restores the context of /init based on this
-// SEPolicy, and finally exec()'s itself to run in the proper domain.
+// Init loads the SEPolicy from the file system, restores the context of /system/bin/init based on
+// this SEPolicy, and finally exec()'s itself to run in the proper domain.
// The SEPolicy on Android comes in two variants: monolithic and split.
@@ -58,8 +58,10 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/unique_fd.h>
+#include <cutils/android_reboot.h>
#include <selinux/android.h>
+#include "reboot_utils.h"
#include "util.h"
using android::base::ParseInt;
@@ -379,8 +381,6 @@
return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy();
}
-} // namespace
-
void SelinuxInitialize() {
Timer t;
@@ -405,6 +405,8 @@
setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
}
+} // namespace
+
// The files and directories that were created before initial sepolicy load or
// files on ramdisk need to have their security context restored to the proper
// value. This must happen before /dev is populated by ueventd.
@@ -496,6 +498,39 @@
return major_version;
}
+// This function initializes SELinux then execs init to run in the init SELinux context.
+int SetupSelinux(char** argv) {
+ android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
+ RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+ });
+
+ if (REBOOT_BOOTLOADER_ON_PANIC) {
+ InstallRebootSignalHandlers();
+ }
+
+ // Set up SELinux, loading the SELinux policy.
+ SelinuxSetupKernelLogging();
+ SelinuxInitialize();
+
+ // We're in the kernel domain and want to transition to the init domain. File systems that
+ // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
+ // but other file systems do. In particular, this is needed for ramdisks such as the
+ // recovery image for A/B devices.
+ if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
+ PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
+ }
+
+ const char* path = "/system/bin/init";
+ const char* args[] = {path, "second_stage", nullptr};
+ execv(path, const_cast<char**>(args));
+
+ // execv() only returns if an error happened, in which case we
+ // panic and never return from this function.
+ PLOG(FATAL) << "execv(\"" << path << "\") failed";
+
+ return 1;
+}
+
// selinux_android_file_context_handle() takes on the order of 10+ms to run, so we want to cache
// its value. selinux_android_restorecon() also needs an sehandle for file context look up. It
// will create and store its own copy, but selinux_android_set_sehandle() can be used to provide
diff --git a/init/selinux.h b/init/selinux.h
index c41d7f0..3aa9406 100644
--- a/init/selinux.h
+++ b/init/selinux.h
@@ -23,7 +23,7 @@
namespace android {
namespace init {
-void SelinuxInitialize();
+int SetupSelinux(char** argv);
void SelinuxRestoreContext();
void SelinuxSetupKernelLogging();
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 8cf2128..d6765b7 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -87,8 +87,8 @@
}
UeventListener::UeventListener() {
- // is 2MB enough? udev uses 128MB!
- device_fd_.reset(uevent_open_socket(2 * 1024 * 1024, true));
+ // is 16MB enough? udev uses 128MB!
+ device_fd_.reset(uevent_open_socket(16 * 1024 * 1024, true));
if (device_fd_ == -1) {
LOG(FATAL) << "Could not open uevent socket";
}
diff --git a/libcutils/uevent.cpp b/libcutils/uevent.cpp
index 2dfceed..721de7c 100644
--- a/libcutils/uevent.cpp
+++ b/libcutils/uevent.cpp
@@ -95,6 +95,8 @@
int uevent_open_socket(int buf_sz, bool passcred) {
struct sockaddr_nl addr;
int on = passcred;
+ int buf_sz_readback = 0;
+ socklen_t optlen = sizeof(buf_sz_readback);
int s;
memset(&addr, 0, sizeof(addr));
@@ -105,11 +107,21 @@
s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
if (s < 0) return -1;
- /* buf_sz should be less than net.core.rmem_max for this to succeed */
- if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) {
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0 ||
+ getsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz_readback, &optlen) < 0) {
close(s);
return -1;
}
+ /* Only if SO_RCVBUF was not effective, try SO_RCVBUFFORCE. Generally, we
+ * want to avoid SO_RCVBUFFORCE, because it generates SELinux denials in
+ * case we don't have CAP_NET_ADMIN. This is the case, for example, for
+ * healthd. */
+ if (buf_sz_readback < 2 * buf_sz) {
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz)) < 0) {
+ close(s);
+ return -1;
+ }
+ }
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 2403ad0..89837f7 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -35,6 +35,13 @@
end = begin + 1;
}
Range range{begin, end};
+ if (valid_mappings_range_.end != 0 &&
+ (begin < valid_mappings_range_.begin || end > valid_mappings_range_.end)) {
+ MEM_LOG_ALWAYS_FATAL("allocation %p-%p is outside mapping range %p-%p",
+ reinterpret_cast<void*>(begin), reinterpret_cast<void*>(end),
+ reinterpret_cast<void*>(valid_mappings_range_.begin),
+ reinterpret_cast<void*>(valid_mappings_range_.end));
+ }
auto inserted = allocations_.insert(std::pair<Range, AllocationInfo>(range, AllocationInfo{}));
if (inserted.second) {
valid_allocations_range_.begin = std::min(valid_allocations_range_.begin, begin);
@@ -76,15 +83,22 @@
Range range = to_do.back();
to_do.pop_back();
+ walking_range_ = range;
ForEachPtrInRange(range, [&](Range& ref_range, AllocationInfo* ref_info) {
if (!ref_info->referenced_from_root) {
ref_info->referenced_from_root = true;
to_do.push_back(ref_range);
}
});
+ walking_range_ = Range{0, 0};
}
}
+void HeapWalker::Mapping(uintptr_t begin, uintptr_t end) {
+ valid_mappings_range_.begin = std::min(valid_mappings_range_.begin, begin);
+ valid_mappings_range_.end = std::max(valid_mappings_range_.end, end);
+}
+
void HeapWalker::Root(uintptr_t begin, uintptr_t end) {
roots_.push_back(Range{begin, end});
}
@@ -113,6 +127,10 @@
RecurseRoot(vals);
+ if (segv_page_count_ > 0) {
+ MEM_ALOGE("%zu pages skipped due to segfaults", segv_page_count_);
+ }
+
return true;
}
@@ -168,7 +186,15 @@
handler.reset();
return;
}
- MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (!segv_logged_) {
+ MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (walking_range_.begin != 0U) {
+ MEM_ALOGW("while walking range %p-%p", reinterpret_cast<void*>(walking_range_.begin),
+ reinterpret_cast<void*>(walking_range_.end));
+ }
+ segv_logged_ = true;
+ }
+ segv_page_count_++;
if (!MapOverPage(si->si_addr)) {
handler.reset();
}
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 92a8325..9e3db08 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -53,9 +53,14 @@
roots_(allocator),
root_vals_(allocator),
segv_handler_(),
- walking_ptr_(0) {
+ walking_ptr_(0),
+ walking_range_{0, 0},
+ segv_logged_(false),
+ segv_page_count_(0) {
valid_allocations_range_.end = 0;
valid_allocations_range_.begin = ~valid_allocations_range_.end;
+ valid_mappings_range_.end = 0;
+ valid_mappings_range_.begin = ~valid_allocations_range_.end;
segv_handler_.install(
SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
@@ -65,6 +70,7 @@
~HeapWalker() {}
bool Allocation(uintptr_t begin, uintptr_t end);
+ void Mapping(uintptr_t begin, uintptr_t end);
void Root(uintptr_t begin, uintptr_t end);
void Root(const allocator::vector<uintptr_t>& vals);
@@ -95,12 +101,16 @@
AllocationMap allocations_;
size_t allocation_bytes_;
Range valid_allocations_range_;
+ Range valid_mappings_range_;
allocator::vector<Range> roots_;
allocator::vector<uintptr_t> root_vals_;
ScopedSignalHandler segv_handler_;
- uintptr_t walking_ptr_;
+ volatile uintptr_t walking_ptr_;
+ Range walking_range_;
+ bool segv_logged_;
+ size_t segv_page_count_;
};
template <class F>
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index b160de9..3d7b8a8 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -87,6 +87,11 @@
const allocator::vector<Mapping>& mappings,
const allocator::vector<uintptr_t>& refs) {
MEM_ALOGI("searching process %d for allocations", pid_);
+
+ for (auto it = mappings.begin(); it != mappings.end(); it++) {
+ heap_walker_.Mapping(it->begin, it->end);
+ }
+
allocator::vector<Mapping> heap_mappings{mappings};
allocator::vector<Mapping> anon_mappings{mappings};
allocator::vector<Mapping> globals_mappings{mappings};
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index 84a0ec6..9610cd6 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -73,6 +73,24 @@
ASSERT_FALSE(heap_walker.Allocation(2, 3));
}
+TEST_F(HeapWalkerTest, mapping) {
+ HeapWalker heap_walker(heap_);
+ heap_walker.Mapping(2, 3);
+ heap_walker.Mapping(4, 5);
+ ASSERT_TRUE(heap_walker.Allocation(2, 3));
+ ASSERT_TRUE(heap_walker.Allocation(4, 5));
+ // space between mappings is not checked, but could be in the future
+ ASSERT_TRUE(heap_walker.Allocation(3, 4));
+
+ // re-enable malloc, ASSERT_DEATH may allocate
+ disable_malloc_.Enable();
+ ASSERT_DEATH({ heap_walker.Allocation(1, 2); }, "0x1-0x2.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(1, 3); }, "0x1-0x3.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(4, 6); }, "0x4-0x6.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(5, 6); }, "0x5-0x6.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(1, 6); }, "0x1-0x6.*outside.*0x2-0x5");
+}
+
#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(buffer)
#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(buffer) + sizeof(buffer))
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 14f82c7..a5e0dc9 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -184,6 +184,7 @@
"tests/MapInfoGetLoadBiasTest.cpp",
"tests/MapsTest.cpp",
"tests/MemoryBufferTest.cpp",
+ "tests/MemoryCacheTest.cpp",
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
@@ -310,6 +311,28 @@
],
}
+//-------------------------------------------------------------------------
+// Benchmarks
+//-------------------------------------------------------------------------
+cc_benchmark {
+ name: "unwind_benchmarks",
+ host_supported: true,
+ defaults: ["libunwindstack_flags"],
+
+ // Disable optimizations so that all of the calls are not optimized away.
+ cflags: [
+ "-O0",
+ ],
+
+ srcs: [
+ "benchmarks/unwind_benchmarks.cpp",
+ ],
+
+ shared_libs: [
+ "libunwindstack",
+ ],
+}
+
// Generates the elf data for use in the tests for .gnu_debugdata frames.
// Once these files are generated, use the xz command to compress the data.
cc_binary_host {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index cfa8c6d..a30d65e 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -174,6 +174,13 @@
return std::shared_ptr<Memory>(new MemoryRemote(pid));
}
+std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
+ if (pid == getpid()) {
+ return std::shared_ptr<Memory>(new MemoryCache(new MemoryLocal()));
+ }
+ return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
+}
+
size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
if (addr >= raw_.size()) {
return 0;
@@ -398,4 +405,50 @@
return 0;
}
+size_t MemoryCache::Read(uint64_t addr, void* dst, size_t size) {
+ // Only bother caching and looking at the cache if this is a small read for now.
+ if (size > 64) {
+ return impl_->Read(addr, dst, size);
+ }
+
+ uint64_t addr_page = addr >> kCacheBits;
+ auto entry = cache_.find(addr_page);
+ uint8_t* cache_dst;
+ if (entry != cache_.end()) {
+ cache_dst = entry->second;
+ } else {
+ cache_dst = cache_[addr_page];
+ if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+ // Erase the entry.
+ cache_.erase(addr_page);
+ return impl_->Read(addr, dst, size);
+ }
+ }
+ size_t max_read = ((addr_page + 1) << kCacheBits) - addr;
+ if (size <= max_read) {
+ memcpy(dst, &cache_dst[addr & kCacheMask], size);
+ return size;
+ }
+
+ // The read crossed into another cached entry, since a read can only cross
+ // into one extra cached page, duplicate the code rather than looping.
+ memcpy(dst, &cache_dst[addr & kCacheMask], max_read);
+ dst = &reinterpret_cast<uint8_t*>(dst)[max_read];
+ addr_page++;
+
+ entry = cache_.find(addr_page);
+ if (entry != cache_.end()) {
+ cache_dst = entry->second;
+ } else {
+ cache_dst = cache_[addr_page];
+ if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+ // Erase the entry.
+ cache_.erase(addr_page);
+ return impl_->Read(addr_page << kCacheBits, dst, size - max_read) + max_read;
+ }
+ }
+ memcpy(dst, cache_dst, size - max_read);
+ return size;
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
new file mode 100644
index 0000000..db0fb54
--- /dev/null
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <memory>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
+
+size_t Call6(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+ unwindstack::RegsGetLocal(regs.get());
+ unwindstack::Unwinder unwinder(32, maps, regs.get(), process_memory);
+ unwinder.Unwind();
+ return unwinder.NumFrames();
+}
+
+size_t Call5(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call6(process_memory, maps);
+}
+
+size_t Call4(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call5(process_memory, maps);
+}
+
+size_t Call3(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call4(process_memory, maps);
+}
+
+size_t Call2(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call3(process_memory, maps);
+}
+
+size_t Call1(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call2(process_memory, maps);
+}
+
+static void BM_uncached_unwind(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
+ unwindstack::LocalMaps maps;
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ }
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(Call1(process_memory, &maps));
+ }
+}
+BENCHMARK(BM_uncached_unwind);
+
+static void BM_cached_unwind(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ unwindstack::LocalMaps maps;
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ }
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(Call1(process_memory, &maps));
+ }
+}
+BENCHMARK(BM_cached_unwind);
+
+BENCHMARK_MAIN();
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 9c425cb..dba41d1 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -25,6 +25,7 @@
#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
namespace unwindstack {
@@ -35,9 +36,12 @@
virtual ~Memory() = default;
static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
+ static std::shared_ptr<Memory> CreateProcessMemoryCached(pid_t pid);
virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
+ virtual void Clear() {}
+
virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
bool ReadFully(uint64_t addr, void* dst, size_t size);
@@ -51,6 +55,24 @@
}
};
+class MemoryCache : public Memory {
+ public:
+ MemoryCache(Memory* memory) : impl_(memory) {}
+ virtual ~MemoryCache() = default;
+
+ size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ void Clear() override { cache_.clear(); }
+
+ private:
+ constexpr static size_t kCacheBits = 12;
+ constexpr static size_t kCacheMask = (1 << kCacheBits) - 1;
+ constexpr static size_t kCacheSize = 1 << kCacheBits;
+ std::unordered_map<uint64_t, uint8_t[kCacheSize]> cache_;
+
+ std::unique_ptr<Memory> impl_;
+};
+
class MemoryBuffer : public Memory {
public:
MemoryBuffer() = default;
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
new file mode 100644
index 0000000..a3def20
--- /dev/null
+++ b/libunwindstack/tests/MemoryCacheTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Memory.h>
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class MemoryCacheTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ memory_ = new MemoryFake;
+ memory_cache_.reset(new MemoryCache(memory_));
+
+ memory_->SetMemoryBlock(0x8000, 4096, 0xab);
+ memory_->SetMemoryBlock(0x9000, 4096, 0xde);
+ memory_->SetMemoryBlock(0xa000, 3000, 0x50);
+ }
+
+ MemoryFake* memory_;
+ std::unique_ptr<MemoryCache> memory_cache_;
+
+ constexpr static size_t kMaxCachedSize = 64;
+};
+
+TEST_F(MemoryCacheTest, cached_read) {
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, no_cached_read_after_clear) {
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is not used after a reset.
+ memory_cache_->Clear();
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, cached_read_across_caches) {
+ std::vector<uint8_t> expect(16, 0xab);
+ expect.resize(32, 0xde);
+
+ std::vector<uint8_t> buffer(32);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+
+ // Verify the cached data is used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ memory_->SetMemoryBlock(0x9000, 4096, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+}
+
+TEST_F(MemoryCacheTest, no_cache_read) {
+ for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is not used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail) {
+ std::vector<uint8_t> buffer(kMaxCachedSize);
+ ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+ ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0x50), buffer);
+
+ // Verify the cached data is not used.
+ memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+ ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0xff), buffer);
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail_cross) {
+ std::vector<uint8_t> expect(16, 0xde);
+ expect.resize(32, 0x50);
+
+ std::vector<uint8_t> buffer(32);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+
+ // Verify the cached data is not used for the second half but for the first.
+ memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+ expect.resize(16);
+ expect.resize(32, 0xff);
+ ASSERT_EQ(expect, buffer);
+}
+
+} // namespace unwindstack
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 2095189..9538bba 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -125,6 +125,7 @@
enabled: true,
},
},
+ test_suites: ["device-tests"],
}
// Performance benchmarks.
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index fc8c960..18d5287 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -165,9 +165,14 @@
bug_num->assign("");
}
+ // Ensure the uid name is not null before passing it to the bug string.
if (uid >= AID_APP_START && uid <= AID_APP_END) {
- bug_num->append(" app=");
- bug_num->append(android::uidToName(uid));
+ char* uidname = android::uidToName(uid);
+ if (uidname) {
+ bug_num->append(" app=");
+ bug_num->append(uidname);
+ free(uidname);
+ }
}
}
diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp
index 70f6faa..6637deb 100644
--- a/property_service/libpropertyinfoparser/Android.bp
+++ b/property_service/libpropertyinfoparser/Android.bp
@@ -12,5 +12,6 @@
"-Werror",
],
stl: "none",
+ system_shared_libs: [],
export_include_dirs: ["include"],
}
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index ca6aafe..461184a 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -6,35 +6,40 @@
# All binaries gets the same configuration 'legacy'
dir.legacy = /system
+dir.legacy = /product
dir.legacy = /vendor
dir.legacy = /odm
dir.legacy = /sbin
-# Except for /postinstall, where only /system is searched
+# Except for /postinstall, where only /system and /product are searched
dir.postinstall = /postinstall
[legacy]
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /product/${LIB}
namespace.default.search.paths += /vendor/${LIB}
namespace.default.search.paths += /odm/${LIB}
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/product/${LIB}
+namespace.default.asan.search.paths += /product/${LIB}
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths += /odm/${LIB}
###############################################################################
# Namespace config for binaries under /postinstall.
# Only one default namespace is defined and it has no directories other than
-# /system/lib in the search paths. This is because linker calls realpath on the
-# search paths and this causes selinux denial if the paths (/vendor, /odm) are
-# not allowed to the poinstall binaries. There is no reason to allow the
-# binaries to access the paths.
+# /system/lib and /product/lib in the search paths. This is because linker
+# calls realpath on the search paths and this causes selinux denial if the
+# paths (/vendor, /odm) are not allowed to the poinstall binaries.
+# There is no reason to allow the binaries to access the paths.
###############################################################################
[postinstall]
namespace.default.isolated = false
-namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /product/${LIB}
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 2f85dec..d47506c 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -72,7 +72,7 @@
/dev/diag_arm9 0660 radio radio
/dev/ttyMSM0 0600 bluetooth bluetooth
/dev/uhid 0660 uhid uhid
-/dev/uinput 0660 system bluetooth
+/dev/uinput 0660 uhid uhid
/dev/alarm 0664 system radio
/dev/rtc0 0640 system system
/dev/tty0 0660 root system