Merge "Create /metadata/staged-install dir to store staged install failure reasons" into rvc-dev
diff --git a/adb/Android.bp b/adb/Android.bp
index 0394bf6..f8e5b38 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -567,7 +567,6 @@
cc_binary {
name: "adbd",
defaults: ["adbd_defaults", "host_adbd_supported", "libadbd_binary_dependencies"],
- stl: "libc++_static",
recovery_available: true,
apex_available: ["com.android.adbd"],
@@ -679,6 +678,8 @@
"mdns_test.cpp",
],
+ test_config: "adb_test.xml",
+
shared_libs: [
"liblog",
],
diff --git a/adb/adb_test.xml b/adb/adb_test.xml
new file mode 100644
index 0000000..cc3302d
--- /dev/null
+++ b/adb/adb_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Runs adbd_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="adbd_test->/data/local/tmp/adbd_test" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="adbd_test" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.adbd" />
+ </object>
+</configuration>
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 092a866..f2de0d2 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -155,6 +155,14 @@
*buf = '\0';
}
+static unique_fd send_command(const std::vector<std::string>& cmd_args, std::string* error) {
+ if (is_abb_exec_supported()) {
+ return send_abb_exec_command(cmd_args, error);
+ } else {
+ return unique_fd(adb_connect(android::base::Join(cmd_args, " "), error));
+ }
+}
+
static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy) {
printf("Performing Streamed Install\n");
@@ -227,12 +235,7 @@
cmd_args.push_back("--apex");
}
- unique_fd remote_fd;
- if (use_abb_exec) {
- remote_fd = send_abb_exec_command(cmd_args, &error);
- } else {
- remote_fd.reset(adb_connect(android::base::Join(cmd_args, " "), &error));
- }
+ unique_fd remote_fd = send_command(cmd_args, &error);
if (remote_fd < 0) {
fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
return 1;
@@ -299,7 +302,7 @@
}
template <class TimePoint>
-static int msBetween(TimePoint start, TimePoint end) {
+static int ms_between(TimePoint start, TimePoint end) {
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
@@ -308,7 +311,7 @@
const auto start = clock::now();
int first_apk = -1;
int last_apk = -1;
- std::vector<std::string_view> args = {"package"sv};
+ incremental::Args passthrough_args = {};
for (int i = 0; i < argc; ++i) {
const auto arg = std::string_view(argv[i]);
if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) {
@@ -316,12 +319,11 @@
if (first_apk == -1) {
first_apk = i;
}
- } else if (arg.starts_with("install-"sv)) {
+ } else if (arg.starts_with("install"sv)) {
// incremental installation command on the device is the same for all its variations in
// the adb, e.g. install-multiple or install-multi-package
- args.push_back("install"sv);
} else {
- args.push_back(arg);
+ passthrough_args.push_back(arg);
}
}
@@ -342,13 +344,13 @@
}
printf("Performing Incremental Install\n");
- auto server_process = incremental::install(files, silent);
+ auto server_process = incremental::install(files, passthrough_args, silent);
if (!server_process) {
return -1;
}
const auto end = clock::now();
- printf("Install command complete in %d ms\n", msBetween(start, end));
+ printf("Install command complete in %d ms\n", ms_between(start, end));
if (wait) {
(*server_process).wait();
@@ -357,9 +359,9 @@
return 0;
}
-static std::pair<InstallMode, std::optional<InstallMode>> calculateInstallMode(
- InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incrementalRequest) {
- if (incrementalRequest == CmdlineOption::Enable) {
+static std::pair<InstallMode, std::optional<InstallMode>> calculate_install_mode(
+ InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incremental_request) {
+ if (incremental_request == CmdlineOption::Enable) {
if (fastdeploy) {
error_exit(
"--incremental and --fast-deploy options are incompatible. "
@@ -368,30 +370,30 @@
}
if (modeFromArgs != INSTALL_DEFAULT) {
- if (incrementalRequest == CmdlineOption::Enable) {
+ if (incremental_request == CmdlineOption::Enable) {
error_exit("--incremental is not compatible with other installation modes");
}
return {modeFromArgs, std::nullopt};
}
- if (incrementalRequest != CmdlineOption::Disable && !is_abb_exec_supported()) {
- if (incrementalRequest == CmdlineOption::None) {
- incrementalRequest = CmdlineOption::Disable;
+ if (incremental_request != CmdlineOption::Disable && !is_abb_exec_supported()) {
+ if (incremental_request == CmdlineOption::None) {
+ incremental_request = CmdlineOption::Disable;
} else {
error_exit("Device doesn't support incremental installations");
}
}
- if (incrementalRequest == CmdlineOption::None) {
+ if (incremental_request == CmdlineOption::None) {
// check if the host is ok with incremental by default
if (const char* incrementalFromEnv = getenv("ADB_INSTALL_DEFAULT_INCREMENTAL")) {
using namespace android::base;
auto val = ParseBool(incrementalFromEnv);
if (val == ParseBoolResult::kFalse) {
- incrementalRequest = CmdlineOption::Disable;
+ incremental_request = CmdlineOption::Disable;
}
}
}
- if (incrementalRequest == CmdlineOption::None) {
+ if (incremental_request == CmdlineOption::None) {
// still ok: let's see if the device allows using incremental by default
// it starts feeling like we're looking for an excuse to not to use incremental...
std::string error;
@@ -407,17 +409,17 @@
using namespace android::base;
auto val = ParseBool(buf);
if (val == ParseBoolResult::kFalse) {
- incrementalRequest = CmdlineOption::Disable;
+ incremental_request = CmdlineOption::Disable;
}
}
}
- if (incrementalRequest == CmdlineOption::Enable) {
+ if (incremental_request == CmdlineOption::Enable) {
// explicitly requested - no fallback
return {INSTALL_INCREMENTAL, std::nullopt};
}
const auto bestMode = best_install_mode();
- if (incrementalRequest == CmdlineOption::None) {
+ if (incremental_request == CmdlineOption::None) {
// no opinion - use incremental, fallback to regular on a failure.
return {INSTALL_INCREMENTAL, bestMode};
}
@@ -425,57 +427,75 @@
return {bestMode, std::nullopt};
}
-int install_app(int argc, const char** argv) {
- std::vector<int> processedArgIndices;
- InstallMode installMode = INSTALL_DEFAULT;
- bool use_fastdeploy = false;
- bool is_reinstall = false;
- bool wait = false;
- auto incremental_request = CmdlineOption::None;
- FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+static std::vector<const char*> parse_install_mode(std::vector<const char*> argv,
+ InstallMode* install_mode,
+ CmdlineOption* incremental_request,
+ bool* incremental_wait) {
+ *install_mode = INSTALL_DEFAULT;
+ *incremental_request = CmdlineOption::None;
+ *incremental_wait = false;
- for (int i = 1; i < argc; i++) {
- if (argv[i] == "--streaming"sv) {
- processedArgIndices.push_back(i);
- installMode = INSTALL_STREAM;
- } else if (argv[i] == "--no-streaming"sv) {
- processedArgIndices.push_back(i);
- installMode = INSTALL_PUSH;
- } else if (argv[i] == "-r"sv) {
- // Note that this argument is not added to processedArgIndices because it
- // must be passed through to pm
- is_reinstall = true;
- } else if (argv[i] == "--fastdeploy"sv) {
- processedArgIndices.push_back(i);
- use_fastdeploy = true;
- } else if (argv[i] == "--no-fastdeploy"sv) {
- processedArgIndices.push_back(i);
- use_fastdeploy = false;
- } else if (argv[i] == "--force-agent"sv) {
- processedArgIndices.push_back(i);
- agent_update_strategy = FastDeploy_AgentUpdateAlways;
- } else if (argv[i] == "--date-check-agent"sv) {
- processedArgIndices.push_back(i);
- agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
- } else if (argv[i] == "--version-check-agent"sv) {
- processedArgIndices.push_back(i);
- agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
- } else if (strlen(argv[i]) >= "--incr"sv.size() && "--incremental"sv.starts_with(argv[i])) {
- processedArgIndices.push_back(i);
- incremental_request = CmdlineOption::Enable;
- } else if (strlen(argv[i]) >= "--no-incr"sv.size() &&
- "--no-incremental"sv.starts_with(argv[i])) {
- processedArgIndices.push_back(i);
- incremental_request = CmdlineOption::Disable;
- } else if (argv[i] == "--wait"sv) {
- processedArgIndices.push_back(i);
- wait = true;
+ std::vector<const char*> passthrough;
+ for (auto&& arg : argv) {
+ if (arg == "--streaming"sv) {
+ *install_mode = INSTALL_STREAM;
+ } else if (arg == "--no-streaming"sv) {
+ *install_mode = INSTALL_PUSH;
+ } else if (strlen(arg) >= "--incr"sv.size() && "--incremental"sv.starts_with(arg)) {
+ *incremental_request = CmdlineOption::Enable;
+ } else if (strlen(arg) >= "--no-incr"sv.size() && "--no-incremental"sv.starts_with(arg)) {
+ *incremental_request = CmdlineOption::Disable;
+ } else if (arg == "--wait"sv) {
+ *incremental_wait = true;
+ } else {
+ passthrough.push_back(arg);
}
}
+ return passthrough;
+}
- auto [primaryMode, fallbackMode] =
- calculateInstallMode(installMode, use_fastdeploy, incremental_request);
- if ((primaryMode == INSTALL_STREAM || fallbackMode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
+static std::vector<const char*> parse_fast_deploy_mode(
+ std::vector<const char*> argv, bool* use_fastdeploy,
+ FastDeploy_AgentUpdateStrategy* agent_update_strategy) {
+ *use_fastdeploy = false;
+ *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+
+ std::vector<const char*> passthrough;
+ for (auto&& arg : argv) {
+ if (arg == "--fastdeploy"sv) {
+ *use_fastdeploy = true;
+ } else if (arg == "--no-fastdeploy"sv) {
+ *use_fastdeploy = false;
+ } else if (arg == "--force-agent"sv) {
+ *agent_update_strategy = FastDeploy_AgentUpdateAlways;
+ } else if (arg == "--date-check-agent"sv) {
+ *agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
+ } else if (arg == "--version-check-agent"sv) {
+ *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+ } else {
+ passthrough.push_back(arg);
+ }
+ }
+ return passthrough;
+}
+
+int install_app(int argc, const char** argv) {
+ InstallMode install_mode = INSTALL_DEFAULT;
+ auto incremental_request = CmdlineOption::None;
+ bool incremental_wait = false;
+
+ bool use_fastdeploy = false;
+ FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+
+ auto unused_argv = parse_install_mode({argv, argv + argc}, &install_mode, &incremental_request,
+ &incremental_wait);
+ auto passthrough_argv =
+ parse_fast_deploy_mode(std::move(unused_argv), &use_fastdeploy, &agent_update_strategy);
+
+ auto [primary_mode, fallback_mode] =
+ calculate_install_mode(install_mode, use_fastdeploy, incremental_request);
+ if ((primary_mode == INSTALL_STREAM ||
+ fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
best_install_mode() == INSTALL_PUSH) {
error_exit("Attempting to use streaming install on unsupported device");
}
@@ -489,19 +509,12 @@
}
fastdeploy_set_agent_update_strategy(agent_update_strategy);
- std::vector<const char*> passthrough_argv;
- for (int i = 0; i < argc; i++) {
- if (std::find(processedArgIndices.begin(), processedArgIndices.end(), i) ==
- processedArgIndices.end()) {
- passthrough_argv.push_back(argv[i]);
- }
- }
if (passthrough_argv.size() < 2) {
error_exit("install requires an apk argument");
}
- auto runInstallMode = [&](InstallMode installMode, bool silent) {
- switch (installMode) {
+ auto run_install_mode = [&](InstallMode install_mode, bool silent) {
+ switch (install_mode) {
case INSTALL_PUSH:
return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
use_fastdeploy);
@@ -510,20 +523,20 @@
use_fastdeploy);
case INSTALL_INCREMENTAL:
return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(),
- wait, silent);
+ incremental_wait, silent);
case INSTALL_DEFAULT:
default:
- return 1;
+ error_exit("invalid install mode");
}
};
- auto res = runInstallMode(primaryMode, fallbackMode.has_value());
- if (res && fallbackMode.value_or(primaryMode) != primaryMode) {
- res = runInstallMode(*fallbackMode, false);
+ auto res = run_install_mode(primary_mode, fallback_mode.has_value());
+ if (res && fallback_mode.value_or(primary_mode) != primary_mode) {
+ res = run_install_mode(*fallback_mode, false);
}
return res;
}
-int install_multiple_app(int argc, const char** argv) {
+static int install_multiple_app_streamed(int argc, const char** argv) {
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
int first_apk = -1;
@@ -548,24 +561,27 @@
if (first_apk == -1) error_exit("need APK file on command line");
- std::string install_cmd;
- if (best_install_mode() == INSTALL_PUSH) {
- install_cmd = "exec:pm";
- } else {
- install_cmd = "exec:cmd package";
- }
+ const bool use_abb_exec = is_abb_exec_supported();
+ const std::string install_cmd =
+ use_abb_exec ? "package"
+ : best_install_mode() == INSTALL_PUSH ? "exec:pm" : "exec:cmd package";
- std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64,
- install_cmd.c_str(), total_size);
+ std::vector<std::string> cmd_args = {install_cmd, "install-create", "-S",
+ std::to_string(total_size)};
+ cmd_args.reserve(first_apk + 4);
for (int i = 1; i < first_apk; i++) {
- cmd += " " + escape_arg(argv[i]);
+ if (use_abb_exec) {
+ cmd_args.push_back(argv[i]);
+ } else {
+ cmd_args.push_back(escape_arg(argv[i]));
+ }
}
// Create install session
std::string error;
char buf[BUFSIZ];
{
- unique_fd fd(adb_connect(cmd, &error));
+ unique_fd fd = send_command(cmd_args, &error);
if (fd < 0) {
fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
return EXIT_FAILURE;
@@ -587,6 +603,7 @@
fputs(buf, stderr);
return EXIT_FAILURE;
}
+ const auto session_id_str = std::to_string(session_id);
// Valid session, now stream the APKs
bool success = true;
@@ -599,10 +616,15 @@
goto finalize_session;
}
- std::string cmd =
- android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %s -",
- install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
- session_id, android::base::Basename(file).c_str());
+ std::vector<std::string> cmd_args = {
+ install_cmd,
+ "install-write",
+ "-S",
+ std::to_string(sb.st_size),
+ session_id_str,
+ android::base::Basename(file),
+ "-",
+ };
unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
if (local_fd < 0) {
@@ -612,7 +634,7 @@
}
std::string error;
- unique_fd remote_fd(adb_connect(cmd, &error));
+ unique_fd remote_fd = send_command(cmd_args, &error);
if (remote_fd < 0) {
fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
success = false;
@@ -637,10 +659,13 @@
finalize_session:
// Commit session if we streamed everything okay; otherwise abandon.
- std::string service = android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
- success ? "commit" : "abandon", session_id);
+ std::vector<std::string> service_args = {
+ install_cmd,
+ success ? "install-commit" : "install-abandon",
+ session_id_str,
+ };
{
- unique_fd fd(adb_connect(service, &error));
+ unique_fd fd = send_command(service_args, &error);
if (fd < 0) {
fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
return EXIT_FAILURE;
@@ -659,6 +684,44 @@
return EXIT_SUCCESS;
}
+int install_multiple_app(int argc, const char** argv) {
+ InstallMode install_mode = INSTALL_DEFAULT;
+ auto incremental_request = CmdlineOption::None;
+ bool incremental_wait = false;
+ bool use_fastdeploy = false;
+
+ auto passthrough_argv = parse_install_mode({argv + 1, argv + argc}, &install_mode,
+ &incremental_request, &incremental_wait);
+
+ auto [primary_mode, fallback_mode] =
+ calculate_install_mode(install_mode, use_fastdeploy, incremental_request);
+ if ((primary_mode == INSTALL_STREAM ||
+ fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
+ best_install_mode() == INSTALL_PUSH) {
+ error_exit("Attempting to use streaming install on unsupported device");
+ }
+
+ auto run_install_mode = [&](InstallMode install_mode, bool silent) {
+ switch (install_mode) {
+ case INSTALL_PUSH:
+ case INSTALL_STREAM:
+ return install_multiple_app_streamed(passthrough_argv.size(),
+ passthrough_argv.data());
+ case INSTALL_INCREMENTAL:
+ return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(),
+ incremental_wait, silent);
+ case INSTALL_DEFAULT:
+ default:
+ error_exit("invalid install mode");
+ }
+ };
+ auto res = run_install_mode(primary_mode, fallback_mode.has_value());
+ if (res && fallback_mode.value_or(primary_mode) != primary_mode) {
+ res = run_install_mode(*fallback_mode, false);
+ }
+ return res;
+}
+
int install_multi_package(int argc, const char** argv) {
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
@@ -683,23 +746,31 @@
fprintf(stderr, "adb: multi-package install is not supported on this device\n");
return EXIT_FAILURE;
}
- std::string install_cmd = "exec:cmd package";
- std::string multi_package_cmd =
- android::base::StringPrintf("%s install-create --multi-package", install_cmd.c_str());
+ const bool use_abb_exec = is_abb_exec_supported();
+ const std::string install_cmd = use_abb_exec ? "package" : "exec:cmd package";
+
+ std::vector<std::string> multi_package_cmd_args = {install_cmd, "install-create",
+ "--multi-package"};
+
+ multi_package_cmd_args.reserve(first_package + 4);
for (int i = 1; i < first_package; i++) {
- multi_package_cmd += " " + escape_arg(argv[i]);
+ if (use_abb_exec) {
+ multi_package_cmd_args.push_back(argv[i]);
+ } else {
+ multi_package_cmd_args.push_back(escape_arg(argv[i]));
+ }
}
if (apex_found) {
- multi_package_cmd += " --staged";
+ multi_package_cmd_args.emplace_back("--staged");
}
// Create multi-package install session
std::string error;
char buf[BUFSIZ];
{
- unique_fd fd(adb_connect(multi_package_cmd, &error));
+ unique_fd fd = send_command(multi_package_cmd_args, &error);
if (fd < 0) {
fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
return EXIT_FAILURE;
@@ -721,6 +792,7 @@
fputs(buf, stderr);
return EXIT_FAILURE;
}
+ const auto parent_session_id_str = std::to_string(parent_session_id);
fprintf(stdout, "Created parent session ID %d.\n", parent_session_id);
@@ -728,17 +800,30 @@
// Valid session, now create the individual sessions and stream the APKs
int success = EXIT_FAILURE;
- std::string individual_cmd =
- android::base::StringPrintf("%s install-create", install_cmd.c_str());
- std::string all_session_ids = "";
+ std::vector<std::string> individual_cmd_args = {install_cmd, "install-create"};
for (int i = 1; i < first_package; i++) {
- individual_cmd += " " + escape_arg(argv[i]);
+ if (use_abb_exec) {
+ individual_cmd_args.push_back(argv[i]);
+ } else {
+ individual_cmd_args.push_back(escape_arg(argv[i]));
+ }
}
if (apex_found) {
- individual_cmd += " --staged";
+ individual_cmd_args.emplace_back("--staged");
}
- std::string individual_apex_cmd = individual_cmd + " --apex";
- std::string cmd = "";
+
+ std::vector<std::string> individual_apex_cmd_args;
+ if (apex_found) {
+ individual_apex_cmd_args = individual_cmd_args;
+ individual_apex_cmd_args.emplace_back("--apex");
+ }
+
+ std::vector<std::string> add_session_cmd_args = {
+ install_cmd,
+ "install-add-session",
+ parent_session_id_str,
+ };
+
for (int i = first_package; i < argc; i++) {
const char* file = argv[i];
char buf[BUFSIZ];
@@ -746,9 +831,9 @@
unique_fd fd;
// Create individual install session
if (android::base::EndsWithIgnoreCase(file, ".apex")) {
- fd.reset(adb_connect(individual_apex_cmd, &error));
+ fd = send_command(individual_apex_cmd_args, &error);
} else {
- fd.reset(adb_connect(individual_cmd, &error));
+ fd = send_command(individual_cmd_args, &error);
}
if (fd < 0) {
fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
@@ -771,6 +856,7 @@
fputs(buf, stderr);
goto finalize_multi_package_session;
}
+ const auto session_id_str = std::to_string(session_id);
fprintf(stdout, "Created child session ID %d.\n", session_id);
session_ids.push_back(session_id);
@@ -785,10 +871,15 @@
goto finalize_multi_package_session;
}
- std::string cmd = android::base::StringPrintf(
- "%s install-write -S %" PRIu64 " %d %d_%s -", install_cmd.c_str(),
- static_cast<uint64_t>(sb.st_size), session_id, i,
- android::base::Basename(split).c_str());
+ std::vector<std::string> cmd_args = {
+ install_cmd,
+ "install-write",
+ "-S",
+ std::to_string(sb.st_size),
+ session_id_str,
+ android::base::StringPrintf("%d_%s", i, android::base::Basename(file).c_str()),
+ "-",
+ };
unique_fd local_fd(adb_open(split.c_str(), O_RDONLY | O_CLOEXEC));
if (local_fd < 0) {
@@ -797,7 +888,7 @@
}
std::string error;
- unique_fd remote_fd(adb_connect(cmd, &error));
+ unique_fd remote_fd = send_command(cmd_args, &error);
if (remote_fd < 0) {
fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
goto finalize_multi_package_session;
@@ -816,13 +907,11 @@
goto finalize_multi_package_session;
}
}
- all_session_ids += android::base::StringPrintf(" %d", session_id);
+ add_session_cmd_args.push_back(std::to_string(session_id));
}
- cmd = android::base::StringPrintf("%s install-add-session %d%s", install_cmd.c_str(),
- parent_session_id, all_session_ids.c_str());
{
- unique_fd fd(adb_connect(cmd, &error));
+ unique_fd fd = send_command(add_session_cmd_args, &error);
if (fd < 0) {
fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str());
goto finalize_multi_package_session;
@@ -831,7 +920,8 @@
}
if (strncmp("Success", buf, 7)) {
- fprintf(stderr, "adb: failed to link sessions (%s)\n", cmd.c_str());
+ fprintf(stderr, "adb: failed to link sessions (%s)\n",
+ android::base::Join(add_session_cmd_args, " ").c_str());
fputs(buf, stderr);
goto finalize_multi_package_session;
}
@@ -841,11 +931,14 @@
finalize_multi_package_session:
// Commit session if we streamed everything okay; otherwise abandon
- std::string service =
- android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
- success == 0 ? "commit" : "abandon", parent_session_id);
+ std::vector<std::string> service_args = {
+ install_cmd,
+ success == 0 ? "install-commit" : "install-abandon",
+ parent_session_id_str,
+ };
+
{
- unique_fd fd(adb_connect(service, &error));
+ unique_fd fd = send_command(service_args, &error);
if (fd < 0) {
fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
return EXIT_FAILURE;
@@ -866,10 +959,13 @@
session_ids.push_back(parent_session_id);
// try to abandon all remaining sessions
for (std::size_t i = 0; i < session_ids.size(); i++) {
- service = android::base::StringPrintf("%s install-abandon %d", install_cmd.c_str(),
- session_ids[i]);
+ std::vector<std::string> service_args = {
+ install_cmd,
+ "install-abandon",
+ std::to_string(session_ids[i]),
+ };
fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
- unique_fd fd(adb_connect(service, &error));
+ unique_fd fd = send_command(service_args, &error);
if (fd < 0) {
fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
continue;
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index f56ef9a..c8f69c3 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -93,12 +93,10 @@
// Send install-incremental to the device along with properly configured file descriptors in
// streaming format. Once connection established, send all fs-verity tree bytes.
-static unique_fd start_install(const Files& files, bool silent) {
+static unique_fd start_install(const Files& files, const Args& passthrough_args, bool silent) {
std::vector<std::string> command_args{"package", "install-incremental"};
+ command_args.insert(command_args.end(), passthrough_args.begin(), passthrough_args.end());
- // fd's with positions at the beginning of fs-verity
- std::vector<unique_fd> signature_fds;
- signature_fds.reserve(files.size());
for (int i = 0, size = files.size(); i < size; ++i) {
const auto& file = files[i];
@@ -118,8 +116,6 @@
auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(),
(long long)st.st_size, i, signature.c_str());
command_args.push_back(std::move(file_desc));
-
- signature_fds.push_back(std::move(signature_fd));
}
std::string error;
@@ -150,8 +146,8 @@
return true;
}
-std::optional<Process> install(const Files& files, bool silent) {
- auto connection_fd = start_install(files, silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent) {
+ auto connection_fd = start_install(files, passthrough_args, silent);
if (connection_fd < 0) {
if (!silent) {
fprintf(stderr, "adb: failed to initiate installation on device.\n");
diff --git a/adb/client/incremental.h b/adb/client/incremental.h
index 1fb1e0b..40e928a 100644
--- a/adb/client/incremental.h
+++ b/adb/client/incremental.h
@@ -26,9 +26,10 @@
namespace incremental {
using Files = std::vector<std::string>;
+using Args = std::vector<std::string_view>;
bool can_install(const Files& files);
-std::optional<Process> install(const Files& files, bool silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent);
enum class Result { Success, Failure, None };
Result wait_for_installation(int read_fd);
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 7fff05a..a663871 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -231,7 +231,14 @@
offset += write_size;
}
}
- SubmitWrites();
+
+ // Wake up the worker thread to submit writes.
+ uint64_t notify = 1;
+ ssize_t rc = adb_write(worker_event_fd_.get(), ¬ify, sizeof(notify));
+ if (rc < 0) {
+ PLOG(FATAL) << "failed to notify worker eventfd to submit writes";
+ }
+
return true;
}
@@ -443,6 +450,9 @@
}
ReadEvents();
+
+ std::lock_guard<std::mutex> lock(write_mutex_);
+ SubmitWrites();
}
});
}
@@ -626,8 +636,6 @@
write_requests_.erase(it);
size_t outstanding_writes = --writes_submitted_;
LOG(DEBUG) << "USB write: reaped, down to " << outstanding_writes;
-
- SubmitWrites();
}
IoWriteBlock CreateWriteBlock(std::shared_ptr<Block> payload, size_t offset, size_t len,
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 884856d..cf0f1ac 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -117,8 +117,10 @@
"device/main.cpp",
"device/usb.cpp",
"device/usb_client.cpp",
+ "device/tcp_client.cpp",
"device/utility.cpp",
"device/variables.cpp",
+ "socket.cpp",
],
shared_libs: [
@@ -143,11 +145,13 @@
],
static_libs: [
+ "libgtest_prod",
"libhealthhalutils",
"libsnapshot_nobinder",
],
header_libs: [
+ "avb_headers",
"libsnapshot_headers",
]
}
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index b8eee4a..2553353 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -625,7 +625,7 @@
if (!sm) {
return device->WriteFail("Unable to create SnapshotManager");
}
- if (!sm->HandleImminentDataWipe()) {
+ if (!sm->FinishMergeInRecovery()) {
return device->WriteFail("Unable to finish snapshot merge");
}
} else {
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index bb085c5..1b0859f 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -19,6 +19,7 @@
#include <algorithm>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/fastboot/1.0/IFastboot.h>
@@ -28,6 +29,7 @@
#include "constants.h"
#include "flashing.h"
+#include "tcp_client.h"
#include "usb_client.h"
using android::fs_mgr::EnsurePathUnmounted;
@@ -60,11 +62,16 @@
{FB_CMD_GSI, GsiHandler},
{FB_CMD_SNAPSHOT_UPDATE, SnapshotUpdateHandler},
}),
- transport_(std::make_unique<ClientUsbTransport>()),
boot_control_hal_(IBootControl::getService()),
health_hal_(get_health_service()),
fastboot_hal_(IFastboot::getService()),
active_slot_("") {
+ if (android::base::GetProperty("fastbootd.protocol", "usb") == "tcp") {
+ transport_ = std::make_unique<ClientTcpTransport>();
+ } else {
+ transport_ = std::make_unique<ClientUsbTransport>();
+ }
+
if (boot_control_hal_) {
boot1_1_ = android::hardware::boot::V1_1::IBootControl::castFrom(boot_control_hal_);
}
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 7e7e507..a5f1223 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -31,6 +31,7 @@
#include <ext4_utils/ext4_utils.h>
#include <fs_mgr_overlayfs.h>
#include <fstab/fstab.h>
+#include <libavb/libavb.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
#include <libsnapshot/snapshot.h>
@@ -122,6 +123,27 @@
}
}
+static void CopyAVBFooter(std::vector<char>* data, const uint64_t block_device_size) {
+ if (data->size() < AVB_FOOTER_SIZE) {
+ return;
+ }
+ std::string footer;
+ uint64_t footer_offset = data->size() - AVB_FOOTER_SIZE;
+ for (int idx = 0; idx < AVB_FOOTER_MAGIC_LEN; idx++) {
+ footer.push_back(data->at(footer_offset + idx));
+ }
+ if (0 != footer.compare(AVB_FOOTER_MAGIC)) {
+ return;
+ }
+
+ // copy AVB footer from end of data to end of block device
+ uint64_t original_data_size = data->size();
+ data->resize(block_device_size, 0);
+ for (int idx = 0; idx < AVB_FOOTER_SIZE; idx++) {
+ data->at(block_device_size - 1 - idx) = data->at(original_data_size - 1 - idx);
+ }
+}
+
int Flash(FastbootDevice* device, const std::string& partition_name) {
PartitionHandle handle;
if (!OpenPartition(device, partition_name, &handle)) {
@@ -131,8 +153,14 @@
std::vector<char> data = std::move(device->download_data());
if (data.size() == 0) {
return -EINVAL;
- } else if (data.size() > get_block_device_size(handle.fd())) {
+ }
+ uint64_t block_device_size = get_block_device_size(handle.fd());
+ if (data.size() > block_device_size) {
return -EOVERFLOW;
+ } else if (data.size() < block_device_size &&
+ (partition_name == "boot" || partition_name == "boot_a" ||
+ partition_name == "boot_b")) {
+ CopyAVBFooter(&data, block_device_size);
}
WipeOverlayfsForPartition(device, partition_name);
return FlashBlockDevice(handle.fd(), data);
diff --git a/fastboot/device/tcp_client.cpp b/fastboot/device/tcp_client.cpp
new file mode 100644
index 0000000..ec5e1e3
--- /dev/null
+++ b/fastboot/device/tcp_client.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 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 "tcp_client.h"
+#include "constants.h"
+
+#include <android-base/errors.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+static constexpr int kDefaultPort = 5554;
+static constexpr int kProtocolVersion = 1;
+static constexpr int kHandshakeTimeoutMs = 2000;
+static constexpr size_t kHandshakeLength = 4;
+
+// Extract the big-endian 8-byte message length into a 64-bit number.
+static uint64_t ExtractMessageLength(const void* buffer) {
+ uint64_t ret = 0;
+ for (int i = 0; i < 8; ++i) {
+ ret |= uint64_t{reinterpret_cast<const uint8_t*>(buffer)[i]} << (56 - i * 8);
+ }
+ return ret;
+}
+
+// Encode the 64-bit number into a big-endian 8-byte message length.
+static void EncodeMessageLength(uint64_t length, void* buffer) {
+ for (int i = 0; i < 8; ++i) {
+ reinterpret_cast<uint8_t*>(buffer)[i] = length >> (56 - i * 8);
+ }
+}
+
+ClientTcpTransport::ClientTcpTransport() {
+ service_ = Socket::NewServer(Socket::Protocol::kTcp, kDefaultPort);
+
+ // A workaround to notify recovery to continue its work.
+ android::base::SetProperty("sys.usb.ffs.ready", "1");
+}
+
+ssize_t ClientTcpTransport::Read(void* data, size_t len) {
+ if (len > SSIZE_MAX) {
+ return -1;
+ }
+
+ size_t total_read = 0;
+ do {
+ // Read a new message
+ while (message_bytes_left_ == 0) {
+ if (socket_ == nullptr) {
+ ListenFastbootSocket();
+ }
+
+ char buffer[8];
+ if (socket_->ReceiveAll(buffer, 8, 0) == 8) {
+ message_bytes_left_ = ExtractMessageLength(buffer);
+ } else {
+ // If connection is closed by host, Receive will return 0 immediately.
+ socket_.reset(nullptr);
+ // In DATA phase, return error.
+ if (downloading_) {
+ return -1;
+ }
+ }
+ }
+
+ size_t read_length = len - total_read;
+ if (read_length > message_bytes_left_) {
+ read_length = message_bytes_left_;
+ }
+ ssize_t bytes_read =
+ socket_->ReceiveAll(reinterpret_cast<char*>(data) + total_read, read_length, 0);
+ if (bytes_read == -1) {
+ socket_.reset(nullptr);
+ return -1;
+ } else {
+ message_bytes_left_ -= bytes_read;
+ total_read += bytes_read;
+ }
+ // There are more than one DATA phases if the downloading buffer is too
+ // large, like a very big system image. All of data phases should be
+ // received until the whole buffer is filled in that case.
+ } while (downloading_ && total_read < len);
+
+ return total_read;
+}
+
+ssize_t ClientTcpTransport::Write(const void* data, size_t len) {
+ if (socket_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+
+ // Use multi-buffer writes for better performance.
+ char header[8];
+ EncodeMessageLength(len, header);
+
+ if (!socket_->Send(std::vector<cutils_socket_buffer_t>{{header, 8}, {data, len}})) {
+ socket_.reset(nullptr);
+ return -1;
+ }
+
+ // In DATA phase
+ if (android::base::StartsWith(reinterpret_cast<const char*>(data), RESPONSE_DATA)) {
+ downloading_ = true;
+ } else {
+ downloading_ = false;
+ }
+
+ return len;
+}
+
+int ClientTcpTransport::Close() {
+ if (socket_ == nullptr) {
+ return -1;
+ }
+ socket_.reset(nullptr);
+
+ return 0;
+}
+
+int ClientTcpTransport::Reset() {
+ return Close();
+}
+
+void ClientTcpTransport::ListenFastbootSocket() {
+ while (true) {
+ socket_ = service_->Accept();
+
+ // Handshake
+ char buffer[kHandshakeLength + 1];
+ buffer[kHandshakeLength] = '\0';
+ if (socket_->ReceiveAll(buffer, kHandshakeLength, kHandshakeTimeoutMs) !=
+ kHandshakeLength) {
+ PLOG(ERROR) << "No Handshake message received";
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ if (memcmp(buffer, "FB", 2) != 0) {
+ PLOG(ERROR) << "Unrecognized initialization message";
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ int version = 0;
+ if (!android::base::ParseInt(buffer + 2, &version) || version < kProtocolVersion) {
+ LOG(ERROR) << "Unknown TCP protocol version " << buffer + 2
+ << ", our version: " << kProtocolVersion;
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ std::string handshake_message(android::base::StringPrintf("FB%02d", kProtocolVersion));
+ if (!socket_->Send(handshake_message.c_str(), kHandshakeLength)) {
+ PLOG(ERROR) << "Failed to send initialization message";
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ break;
+ }
+}
diff --git a/fastboot/device/tcp_client.h b/fastboot/device/tcp_client.h
new file mode 100644
index 0000000..32e9834
--- /dev/null
+++ b/fastboot/device/tcp_client.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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 <memory>
+
+#include "socket.h"
+#include "transport.h"
+
+class ClientTcpTransport : public Transport {
+ public:
+ ClientTcpTransport();
+ ~ClientTcpTransport() override = default;
+
+ ssize_t Read(void* data, size_t len) override;
+ ssize_t Write(const void* data, size_t len) override;
+ int Close() override;
+ int Reset() override;
+
+ private:
+ void ListenFastbootSocket();
+
+ std::unique_ptr<Socket> service_;
+ std::unique_ptr<Socket> socket_;
+ uint64_t message_bytes_left_ = 0;
+ bool downloading_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientTcpTransport);
+};
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index e56ffcf..5a14b63 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -54,7 +54,9 @@
while (total < length) {
ssize_t bytes = Receive(reinterpret_cast<char*>(data) + total, length - total, timeout_ms);
- if (bytes == -1) {
+ // Returns 0 only when the peer has disconnected because our requested length is not 0. So
+ // we return immediately to avoid dead loop here.
+ if (bytes <= 0) {
if (total == 0) {
return -1;
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 76e3955..b8385d3 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -454,7 +454,8 @@
<< entry.encryption_options;
return;
}
- if ((options.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) != 0) {
+ if ((options.flags &
+ (FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) != 0) {
// We can only use this policy on ext4 if the "stable_inodes" feature
// is set on the filesystem, otherwise shrinking will break encrypted files.
if ((sb->s_feature_compat & cpu_to_le32(EXT4_FEATURE_COMPAT_STABLE_INODES)) == 0) {
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index ea9c957..9046132 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -52,17 +52,27 @@
using DmTargetZero = android::dm::DmTargetZero;
using DmTargetLinear = android::dm::DmTargetLinear;
-static bool GetPhysicalPartitionDevicePath(const IPartitionOpener& opener,
- const LpMetadata& metadata,
+static bool GetPhysicalPartitionDevicePath(const CreateLogicalPartitionParams& params,
const LpMetadataBlockDevice& block_device,
const std::string& super_device, std::string* result) {
// If the super device is the source of this block device's metadata,
// make sure we use the correct super device (and not just "super",
// which might not exist.)
std::string name = GetBlockDevicePartitionName(block_device);
- std::string dev_string = opener.GetDeviceString(name);
- if (GetMetadataSuperBlockDevice(metadata) == &block_device) {
- dev_string = opener.GetDeviceString(super_device);
+ if (android::base::StartsWith(name, "dm-")) {
+ // Device-mapper nodes are not normally allowed in LpMetadata, since
+ // they are not consistent across reboots. However for the purposes of
+ // testing it's useful to handle them. For example when running DSUs,
+ // userdata is a device-mapper device, and some stacking will result
+ // when using libfiemap.
+ *result = "/dev/block/" + name;
+ return true;
+ }
+
+ auto opener = params.partition_opener;
+ std::string dev_string = opener->GetDeviceString(name);
+ if (GetMetadataSuperBlockDevice(*params.metadata) == &block_device) {
+ dev_string = opener->GetDeviceString(super_device);
}
// Note: device-mapper will not accept symlinks, so we must use realpath
@@ -93,8 +103,8 @@
case LP_TARGET_TYPE_LINEAR: {
const auto& block_device = params.metadata->block_devices[extent.target_source];
std::string dev_string;
- if (!GetPhysicalPartitionDevicePath(*params.partition_opener, *params.metadata,
- block_device, super_device, &dev_string)) {
+ if (!GetPhysicalPartitionDevicePath(params, block_device, super_device,
+ &dev_string)) {
LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
return false;
}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index f3f1cb7..fa4ac39 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -402,16 +402,17 @@
return fstab_result;
}
-// Identify path to fstab file. Lookup is based on pattern fstab.<hardware>,
-// fstab.<hardware.platform> in folders /odm/etc, vendor/etc, or /.
+// Identify path to fstab file. Lookup is based on pattern
+// fstab.<fstab_suffix>, fstab.<hardware>, fstab.<hardware.platform> in
+// folders /odm/etc, vendor/etc, or /.
std::string GetFstabPath() {
- for (const char* prop : {"hardware", "hardware.platform"}) {
- std::string hw;
+ for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
+ std::string suffix;
- if (!fs_mgr_get_boot_config(prop, &hw)) continue;
+ if (!fs_mgr_get_boot_config(prop, &suffix)) continue;
for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
- std::string fstab_path = prefix + hw;
+ std::string fstab_path = prefix + suffix;
if (access(fstab_path.c_str(), F_OK) == 0) {
return fstab_path;
}
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 673e145..7912688 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -29,6 +29,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <uuid/uuid.h>
@@ -140,6 +141,10 @@
return std::string{uuid_chars};
}
+static bool IsRecovery() {
+ return access("/system/bin/recovery", F_OK) == 0;
+}
+
bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
const std::chrono::milliseconds& timeout_ms) {
std::string uuid = GenerateUuid();
@@ -160,6 +165,16 @@
if (timeout_ms <= std::chrono::milliseconds::zero()) {
return true;
}
+
+ if (IsRecovery()) {
+ bool non_ab_device = android::base::GetProperty("ro.build.ab_update", "").empty();
+ int sdk = android::base::GetIntProperty("ro.build.version.sdk", 0);
+ if (non_ab_device && sdk && sdk <= 29) {
+ LOG(INFO) << "Detected ueventd incompatibility, reverting to legacy libdm behavior.";
+ unique_path = *path;
+ }
+ }
+
if (!WaitForFile(unique_path, timeout_ms)) {
LOG(ERROR) << "Failed waiting for device path: " << unique_path;
DeleteDevice(name);
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 6717922..3ee742f 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -51,6 +51,7 @@
using android::fs_mgr::GetPartitionName;
static constexpr char kTestImageMetadataDir[] = "/metadata/gsi/test";
+static constexpr char kOtaTestImageMetadataDir[] = "/metadata/gsi/ota/test";
std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix) {
auto metadata_dir = "/metadata/gsi/" + dir_prefix;
@@ -135,10 +136,13 @@
return !!FindPartition(*metadata.get(), name);
}
+static bool IsTestDir(const std::string& path) {
+ return android::base::StartsWith(path, kTestImageMetadataDir) ||
+ android::base::StartsWith(path, kOtaTestImageMetadataDir);
+}
+
static bool IsUnreliablePinningAllowed(const std::string& path) {
- return android::base::StartsWith(path, "/data/gsi/dsu/") ||
- android::base::StartsWith(path, "/data/gsi/test/") ||
- android::base::StartsWith(path, "/data/gsi/ota/test/");
+ return android::base::StartsWith(path, "/data/gsi/dsu/") || IsTestDir(path);
}
FiemapStatus ImageManager::CreateBackingImage(
@@ -174,8 +178,7 @@
// if device-mapper is stacked in some complex way not supported by
// FiemapWriter.
auto device_path = GetDevicePathForFile(fw.get());
- if (android::base::StartsWith(device_path, "/dev/block/dm-") &&
- !android::base::StartsWith(metadata_dir_, kTestImageMetadataDir)) {
+ if (android::base::StartsWith(device_path, "/dev/block/dm-") && !IsTestDir(metadata_dir_)) {
LOG(ERROR) << "Cannot persist images against device-mapper device: " << device_path;
fw = {};
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index 5388b44..6663391 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -131,132 +131,6 @@
ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
}
-// This fixture is for tests against a simulated device environment. Rather
-// than use /data, we create an image and then layer a new filesystem within
-// it. Each test then decides how to mount and create layered images. This
-// allows us to test FBE vs FDE configurations.
-class ImageTest : public ::testing::Test {
- public:
- ImageTest() : dm_(DeviceMapper::Instance()) {}
-
- void SetUp() override {
- manager_ = ImageManager::Open(kMetadataPath, gDataPath);
- ASSERT_NE(manager_, nullptr);
-
- manager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
-
- submanager_ = ImageManager::Open(kMetadataPath + "/mnt"s, gDataPath + "/mnt"s);
- ASSERT_NE(submanager_, nullptr);
-
- submanager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
-
- // Ensure that metadata is cleared in between runs.
- submanager_->RemoveAllImages();
- manager_->RemoveAllImages();
-
- const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info();
- base_name_ = tinfo->name();
- test_image_name_ = base_name_ + "-base";
- wrapper_device_name_ = base_name_ + "-wrapper";
-
- ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize * 16, false, nullptr));
- ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &base_device_));
- }
-
- void TearDown() override {
- submanager_->UnmapImageDevice(test_image_name_);
- umount(gDataMountPath.c_str());
- dm_.DeleteDeviceIfExists(wrapper_device_name_);
- manager_->UnmapImageDevice(base_name_);
- manager_->DeleteBackingImage(base_name_);
- }
-
- protected:
- bool DoFormat(const std::string& device) {
- // clang-format off
- std::vector<std::string> mkfs_args = {
- "/system/bin/mke2fs",
- "-F",
- "-b 4096",
- "-t ext4",
- "-m 0",
- "-O has_journal",
- device,
- ">/dev/null",
- "2>/dev/null",
- "</dev/null",
- };
- // clang-format on
- auto command = android::base::Join(mkfs_args, " ");
- return system(command.c_str()) == 0;
- }
-
- std::unique_ptr<ImageManager> manager_;
- std::unique_ptr<ImageManager> submanager_;
-
- DeviceMapper& dm_;
- std::string base_name_;
- std::string base_device_;
- std::string test_image_name_;
- std::string wrapper_device_name_;
-};
-
-TEST_F(ImageTest, DirectMount) {
- ASSERT_TRUE(DoFormat(base_device_));
- ASSERT_EQ(mount(base_device_.c_str(), gDataMountPath.c_str(), "ext4", 0, nullptr), 0);
- ASSERT_TRUE(submanager_->CreateBackingImage(test_image_name_, kTestImageSize, false, nullptr));
-
- std::string path;
- ASSERT_TRUE(submanager_->MapImageDevice(test_image_name_, 5s, &path));
- ASSERT_TRUE(android::base::StartsWith(path, "/dev/block/loop"));
-}
-
-TEST_F(ImageTest, IndirectMount) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148874852";
-#endif
- // Create a simple wrapper around the base device that we'll mount from
- // instead. This will simulate the code paths for dm-crypt/default-key/bow
- // and force us to use device-mapper rather than loop devices.
- uint64_t device_size = 0;
- {
- unique_fd fd(open(base_device_.c_str(), O_RDWR | O_CLOEXEC));
- ASSERT_GE(fd, 0);
- device_size = get_block_device_size(fd);
- ASSERT_EQ(device_size, kTestImageSize * 16);
- }
- uint64_t num_sectors = device_size / 512;
-
- auto& dm = DeviceMapper::Instance();
-
- DmTable table;
- table.Emplace<DmTargetLinear>(0, num_sectors, base_device_, 0);
- ASSERT_TRUE(dm.CreateDevice(wrapper_device_name_, table));
-
- // Format and mount.
- std::string wrapper_device;
- ASSERT_TRUE(dm.GetDmDevicePathByName(wrapper_device_name_, &wrapper_device));
- ASSERT_TRUE(WaitForFile(wrapper_device, 5s));
- ASSERT_TRUE(DoFormat(wrapper_device));
- ASSERT_EQ(mount(wrapper_device.c_str(), gDataMountPath.c_str(), "ext4", 0, nullptr), 0);
-
- ASSERT_TRUE(submanager_->CreateBackingImage(test_image_name_, kTestImageSize, false, nullptr));
-
- std::set<std::string> backing_devices;
- auto init = [&](std::set<std::string> devices) -> bool {
- backing_devices = std::move(devices);
- return true;
- };
-
- std::string path;
- ASSERT_TRUE(submanager_->MapImageDevice(test_image_name_, 5s, &path));
- ASSERT_TRUE(android::base::StartsWith(path, "/dev/block/dm-"));
- ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
- ASSERT_TRUE(submanager_->MapAllImages(init));
- ASSERT_FALSE(backing_devices.empty());
- ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
-}
-
bool Mkdir(const std::string& path) {
if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 4505382..2288674 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -124,6 +124,64 @@
return true;
}
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
+ bool found = false;
+ const uint8_t* desc_partition_name;
+ auto hash_desc = std::make_unique<FsAvbHashDescriptor>();
+
+ for (const auto& vbmeta : vbmeta_images) {
+ size_t num_descriptors;
+ std::unique_ptr<const AvbDescriptor*[], decltype(&avb_free)> descriptors(
+ avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
+
+ if (!descriptors || num_descriptors < 1) {
+ continue;
+ }
+
+ for (size_t n = 0; n < num_descriptors && !found; n++) {
+ AvbDescriptor desc;
+ if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
+ LWARNING << "Descriptor[" << n << "] is invalid";
+ continue;
+ }
+ if (desc.tag == AVB_DESCRIPTOR_TAG_HASH) {
+ desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashDescriptor);
+ if (!avb_hash_descriptor_validate_and_byteswap((AvbHashDescriptor*)descriptors[n],
+ hash_desc.get())) {
+ continue;
+ }
+ if (hash_desc->partition_name_len != partition_name.length()) {
+ continue;
+ }
+ // Notes that desc_partition_name is not NUL-terminated.
+ std::string hash_partition_name((const char*)desc_partition_name,
+ hash_desc->partition_name_len);
+ if (hash_partition_name == partition_name) {
+ found = true;
+ }
+ }
+ }
+
+ if (found) break;
+ }
+
+ if (!found) {
+ LERROR << "Hash descriptor not found: " << partition_name;
+ return nullptr;
+ }
+
+ hash_desc->partition_name = partition_name;
+
+ const uint8_t* desc_salt = desc_partition_name + hash_desc->partition_name_len;
+ hash_desc->salt = BytesToHex(desc_salt, hash_desc->salt_len);
+
+ const uint8_t* desc_digest = desc_salt + hash_desc->salt_len;
+ hash_desc->digest = BytesToHex(desc_digest, hash_desc->digest_len);
+
+ return hash_desc;
+}
+
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
bool found = false;
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index 09c786a..e8f7c39 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -40,6 +40,9 @@
std::string GetAvbPropertyDescriptor(const std::string& key,
const std::vector<VBMetaData>& vbmeta_images);
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
+
// AvbHashtreeDescriptor to dm-verity table setup.
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
diff --git a/fs_mgr/libfs_avb/fs_avb_util.cpp b/fs_mgr/libfs_avb/fs_avb_util.cpp
index f82f83d..1c14cc0 100644
--- a/fs_mgr/libfs_avb/fs_avb_util.cpp
+++ b/fs_mgr/libfs_avb/fs_avb_util.cpp
@@ -74,5 +74,15 @@
return GetHashtreeDescriptor(avb_partition_name, vbmeta_images);
}
+// Given a path, loads and verifies the vbmeta, to extract the Avb Hash descriptor.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+ VBMetaData&& vbmeta) {
+ if (!vbmeta.size()) return nullptr;
+
+ std::vector<VBMetaData> vbmeta_images;
+ vbmeta_images.emplace_back(std::move(vbmeta));
+ return GetHashDescriptor(avb_partition_name, vbmeta_images);
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
index ec8badb..3f37bd7 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
@@ -32,9 +32,20 @@
std::string* out_avb_partition_name,
VBMetaVerifyResult* out_verify_result);
+// Loads the single vbmeta from a given path.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
+ const std::string& image_path, const std::string& partition_name,
+ const std::string& expected_public_key_blob, bool allow_verification_error,
+ bool rollback_protection, bool is_chained_vbmeta, std::string* out_public_key_data,
+ bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result);
+
// Gets the hashtree descriptor for avb_partition_name from the vbmeta.
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& avb_partition_name, VBMetaData&& vbmeta);
+// Gets the hash descriptor for avb_partition_name from the vbmeta.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+ VBMetaData&& vbmeta);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/types.h b/fs_mgr/libfs_avb/include/fs_avb/types.h
index bd638e6..f2aa7cc 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/types.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/types.h
@@ -55,6 +55,12 @@
std::ostream& operator<<(std::ostream& os, AvbHandleStatus status);
+struct FsAvbHashDescriptor : AvbHashDescriptor {
+ std::string partition_name;
+ std::string salt;
+ std::string digest;
+};
+
struct FsAvbHashtreeDescriptor : AvbHashtreeDescriptor {
std::string partition_name;
std::string salt;
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 2ac0c44..0328132 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -132,7 +132,7 @@
uint64 metadata_sectors = 4;
}
-// Next: 2
+// Next: 4
message SnapshotMergeReport {
// Status of the update after the merge attempts.
UpdateState state = 1;
@@ -140,4 +140,7 @@
// Number of reboots that occurred after issuing and before completeing the
// merge of all the snapshot devices.
int32 resume_count = 2;
+
+ // Total size of all the COW images before the update.
+ uint64 cow_file_size = 3;
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 1daa83b..b207978 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -148,7 +148,7 @@
// Initiate a merge on all snapshot devices. This should only be used after an
// update has been marked successful after booting.
- bool InitiateMerge();
+ bool InitiateMerge(uint64_t* cow_file_size = nullptr);
// Perform any necessary post-boot actions. This should be run soon after
// /data is mounted.
@@ -223,6 +223,10 @@
// optional callback fires periodically to query progress via GetUpdateState.
bool HandleImminentDataWipe(const std::function<void()>& callback = {});
+ // Force a merge to complete in recovery. This is similar to HandleImminentDataWipe
+ // but does not expect a data wipe after.
+ bool FinishMergeInRecovery();
+
// This method is only allowed in recovery and is used as a helper to
// initialize the snapshot devices as a requirement to mount a snapshotted
// /system in recovery.
@@ -536,11 +540,16 @@
bool ProcessUpdateStateOnDataWipe(bool allow_forward_merge,
const std::function<bool()>& callback);
+ // Return device string of a mapped image, or if it is not available, the mapped image path.
+ bool GetMappedImageDeviceStringOrPath(const std::string& device_name,
+ std::string* device_string_or_mapped_path);
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
std::unique_ptr<IImageManager> images_;
bool has_local_image_manager_ = false;
+ bool in_factory_data_reset_ = false;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index 91dd34f..bdc3ea3 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -31,6 +31,8 @@
// Called when merge starts or resumes.
bool Start();
void set_state(android::snapshot::UpdateState state);
+ virtual void set_cow_file_size(uint64_t cow_file_size);
+ virtual uint64_t cow_file_size();
// Called when merge ends. Properly clean up permanent storage.
class Result {
@@ -43,6 +45,8 @@
std::unique_ptr<Result> Finish();
private:
+ virtual ~SnapshotMergeStats() {}
+
bool ReadState();
bool WriteState();
bool DeleteState();
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index c9fa28e..0739fab 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -555,7 +555,7 @@
return true;
}
-bool SnapshotManager::InitiateMerge() {
+bool SnapshotManager::InitiateMerge(uint64_t* cow_file_size) {
auto lock = LockExclusive();
if (!lock) return false;
@@ -577,8 +577,16 @@
return false;
}
+ auto other_suffix = device_->GetOtherSlotSuffix();
+
auto& dm = DeviceMapper::Instance();
for (const auto& snapshot : snapshots) {
+ if (android::base::EndsWith(snapshot, other_suffix)) {
+ // Allow the merge to continue, but log this unexpected case.
+ LOG(ERROR) << "Unexpected snapshot found during merge: " << snapshot;
+ continue;
+ }
+
// The device has to be mapped, since everything should be merged at
// the same time. This is a fairly serious error. We could forcefully
// map everything here, but it should have been mapped during first-
@@ -610,6 +618,7 @@
}
}
+ uint64_t total_cow_file_size = 0;
DmTargetSnapshot::Status initial_target_values = {};
for (const auto& snapshot : snapshots) {
DmTargetSnapshot::Status current_status;
@@ -619,6 +628,16 @@
initial_target_values.sectors_allocated += current_status.sectors_allocated;
initial_target_values.total_sectors += current_status.total_sectors;
initial_target_values.metadata_sectors += current_status.metadata_sectors;
+
+ SnapshotStatus snapshot_status;
+ if (!ReadSnapshotStatus(lock.get(), snapshot, &snapshot_status)) {
+ return false;
+ }
+ total_cow_file_size += snapshot_status.cow_file_size();
+ }
+
+ if (cow_file_size) {
+ *cow_file_size = total_cow_file_size;
}
SnapshotUpdateStatus initial_status;
@@ -1008,6 +1027,15 @@
}
void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
+ // It's not possible to remove update state in recovery, so write an
+ // indicator that cleanup is needed on reboot. If a factory data reset
+ // was requested, it doesn't matter, everything will get wiped anyway.
+ // To make testing easier we consider a /data wipe as cleaned up.
+ if (device_->IsRecovery() && !in_factory_data_reset_) {
+ WriteUpdateState(lock, UpdateState::MergeCompleted);
+ return;
+ }
+
RemoveAllUpdateState(lock);
}
@@ -1674,7 +1702,7 @@
return false;
}
std::string cow_device;
- if (!dm.GetDeviceString(cow_name, &cow_device)) {
+ if (!GetMappedImageDeviceStringOrPath(cow_name, &cow_device)) {
LOG(ERROR) << "Could not determine major/minor for: " << cow_name;
return false;
}
@@ -1771,7 +1799,7 @@
// If the COW image exists, append it as the last extent.
if (snapshot_status.cow_file_size() > 0) {
std::string cow_image_device;
- if (!dm.GetDeviceString(cow_image_name, &cow_image_device)) {
+ if (!GetMappedImageDeviceStringOrPath(cow_image_name, &cow_image_device)) {
LOG(ERROR) << "Cannot determine major/minor for: " << cow_image_name;
return false;
}
@@ -2347,7 +2375,6 @@
const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
CHECK(lock);
- auto& dm = DeviceMapper::Instance();
CreateLogicalPartitionParams cow_params{
.block_device = LP_METADATA_DEFAULT_PARTITION_NAME,
.metadata = exported_target_metadata,
@@ -2372,7 +2399,7 @@
}
std::string cow_path;
- if (!dm.GetDmDevicePathByName(cow_name, &cow_path)) {
+ if (!images_->GetMappedImageDevice(cow_name, &cow_path)) {
LOG(ERROR) << "Cannot determine path for " << cow_name;
return Return::Error();
}
@@ -2528,7 +2555,43 @@
}
return true;
};
- if (!ProcessUpdateStateOnDataWipe(true /* allow_forward_merge */, process_callback)) {
+
+ in_factory_data_reset_ = true;
+ bool ok = ProcessUpdateStateOnDataWipe(true /* allow_forward_merge */, process_callback);
+ in_factory_data_reset_ = false;
+
+ if (!ok) {
+ return false;
+ }
+
+ // Nothing should be depending on partitions now, so unmap them all.
+ if (!UnmapAllPartitions()) {
+ LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
+ }
+ return true;
+}
+
+bool SnapshotManager::FinishMergeInRecovery() {
+ if (!device_->IsRecovery()) {
+ LOG(ERROR) << "Data wipes are only allowed in recovery.";
+ return false;
+ }
+
+ auto mount = EnsureMetadataMounted();
+ if (!mount || !mount->HasDevice()) {
+ return false;
+ }
+
+ auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
+ auto super_path = device_->GetSuperDevice(slot_number);
+ if (!CreateLogicalAndSnapshotPartitions(super_path)) {
+ LOG(ERROR) << "Unable to map partitions to complete merge.";
+ return false;
+ }
+
+ UpdateState state = ProcessUpdateState();
+ if (state != UpdateState::MergeCompleted) {
+ LOG(ERROR) << "Merge returned unexpected status: " << state;
return false;
}
@@ -2685,5 +2748,24 @@
return true;
}
+bool SnapshotManager::GetMappedImageDeviceStringOrPath(const std::string& device_name,
+ std::string* device_string_or_mapped_path) {
+ auto& dm = DeviceMapper::Instance();
+ // Try getting the device string if it is a device mapper device.
+ if (dm.GetState(device_name) != DmDeviceState::INVALID) {
+ return dm.GetDeviceString(device_name, device_string_or_mapped_path);
+ }
+
+ // Otherwise, get path from IImageManager.
+ if (!images_->GetMappedImageDevice(device_name, device_string_or_mapped_path)) {
+ return false;
+ }
+
+ LOG(WARNING) << "Calling GetMappedImageDevice with local image manager; device "
+ << (device_string_or_mapped_path ? *device_string_or_mapped_path : "(nullptr)")
+ << "may not be available in first stage init! ";
+ return true;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 5da7b98..3723730 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -88,6 +88,15 @@
report_.set_state(state);
}
+void SnapshotMergeStats::set_cow_file_size(uint64_t cow_file_size) {
+ report_.set_cow_file_size(cow_file_size);
+ WriteState();
+}
+
+uint64_t SnapshotMergeStats::cow_file_size() {
+ return report_.cow_file_size();
+}
+
class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result {
public:
SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report,
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f82c082..9ca2412 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1454,6 +1454,52 @@
ASSERT_EQ(new_sm->GetUpdateState(), UpdateState::None);
}
+// Test that a merge does not clear the snapshot state in fastboot.
+TEST_F(SnapshotUpdateTest, MergeInFastboot) {
+ // Execute the first update.
+ ASSERT_TRUE(sm->BeginUpdate());
+ ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+ ASSERT_TRUE(MapUpdateSnapshots());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+ // Simulate shutting down the device.
+ ASSERT_TRUE(UnmapAll());
+
+ // After reboot, init does first stage mount.
+ auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ ASSERT_NE(init, nullptr);
+ ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+ init = nullptr;
+
+ // Initiate the merge and then immediately stop it to simulate a reboot.
+ auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
+ ASSERT_TRUE(new_sm->InitiateMerge());
+ ASSERT_TRUE(UnmapAll());
+
+ // Simulate a reboot into recovery.
+ auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+ test_device->set_recovery(true);
+ new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+
+ ASSERT_TRUE(new_sm->FinishMergeInRecovery());
+
+ auto mount = new_sm->EnsureMetadataMounted();
+ ASSERT_TRUE(mount && mount->HasDevice());
+ ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
+
+ // Finish the merge in a normal boot.
+ test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+ init = SnapshotManager::NewForFirstStageMount(test_device.release());
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+ init = nullptr;
+
+ test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+ new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+ ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
+ ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::None);
+}
+
// Test that after an OTA, before a merge, we can wipe data in recovery.
TEST_F(SnapshotUpdateTest, DataWipeRollbackInRecovery) {
// Execute the first update.
diff --git a/init/README.md b/init/README.md
index 726c0cc..0dd1490 100644
--- a/init/README.md
+++ b/init/README.md
@@ -547,13 +547,16 @@
* `ref`: use the systemwide DE key
* `per_boot_ref`: use the key freshly generated on each boot.
-`mount_all <fstab> [ <path> ]\* [--<option>]`
+`mount_all [ <fstab> ] [--<option>]`
> Calls fs\_mgr\_mount\_all on the given fs\_mgr-format fstab with optional
options "early" and "late".
With "--early" set, the init executable will skip mounting entries with
"latemount" flag and triggering fs encryption state event. With "--late" set,
init executable will only mount entries with "latemount" flag. By default,
no option is set, and mount\_all will process all entries in the given fstab.
+ If the fstab parameter is not specified, fstab.${ro.boot.fstab_suffix},
+ fstab.${ro.hardware} or fstab.${ro.hardware.platform} will be scanned for
+ under /odm/etc, /vendor/etc, or / at runtime, in that order.
`mount <type> <device> <dir> [ <flag>\* ] [<options>]`
> Attempt to mount the named device at the directory _dir_
@@ -644,7 +647,8 @@
`wait <path> [ <timeout> ]`
> Poll for the existence of the given file and return when found,
or the timeout has been reached. If timeout is not specified it
- currently defaults to five seconds.
+ currently defaults to five seconds. The timeout value can be
+ fractional seconds, specified in floating point notation.
`wait_for_prop <name> <value>`
> Wait for system property _name_ to be _value_. Properties are expanded
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 200bfff..e918e12 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -49,6 +49,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parsedouble.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -517,21 +518,21 @@
/* Imports .rc files from the specified paths. Default ones are applied if none is given.
*
- * start_index: index of the first path in the args list
+ * rc_paths: list of paths to rc files to import
*/
-static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
+static void import_late(const std::vector<std::string>& rc_paths) {
auto& action_manager = ActionManager::GetInstance();
auto& service_list = ServiceList::GetInstance();
Parser parser = CreateParser(action_manager, service_list);
- if (end_index <= start_index) {
+ if (rc_paths.empty()) {
// Fallbacks for partitions on which early mount isn't enabled.
for (const auto& path : late_import_paths) {
parser.ParseConfig(path);
}
late_import_paths.clear();
} else {
- for (size_t i = start_index; i < end_index; ++i) {
- parser.ParseConfig(args[i]);
+ for (const auto& rc_path : rc_paths) {
+ parser.ParseConfig(rc_path);
}
}
@@ -632,48 +633,44 @@
static int initial_mount_fstab_return_code = -1;
-/* mount_all <fstab> [ <path> ]* [--<options>]*
+/* <= Q: mount_all <fstab> [ <path> ]* [--<options>]*
+ * >= R: mount_all [ <fstab> ] [--<options>]*
*
* This function might request a reboot, in which case it will
* not return.
*/
static Result<void> do_mount_all(const BuiltinArguments& args) {
- std::size_t na = 0;
- bool import_rc = true;
- bool queue_event = true;
- int mount_mode = MOUNT_MODE_DEFAULT;
- const auto& fstab_file = args[1];
- std::size_t path_arg_end = args.size();
- const char* prop_post_fix = "default";
+ auto mount_all = ParseMountAll(args.args);
+ if (!mount_all.ok()) return mount_all.error();
- for (na = args.size() - 1; na > 1; --na) {
- if (args[na] == "--early") {
- path_arg_end = na;
- queue_event = false;
- mount_mode = MOUNT_MODE_EARLY;
- prop_post_fix = "early";
- } else if (args[na] == "--late") {
- path_arg_end = na;
- import_rc = false;
- mount_mode = MOUNT_MODE_LATE;
- prop_post_fix = "late";
- }
+ const char* prop_post_fix = "default";
+ bool queue_event = true;
+ if (mount_all->mode == MOUNT_MODE_EARLY) {
+ prop_post_fix = "early";
+ queue_event = false;
+ } else if (mount_all->mode == MOUNT_MODE_LATE) {
+ prop_post_fix = "late";
}
std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
android::base::Timer t;
Fstab fstab;
- if (!ReadFstabFromFile(fstab_file, &fstab)) {
- return Error() << "Could not read fstab";
+ if (mount_all->fstab_path.empty()) {
+ if (!ReadDefaultFstab(&fstab)) {
+ return Error() << "Could not read default fstab";
+ }
+ } else {
+ if (!ReadFstabFromFile(mount_all->fstab_path, &fstab)) {
+ return Error() << "Could not read fstab";
+ }
}
- auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode);
+ auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_all->mode);
SetProperty(prop_name, std::to_string(t.duration().count()));
- if (import_rc && SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) {
- /* Paths of .rc files are specified at the 2nd argument and beyond */
- import_late(args.args, 2, path_arg_end);
+ if (mount_all->import_rc) {
+ import_late(mount_all->rc_paths);
}
if (queue_event) {
@@ -689,11 +686,20 @@
return {};
}
-/* umount_all <fstab> */
+/* umount_all [ <fstab> ] */
static Result<void> do_umount_all(const BuiltinArguments& args) {
+ auto umount_all = ParseUmountAll(args.args);
+ if (!umount_all.ok()) return umount_all.error();
+
Fstab fstab;
- if (!ReadFstabFromFile(args[1], &fstab)) {
- return Error() << "Could not read fstab";
+ if (umount_all->empty()) {
+ if (!ReadDefaultFstab(&fstab)) {
+ return Error() << "Could not read default fstab";
+ }
+ } else {
+ if (!ReadFstabFromFile(*umount_all, &fstab)) {
+ return Error() << "Could not read fstab";
+ }
}
if (auto result = fs_mgr_umount_all(&fstab); result != 0) {
@@ -1065,11 +1071,12 @@
static Result<void> do_wait(const BuiltinArguments& args) {
auto timeout = kCommandRetryTimeout;
if (args.size() == 3) {
- int timeout_int;
- if (!android::base::ParseInt(args[2], &timeout_int)) {
+ double timeout_double;
+ if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
return Error() << "failed to parse timeout";
}
- timeout = std::chrono::seconds(timeout_int);
+ timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::duration<double>(timeout_double));
}
if (wait_for_file(args[1].c_str(), timeout) != 0) {
@@ -1347,11 +1354,11 @@
// mount_all is currently too complex to run in vendor_init as it queues action triggers,
// imports rc scripts, etc. It should be simplified and run in vendor_init context.
// mount and umount are run in the same context as mount_all for symmetry.
- {"mount_all", {1, kMax, {false, do_mount_all}}},
+ {"mount_all", {0, kMax, {false, do_mount_all}}},
{"mount", {3, kMax, {false, do_mount}}},
{"perform_apex_config", {0, 0, {false, do_perform_apex_config}}},
{"umount", {1, 1, {false, do_umount}}},
- {"umount_all", {1, 1, {false, do_umount_all}}},
+ {"umount_all", {0, 1, {false, do_umount_all}}},
{"update_linker_config", {0, 0, {false, do_update_linker_config}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"remount_userdata", {0, 0, {false, do_remount_userdata}}},
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index d62ecb0..450c079 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -25,6 +25,7 @@
#include <sys/time.h>
#include <android-base/logging.h>
+#include <android-base/parsedouble.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
@@ -122,6 +123,14 @@
return {};
}
+Result<void> check_mount_all(const BuiltinArguments& args) {
+ auto options = ParseMountAll(args.args);
+ if (!options.ok()) {
+ return options.error();
+ }
+ return {};
+}
+
Result<void> check_mkdir(const BuiltinArguments& args) {
auto options = ParseMkdir(args.args);
if (!options.ok()) {
@@ -203,10 +212,18 @@
return {};
}
+Result<void> check_umount_all(const BuiltinArguments& args) {
+ auto options = ParseUmountAll(args.args);
+ if (!options.ok()) {
+ return options.error();
+ }
+ return {};
+}
+
Result<void> check_wait(const BuiltinArguments& args) {
if (args.size() == 3 && !args[2].empty()) {
- int timeout_int;
- if (!android::base::ParseInt(args[2], &timeout_int)) {
+ double timeout_double;
+ if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
return Error() << "failed to parse timeout";
}
}
diff --git a/init/check_builtins.h b/init/check_builtins.h
index fb34556..725a6fd 100644
--- a/init/check_builtins.h
+++ b/init/check_builtins.h
@@ -32,11 +32,13 @@
Result<void> check_load_system_props(const BuiltinArguments& args);
Result<void> check_loglevel(const BuiltinArguments& args);
Result<void> check_mkdir(const BuiltinArguments& args);
+Result<void> check_mount_all(const BuiltinArguments& args);
Result<void> check_restorecon(const BuiltinArguments& args);
Result<void> check_restorecon_recursive(const BuiltinArguments& args);
Result<void> check_setprop(const BuiltinArguments& args);
Result<void> check_setrlimit(const BuiltinArguments& args);
Result<void> check_sysclktz(const BuiltinArguments& args);
+Result<void> check_umount_all(const BuiltinArguments& args);
Result<void> check_wait(const BuiltinArguments& args);
Result<void> check_wait_for_prop(const BuiltinArguments& args);
diff --git a/init/first_stage_console.cpp b/init/first_stage_console.cpp
index cae53f4..cfa0d99 100644
--- a/init/first_stage_console.cpp
+++ b/init/first_stage_console.cpp
@@ -16,6 +16,7 @@
#include "first_stage_console.h"
+#include <stdio.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
@@ -87,8 +88,18 @@
_exit(127);
}
-bool FirstStageConsole(const std::string& cmdline) {
- return cmdline.find("androidboot.first_stage_console=1") != std::string::npos;
+int FirstStageConsole(const std::string& cmdline) {
+ auto pos = cmdline.find("androidboot.first_stage_console=");
+ if (pos != std::string::npos) {
+ int val = 0;
+ if (sscanf(cmdline.c_str() + pos, "androidboot.first_stage_console=%d", &val) != 1) {
+ return FirstStageConsoleParam::DISABLED;
+ }
+ if (val <= FirstStageConsoleParam::MAX_PARAM_VALUE && val >= 0) {
+ return val;
+ }
+ }
+ return FirstStageConsoleParam::DISABLED;
}
} // namespace init
diff --git a/init/first_stage_console.h b/init/first_stage_console.h
index 7485339..8f36a7c 100644
--- a/init/first_stage_console.h
+++ b/init/first_stage_console.h
@@ -21,8 +21,15 @@
namespace android {
namespace init {
+enum FirstStageConsoleParam {
+ DISABLED = 0,
+ CONSOLE_ON_FAILURE = 1,
+ IGNORE_FAILURE = 2,
+ MAX_PARAM_VALUE = IGNORE_FAILURE,
+};
+
void StartConsole();
-bool FirstStageConsole(const std::string& cmdline);
+int FirstStageConsole(const std::string& cmdline);
} // namespace init
} // namespace android
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 5eca644..1a608f6 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -200,16 +200,16 @@
}
Modprobe m({"/lib/modules"}, module_load_file);
- auto want_console = ALLOW_FIRST_STAGE_CONSOLE && FirstStageConsole(cmdline);
+ auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline) : 0;
if (!m.LoadListedModules(!want_console)) {
- if (want_console) {
+ if (want_console != FirstStageConsoleParam::DISABLED) {
LOG(ERROR) << "Failed to load kernel modules, starting console";
} else {
LOG(FATAL) << "Failed to load kernel modules";
}
}
- if (want_console) {
+ if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
StartConsole();
}
diff --git a/init/init.cpp b/init/init.cpp
index 6465df1..29859c5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -509,7 +509,9 @@
// Set the UDC controller for the ConfigFS USB Gadgets.
// Read the UDC controller in use from "/sys/class/udc".
// In case of multiple UDC controllers select the first one.
-static void set_usb_controller() {
+static void SetUsbController() {
+ static auto controller_set = false;
+ if (controller_set) return;
std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
if (!dir) return;
@@ -518,6 +520,7 @@
if (dp->d_name[0] == '.') continue;
SetProperty("sys.usb.controller", dp->d_name);
+ controller_set = true;
break;
}
}
@@ -772,7 +775,7 @@
fs_mgr_vendor_overlay_mount_all();
export_oem_lock_status();
MountHandler mount_handler(&epoll);
- set_usb_controller();
+ SetUsbController();
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
Action::set_function_map(&function_map);
@@ -879,6 +882,7 @@
}
if (!IsShuttingDown()) {
HandleControlMessages();
+ SetUsbController();
}
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index e89f74a..23a07aa 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -66,8 +66,6 @@
#include "sigchld_handler.h"
#include "util.h"
-#define PROC_SYSRQ "/proc/sysrq-trigger"
-
using namespace std::literals;
using android::base::boot_clock;
@@ -680,9 +678,12 @@
// Reap subcontext pids.
ReapAnyOutstandingChildren();
- // 3. send volume shutdown to vold
+ // 3. send volume abort_fuse and volume shutdown to vold
Service* vold_service = ServiceList::GetInstance().FindService("vold");
if (vold_service != nullptr && vold_service->IsRunning()) {
+ // Manually abort FUSE connections, since the FUSE daemon is already dead
+ // at this point, and unmounting it might hang.
+ CallVdc("volume", "abort_fuse");
CallVdc("volume", "shutdown");
vold_service->Stop();
} else {
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 485188b..76460a5 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -29,6 +29,7 @@
#include <cutils/android_reboot.h>
#include "capabilities.h"
+#include "reboot_utils.h"
namespace android {
namespace init {
@@ -138,6 +139,9 @@
LOG(ERROR) << backtrace->FormatFrameData(i);
}
if (init_fatal_panic) {
+ LOG(ERROR) << __FUNCTION__ << ": Trigger crash";
+ android::base::WriteStringToFile("c", PROC_SYSRQ);
+ LOG(ERROR) << __FUNCTION__ << ": Sys-Rq failed to crash the system; fallback to exit().";
_exit(signal_number);
}
RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index 878ad96..05bb9ae 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -18,6 +18,8 @@
#include <string>
+#define PROC_SYSRQ "/proc/sysrq-trigger"
+
namespace android {
namespace init {
diff --git a/init/util.cpp b/init/util.cpp
index 24f94ec..90ac50c 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -570,6 +570,48 @@
return MkdirOptions{args[1], mode, *uid, *gid, fscrypt_action, ref_option};
}
+Result<MountAllOptions> ParseMountAll(const std::vector<std::string>& args) {
+ bool compat_mode = false;
+ bool import_rc = false;
+ if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) {
+ if (args.size() <= 1) {
+ return Error() << "mount_all requires at least 1 argument";
+ }
+ compat_mode = true;
+ import_rc = true;
+ }
+
+ std::size_t first_option_arg = args.size();
+ enum mount_mode mode = MOUNT_MODE_DEFAULT;
+
+ // If we are <= Q, then stop looking for non-fstab arguments at slot 2.
+ // Otherwise, stop looking at slot 1 (as the fstab path argument is optional >= R).
+ for (std::size_t na = args.size() - 1; na > (compat_mode ? 1 : 0); --na) {
+ if (args[na] == "--early") {
+ first_option_arg = na;
+ mode = MOUNT_MODE_EARLY;
+ } else if (args[na] == "--late") {
+ first_option_arg = na;
+ mode = MOUNT_MODE_LATE;
+ import_rc = false;
+ }
+ }
+
+ std::string fstab_path;
+ if (first_option_arg > 1) {
+ fstab_path = args[1];
+ } else if (compat_mode) {
+ return Error() << "mount_all argument 1 must be the fstab path";
+ }
+
+ std::vector<std::string> rc_paths;
+ for (std::size_t na = 2; na < first_option_arg; ++na) {
+ rc_paths.push_back(args[na]);
+ }
+
+ return MountAllOptions{rc_paths, fstab_path, mode, import_rc};
+}
+
Result<std::pair<int, std::vector<std::string>>> ParseRestorecon(
const std::vector<std::string>& args) {
struct flag_type {
@@ -610,6 +652,15 @@
return std::pair(flag, paths);
}
+Result<std::string> ParseUmountAll(const std::vector<std::string>& args) {
+ if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) {
+ if (args.size() <= 1) {
+ return Error() << "umount_all requires at least 1 argument";
+ }
+ }
+ return args[1];
+}
+
static void InitAborter(const char* abort_message) {
// When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
// simply abort instead of trying to reboot the system.
diff --git a/init/util.h b/init/util.h
index ad322d9..a7f813b 100644
--- a/init/util.h
+++ b/init/util.h
@@ -22,6 +22,7 @@
#include <chrono>
#include <functional>
#include <string>
+#include <vector>
#include <android-base/chrono_utils.h>
@@ -33,6 +34,12 @@
namespace android {
namespace init {
+enum mount_mode {
+ MOUNT_MODE_DEFAULT = 0,
+ MOUNT_MODE_EARLY = 1,
+ MOUNT_MODE_LATE = 2,
+};
+
static const char kColdBootDoneProp[] = "ro.cold_boot_done";
extern void (*trigger_shutdown)(const std::string& command);
@@ -73,9 +80,20 @@
Result<MkdirOptions> ParseMkdir(const std::vector<std::string>& args);
+struct MountAllOptions {
+ std::vector<std::string> rc_paths;
+ std::string fstab_path;
+ mount_mode mode;
+ bool import_rc;
+};
+
+Result<MountAllOptions> ParseMountAll(const std::vector<std::string>& args);
+
Result<std::pair<int, std::vector<std::string>>> ParseRestorecon(
const std::vector<std::string>& args);
+Result<std::string> ParseUmountAll(const std::vector<std::string>& args);
+
void SetStdioToDevNull(char** argv);
void InitKernelLogging(char** argv);
bool IsRecoveryMode();
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index dc989a0..c4cfa6f 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -48,6 +48,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "apex_inherit",
}
cc_defaults {
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 9ed7927..24110ee 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -33,6 +33,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "29",
native_bridge_supported: true,
export_include_dirs: ["include"],
target: {
@@ -59,6 +60,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "29",
export_include_dirs: ["include"],
@@ -142,6 +144,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "29",
native_bridge_supported: true,
srcs: [
"config_utils.cpp",
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index 3ec98b3..6543426 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -198,7 +198,7 @@
}
#define WRITE_MSG(format_begin, format_end, name, value) { \
- char buf[ATRACE_MESSAGE_LENGTH]; \
+ char buf[ATRACE_MESSAGE_LENGTH] __attribute__((uninitialized)); \
int pid = getpid(); \
int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
name, value); \
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index ce0c3c8..33ae13d 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -26,4 +26,5 @@
export_include_dirs: ["include"],
shared_libs: ["android.hardware.graphics.allocator@2.0"],
header_libs: ["libhardware_headers"],
+ min_sdk_version: "29",
}
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index 9ecdd4f..64de00e 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -37,25 +37,22 @@
#include "dhcpmsg.h"
-int fatal();
+int fatal(const char*);
-int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
-{
- int s;
- struct sockaddr_ll bindaddr;
+int open_raw_socket(const char* ifname __unused, uint8_t hwaddr[ETH_ALEN], int if_index) {
+ int s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (s < 0) return fatal("socket(PF_PACKET)");
- if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
- return fatal("socket(PF_PACKET)");
- }
-
- memset(&bindaddr, 0, sizeof(bindaddr));
- bindaddr.sll_family = AF_PACKET;
- bindaddr.sll_protocol = htons(ETH_P_IP);
- bindaddr.sll_halen = ETH_ALEN;
+ struct sockaddr_ll bindaddr = {
+ .sll_family = AF_PACKET,
+ .sll_protocol = htons(ETH_P_IP),
+ .sll_ifindex = if_index,
+ .sll_halen = ETH_ALEN,
+ };
memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
- bindaddr.sll_ifindex = if_index;
if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
+ close(s);
return fatal("Cannot bind raw socket to interface");
}
diff --git a/libnetutils/packet.h b/libnetutils/packet.h
index aade392..66186fc 100644
--- a/libnetutils/packet.h
+++ b/libnetutils/packet.h
@@ -17,7 +17,9 @@
#ifndef _WIFI_PACKET_H_
#define _WIFI_PACKET_H_
-int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
+#include <linux/if_ether.h>
+
+int open_raw_socket(const char* ifname, uint8_t hwaddr[ETH_ALEN], int if_index);
int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
int receive_packet(int s, struct dhcp_msg *msg);
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 2c1b255..bda11e9 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -17,6 +17,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "29",
}
cc_library {
@@ -60,4 +61,5 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "29",
}
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index 766ea0f..ccc6f62 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -89,15 +89,15 @@
"test_vendor.cpp",
],
static_libs: [
+ "libbase",
"libgmock",
+ "liblog",
+ "libjsoncpp",
"libjsonpbverify",
"libjsonpbparse",
"libprocessgroup_proto",
],
shared_libs: [
- "libbase",
- "liblog",
- "libjsoncpp",
"libprotobuf-cpp-full",
],
test_suites: [
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 0c9a2b8..15b0d89 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -51,6 +51,12 @@
enabled: false,
},
},
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.art.debug",
+ "com.android.art.release",
+ ],
}
// Tests
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
index 2658639..a8b4a4f 100644
--- a/libstats/pull/Android.bp
+++ b/libstats/pull/Android.bp
@@ -85,13 +85,18 @@
"libstatssocket",
],
test_suites: ["general-tests", "mts"],
+ test_config: "libstatspull_test.xml",
+
//TODO(b/153588990): Remove when the build system properly separates
//32bit and 64bit architectures.
compile_multilib: "both",
multilib: {
lib64: {
suffix: "64",
- }
+ },
+ lib32: {
+ suffix: "32",
+ },
},
cflags: [
"-Wall",
diff --git a/libstats/pull/libstatspull_test.xml b/libstats/pull/libstatspull_test.xml
new file mode 100644
index 0000000..233fc1f
--- /dev/null
+++ b/libstats/pull/libstatspull_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs libstatspull_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <option name="test-suite-tag" value="mts" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libstatspull_test->/data/local/tmp/libstatspull_test" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libstatspull_test" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+ </object>
+</configuration>
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
index 2d184bd..478cae7 100644
--- a/libstats/pull/stats_pull_atom_callback.cpp
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -47,7 +47,7 @@
}
static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second.
-static const int64_t DEFAULT_TIMEOUT_MILLIS = 10000LL; // 10 seconds.
+static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds.
struct AStatsManager_PullAtomMetadata {
int64_t cool_down_millis;
@@ -131,7 +131,11 @@
parcels.push_back(std::move(p));
}
- resultReceiver->pullFinished(atomTag, success, parcels);
+ Status status = resultReceiver->pullFinished(atomTag, success, parcels);
+ if (!status.isOk()) {
+ std::vector<StatsEventParcel> emptyParcels;
+ resultReceiver->pullFinished(atomTag, /*success=*/false, emptyParcels);
+ }
for (int i = 0; i < statsEventList.data.size(); i++) {
AStatsEvent_release(statsEventList.data[i]);
}
diff --git a/libstats/pull/tests/pull_atom_metadata_test.cpp b/libstats/pull/tests/pull_atom_metadata_test.cpp
index cf19303..abc8e47 100644
--- a/libstats/pull/tests/pull_atom_metadata_test.cpp
+++ b/libstats/pull/tests/pull_atom_metadata_test.cpp
@@ -21,7 +21,7 @@
namespace {
static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second.
-static const int64_t DEFAULT_TIMEOUT_MILLIS = 10000LL; // 10 seconds.
+static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds.
} // anonymous namespace
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
index 2f7212f..a63a5b6 100644
--- a/libstats/push_compat/Android.bp
+++ b/libstats/push_compat/Android.bp
@@ -50,6 +50,7 @@
],
static_libs: ["libgtest_prod"],
apex_available: ["com.android.resolv"],
+ min_sdk_version: "29",
}
cc_test {
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
index e1a86ae..c17ca61 100644
--- a/libstats/push_compat/StatsEventCompat.cpp
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -28,17 +28,8 @@
using android::base::GetProperty;
const static int kStatsEventTag = 1937006964;
-
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
const bool StatsEventCompat::mPlatformAtLeastR =
- GetProperty("ro.build.version.codename", "") == "R" ||
- android_get_device_api_level() > __ANDROID_API_Q__;
+ android_get_device_api_level() >= __ANDROID_API_R__;
// initializations of static class variables
bool StatsEventCompat::mAttemptedLoad = false;
diff --git a/libstats/push_compat/tests/StatsEventCompat_test.cpp b/libstats/push_compat/tests/StatsEventCompat_test.cpp
index dcb3797..2a70db5 100644
--- a/libstats/push_compat/tests/StatsEventCompat_test.cpp
+++ b/libstats/push_compat/tests/StatsEventCompat_test.cpp
@@ -21,16 +21,7 @@
using android::base::GetProperty;
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
-const static bool mPlatformAtLeastR = GetProperty("ro.build.version.codename", "") == "R" ||
- android_get_device_api_level() > __ANDROID_API_Q__;
+const static bool mPlatformAtLeastR = android_get_device_api_level() >= __ANDROID_API_R__;
TEST(StatsEventCompatTest, TestDynamicLoading) {
StatsEventCompat event;
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index e40a432..2bf0261 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -86,6 +86,7 @@
export_include_dirs: ["include"],
host_supported: true,
apex_available: ["com.android.resolv"],
+ min_sdk_version: "29",
}
cc_benchmark {
@@ -126,13 +127,17 @@
"libutils",
],
test_suites: ["device-tests", "mts"],
+ test_config: "libstatssocket_test.xml",
//TODO(b/153588990): Remove when the build system properly separates
//32bit and 64bit architectures.
compile_multilib: "both",
multilib: {
lib64: {
suffix: "64",
- }
+ },
+ lib32: {
+ suffix: "32",
+ },
},
require_root: true,
}
diff --git a/libstats/socket/libstatssocket_test.xml b/libstats/socket/libstatssocket_test.xml
new file mode 100644
index 0000000..d2694d1
--- /dev/null
+++ b/libstats/socket/libstatssocket_test.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs libstatssocket_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <option name="test-suite-tag" value="mts" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libstatssocket_test->/data/local/tmp/libstatssocket_test" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libstatssocket_test" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+ </object>
+</configuration>
+
diff --git a/libstats/socket/stats_buffer_writer.c b/libstats/socket/stats_buffer_writer.c
index 74acb20..549acdc 100644
--- a/libstats/socket/stats_buffer_writer.c
+++ b/libstats/socket/stats_buffer_writer.c
@@ -50,24 +50,16 @@
int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId) {
int ret = 1;
-#ifdef __ANDROID__
- bool statsdEnabled = property_get_bool("ro.statsd.enable", true);
-#else
- bool statsdEnabled = false;
-#endif
+ struct iovec vecs[2];
+ vecs[0].iov_base = (void*)&kStatsEventTag;
+ vecs[0].iov_len = sizeof(kStatsEventTag);
+ vecs[1].iov_base = buffer;
+ vecs[1].iov_len = size;
- if (statsdEnabled) {
- struct iovec vecs[2];
- vecs[0].iov_base = (void*)&kStatsEventTag;
- vecs[0].iov_len = sizeof(kStatsEventTag);
- vecs[1].iov_base = buffer;
- vecs[1].iov_len = size;
+ ret = __write_to_statsd(vecs, 2);
- ret = __write_to_statsd(vecs, 2);
-
- if (ret < 0) {
- note_log_drop(ret, atomId);
- }
+ if (ret < 0) {
+ note_log_drop(ret, atomId);
}
return ret;
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index ff886fd..db61669 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -8,6 +8,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "apex_inherit",
export_include_dirs: ["include"],
target: {
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index 627f0d4..3b98bab 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -43,6 +43,7 @@
"//apex_available:anyapex",
"//apex_available:platform",
],
+ min_sdk_version: "apex_inherit",
}
cc_test {
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 5efe03f..9c1621b 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -180,6 +180,7 @@
struct ifa_cacheinfo *cacheinfo = nullptr;
char addrstr[INET6_ADDRSTRLEN] = "";
char ifname[IFNAMSIZ] = "";
+ uint32_t flags;
if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
return false;
@@ -194,6 +195,9 @@
// For log messages.
const char *msgtype = rtMessageName(type);
+ // First 8 bits of flags. In practice will always be overridden when parsing IFA_FLAGS below.
+ flags = ifaddr->ifa_flags;
+
struct rtattr *rta;
int len = IFA_PAYLOAD(nh);
for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
@@ -242,6 +246,9 @@
}
cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
+
+ } else if (rta->rta_type == IFA_FLAGS) {
+ flags = *(uint32_t*)RTA_DATA(rta);
}
}
@@ -256,7 +263,7 @@
mSubsystem = strdup("net");
asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen);
asprintf(&mParams[1], "INTERFACE=%s", ifname);
- asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+ asprintf(&mParams[2], "FLAGS=%u", flags);
asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
asprintf(&mParams[4], "IFINDEX=%u", ifaddr->ifa_index);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 1f3ba59..563c2c2 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -135,6 +135,12 @@
exclude_shared_libs: ["libdexfile_support"],
},
},
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.art.debug",
+ "com.android.art.release",
+ ],
}
// Static library without DEX support to avoid dependencies on the ART APEX.
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 7405c96..3a30a9e 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,6 +22,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "apex_inherit",
header_libs: [
"liblog_headers",
@@ -168,6 +169,7 @@
"//apex_available:anyapex",
"//apex_available:platform",
],
+ min_sdk_version: "apex_inherit",
}
cc_library {
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 1202c15..0abb861 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -189,13 +189,17 @@
int adjust = offset % mPageSize;
off64_t adjOffset = offset - adjust;
- size_t adjLength = length + adjust;
+ size_t adjLength;
+ if (__builtin_add_overflow(length, adjust, &adjLength)) {
+ ALOGE("adjusted length overflow: length %zu adjust %d", length, adjust);
+ return false;
+ }
int flags = MAP_SHARED;
int prot = PROT_READ;
if (!readOnly) prot |= PROT_WRITE;
- void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
+ void* ptr = mmap64(nullptr, adjLength, prot, flags, fd, adjOffset);
if (ptr == MAP_FAILED) {
if (errno == EINVAL && length == 0) {
ptr = nullptr;
diff --git a/libutils/FileMap_test.cpp b/libutils/FileMap_test.cpp
index 576d89b..fd1c9b0 100644
--- a/libutils/FileMap_test.cpp
+++ b/libutils/FileMap_test.cpp
@@ -32,3 +32,36 @@
ASSERT_EQ(0u, m.getDataLength());
ASSERT_EQ(4096, m.getDataOffset());
}
+
+TEST(FileMap, large_offset) {
+ // Make sure that an offset > INT32_MAX will not fail the create
+ // function. See http://b/155662887.
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ off64_t offset = INT32_MAX + 1024LL;
+
+ // Make the temporary file large enough to pass the mmap.
+ ASSERT_EQ(offset, lseek64(tf.fd, offset, SEEK_SET));
+ char value = 0;
+ ASSERT_EQ(1, write(tf.fd, &value, 1));
+
+ android::FileMap m;
+ ASSERT_TRUE(m.create("test", tf.fd, offset, 0, true));
+ ASSERT_STREQ("test", m.getFileName());
+ ASSERT_EQ(0u, m.getDataLength());
+ ASSERT_EQ(offset, m.getDataOffset());
+}
+
+TEST(FileMap, offset_overflow) {
+ // Make sure that an end that overflows SIZE_MAX will not abort.
+ // See http://b/156997193.
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ off64_t offset = 200;
+ size_t length = SIZE_MAX;
+
+ android::FileMap m;
+ ASSERT_FALSE(m.create("test", tf.fd, offset, length, true));
+}
diff --git a/libutils/include/utils/Compat.h b/libutils/include/utils/Compat.h
index dee577e..6002567 100644
--- a/libutils/include/utils/Compat.h
+++ b/libutils/include/utils/Compat.h
@@ -19,12 +19,20 @@
#include <unistd.h>
+#if !defined(__MINGW32__)
+#include <sys/mman.h>
+#endif
+
#if defined(__APPLE__)
/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
-
+static_assert(sizeof(off_t) >= 8, "This code requires that Mac OS have at least a 64-bit off_t.");
typedef off_t off64_t;
+static inline void* mmap64(void* addr, size_t length, int prot, int flags, int fd, off64_t offset) {
+ return mmap(addr, length, prot, flags, fd, offset);
+}
+
static inline off64_t lseek64(int fd, off64_t offset, int whence) {
return lseek(fd, offset, whence);
}
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 1bbffaf..553136a 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -109,6 +109,12 @@
enabled: true,
},
},
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.art.debug",
+ "com.android.art.release",
+ ],
}
// Tests.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4b64715..01609db 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -177,6 +177,9 @@
mount binder binder /dev/binderfs stats=global
chmod 0755 /dev/binderfs
+ # Mount fusectl
+ mount fusectl none /sys/fs/fuse/connections
+
symlink /dev/binderfs/binder /dev/binder
symlink /dev/binderfs/hwbinder /dev/hwbinder
symlink /dev/binderfs/vndbinder /dev/vndbinder
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 9adbcba..e827cf5 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -5,6 +5,7 @@
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
+ onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index f6149c9..fe6dcfa 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -5,6 +5,7 @@
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
+ onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 0e69b16..adc7031 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -5,6 +5,7 @@
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
+ onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 3e80168..7029748 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -5,6 +5,7 @@
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
+ onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver