Merge "test_adb.py: silence ResourceWarning."
diff --git a/adb/Android.bp b/adb/Android.bp
index bccc71a..2a88de5 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -174,6 +174,12 @@
"libdiagnose_usb",
"libmdnssd",
"libusb",
+ "libandroidfw",
+ "libziparchive",
+ "libz",
+ "libutils",
+ "liblog",
+ "libcutils",
],
}
@@ -256,6 +262,12 @@
"liblog",
"libmdnssd",
"libusb",
+ "libandroidfw",
+ "libziparchive",
+ "libz",
+ "libutils",
+ "liblog",
+ "libcutils",
],
stl: "libc++_static",
@@ -474,7 +486,7 @@
},
}
-python_binary_host {
+python_test_host {
name: "adb_integration_test_device",
main: "test_device.py",
srcs: [
@@ -483,6 +495,8 @@
libs: [
"adb_py",
],
+ test_config: "adb_integration_test_device.xml",
+ test_suites: ["general-tests"],
version: {
py2: {
enabled: true,
diff --git a/adb/adb_integration_test_device.xml b/adb/adb_integration_test_device.xml
new file mode 100644
index 0000000..b892377
--- /dev/null
+++ b/adb/adb_integration_test_device.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config to run adb integration tests for device">
+ <option name="test-suite-tag" value="adb_tests" />
+ <option name="test-suite-tag" value="adb_integration_device" />
+ <target_preparer class="com.android.tradefed.targetprep.SemaphoreTokenTargetPreparer">
+ <option name="disable" value="false" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.adb.AdbStopServerPreparer" />
+ <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
+ <option name="par-file-name" value="adb_integration_test_device" />
+ <option name="inject-android-serial" value="true" />
+ <option name="test-timeout" value="2m" />
+ </test>
+</configuration>
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index f4a92e3..051ab73 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -21,6 +21,7 @@
#include <algorithm>
#include <list>
+#include <memory>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -29,7 +30,6 @@
#include "socket_spec.h"
#include "sysdeps.h"
-#include "sysdeps/memory.h"
#include "transport.h"
// A listener is an entity which binds to a local port and, upon receiving a connection on that
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 4cbc45a..d69dbef 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -14,31 +14,27 @@
* limitations under the License.
*/
-#define TRACE_TAG ADB
+#include "adb_install.h"
#include <stdio.h>
#include <stdlib.h>
-
-#include "adb.h"
-#include "adb_client.h"
-#include "adb_install.h"
-#include "adb_utils.h"
-#include "client/file_sync_client.h"
-#include "commandline.h"
-#include "fastdeploy.h"
-#include "sysdeps.h"
-
+#include <unistd.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
-#include <unistd.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/test_utils.h>
+#include "adb.h"
+#include "adb_client.h"
+#include "adb_utils.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
+#include "android-base/test_utils.h"
+#include "client/file_sync_client.h"
+#include "commandline.h"
+#include "fastdeploy.h"
+#include "sysdeps.h"
static constexpr int kFastDeployMinApi = 24;
@@ -146,41 +142,16 @@
TemporaryFile patchTmpFile;
FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
- int metadata_len = extract_metadata(file, metadataFile);
+ extract_metadata(file, metadataFile);
fclose(metadataFile);
- int result = -1;
- if (metadata_len <= 0) {
- printf("failed to extract metadata %d\n", metadata_len);
- return 1;
- } else {
- int create_patch_result = create_patch(file, metadataTmpFile.path, patchTmpFile.path);
- if (create_patch_result != 0) {
- printf("Patch creation failure, error code: %d\n", create_patch_result);
- result = create_patch_result;
- goto cleanup_streamed_apk;
- } else {
- std::vector<const char*> pm_args;
- // pass all but 1st (command) and last (apk path) parameters through to pm for
- // session creation
- for (int i = 1; i < argc - 1; i++) {
- pm_args.push_back(argv[i]);
- }
- int apply_patch_result =
- install_patch(file, patchTmpFile.path, pm_args.size(), pm_args.data());
- if (apply_patch_result != 0) {
- printf("Patch application failure, error code: %d\n", apply_patch_result);
- result = apply_patch_result;
- goto cleanup_streamed_apk;
- }
- }
- }
-
- cleanup_streamed_apk:
- if (use_fastdeploy == true) {
- delete_device_patch_file(file);
- }
- return result;
+ create_patch(file, metadataTmpFile.path, patchTmpFile.path);
+ // pass all but 1st (command) and last (apk path) parameters through to pm for
+ // session creation
+ std::vector<const char*> pm_args{argv + 1, argv + argc - 1};
+ install_patch(file, patchTmpFile.path, pm_args.size(), pm_args.data());
+ delete_device_patch_file(file);
+ return 0;
} else {
struct stat sb;
if (stat(file, &sb) == -1) {
@@ -265,29 +236,11 @@
TemporaryFile patchTmpFile;
FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
- int metadata_len = extract_metadata(apk_file[0], metadataFile);
+ extract_metadata(apk_file[0], metadataFile);
fclose(metadataFile);
- if (metadata_len <= 0) {
- printf("failed to extract metadata %d\n", metadata_len);
- return 1;
- } else {
- int create_patch_result =
- create_patch(apk_file[0], metadataTmpFile.path, patchTmpFile.path);
- if (create_patch_result != 0) {
- printf("Patch creation failure, error code: %d\n", create_patch_result);
- result = create_patch_result;
- goto cleanup_apk;
- } else {
- int apply_patch_result =
- apply_patch_on_device(apk_file[0], patchTmpFile.path, apk_dest.c_str());
- if (apply_patch_result != 0) {
- printf("Patch application failure, error code: %d\n", apply_patch_result);
- result = apply_patch_result;
- goto cleanup_apk;
- }
- }
- }
+ create_patch(apk_file[0], metadataTmpFile.path, patchTmpFile.path);
+ apply_patch_on_device(apk_file[0], patchTmpFile.path, apk_dest.c_str());
} else {
if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
}
@@ -347,7 +300,6 @@
use_localagent = true;
#endif
}
- // TODO: --installlog <filename>
}
if (installMode == INSTALL_DEFAULT) {
diff --git a/adb/client/adb_install.h b/adb/client/adb_install.h
index e9410a9..5b6c4cb 100644
--- a/adb/client/adb_install.h
+++ b/adb/client/adb_install.h
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-#ifndef ADB_INSTALL_H
-#define ADB_INSTALL_H
+#pragma once
-#include "fastdeploy.h"
+#include <string>
int install_app(int argc, const char** argv);
int install_multiple_app(int argc, const char** argv);
@@ -26,4 +25,3 @@
int delete_device_file(const std::string& filename);
int delete_host_file(const std::string& filename);
-#endif
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e38e305..07b5747 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -63,7 +63,6 @@
#include "services.h"
#include "shell_protocol.h"
#include "sysdeps/chrono.h"
-#include "sysdeps/memory.h"
extern int gListenAll;
@@ -1580,15 +1579,20 @@
}
return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
}
+ // clang-format off
else if (!strcmp(argv[0], "remount") ||
!strcmp(argv[0], "reboot") ||
!strcmp(argv[0], "reboot-bootloader") ||
+ !strcmp(argv[0], "reboot-fastboot") ||
!strcmp(argv[0], "usb") ||
!strcmp(argv[0], "disable-verity") ||
!strcmp(argv[0], "enable-verity")) {
+ // clang-format on
std::string command;
if (!strcmp(argv[0], "reboot-bootloader")) {
command = "reboot:bootloader";
+ } else if (!strcmp(argv[0], "reboot-fastboot")) {
+ command = "reboot:fastboot";
} else if (argc > 1) {
command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
} else {
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index d3f35c8..183a1fa 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#include <libgen.h>
+#include "fastdeploy.h"
+
#include <algorithm>
#include <array>
+#include <memory>
#include "android-base/file.h"
#include "android-base/strings.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/ZipFileRO.h"
#include "client/file_sync_client.h"
#include "commandline.h"
-#include "fastdeploy.h"
#include "fastdeploycallbacks.h"
#include "utils/String16.h"
@@ -138,60 +141,82 @@
}
}
-static std::string get_aapt2_path() {
- if (g_use_localagent) {
- // This should never happen on a Windows machine
- const char* host_out = getenv("ANDROID_HOST_OUT");
- if (host_out == nullptr) {
- fatal("Could not locate aapt2 because $ANDROID_HOST_OUT is not defined");
- }
- return android::base::StringPrintf("%s/bin/aapt2", host_out);
+static std::string get_string_from_utf16(const char16_t* input, int input_len) {
+ ssize_t utf8_length = utf16_to_utf8_length(input, input_len);
+ if (utf8_length <= 0) {
+ return {};
}
-
- std::string adb_dir = android::base::GetExecutableDirectory();
- if (adb_dir.empty()) {
- fatal("Could not locate aapt2");
- }
- return adb_dir + "/aapt2";
+ std::string utf8;
+ utf8.resize(utf8_length);
+ utf16_to_utf8(input, input_len, &*utf8.begin(), utf8_length + 1);
+ return utf8;
}
-static int system_capture(const char* cmd, std::string& output) {
- FILE* pipe = popen(cmd, "re");
- int fd = -1;
-
- if (pipe != nullptr) {
- fd = fileno(pipe);
- }
-
- if (fd == -1) {
- fatal_errno("Could not create pipe for process '%s'", cmd);
- }
-
- if (!android::base::ReadFdToString(fd, &output)) {
- fatal_errno("Error reading from process '%s'", cmd);
- }
-
- return pclose(pipe);
-}
-
-// output is required to point to a valid output string (non-null)
static std::string get_packagename_from_apk(const char* apkPath) {
- const char* kAapt2DumpNameCommandPattern = R"(%s dump packagename "%s")";
- std::string aapt2_path_string = get_aapt2_path();
- std::string getPackagenameCommand = android::base::StringPrintf(
- kAapt2DumpNameCommandPattern, aapt2_path_string.c_str(), apkPath);
-
- std::string package_name;
- int exit_code = system_capture(getPackagenameCommand.c_str(), package_name);
- if (exit_code != 0) {
- fatal("Error executing '%s' exitcode: %d", getPackagenameCommand.c_str(), exit_code);
+ std::unique_ptr<android::ZipFileRO> zipFile(android::ZipFileRO::open(apkPath));
+ if (zipFile == nullptr) {
+ fatal("Could not open %s", apkPath);
}
-
- // strip any line end characters from the output
- return android::base::Trim(package_name);
+ android::ZipEntryRO entry = zipFile->findEntryByName("AndroidManifest.xml");
+ if (entry == nullptr) {
+ fatal("Could not find AndroidManifest.xml inside %s", apkPath);
+ }
+ uint32_t manifest_len = 0;
+ if (!zipFile->getEntryInfo(entry, NULL, &manifest_len, NULL, NULL, NULL, NULL)) {
+ fatal("Could not read AndroidManifest.xml inside %s", apkPath);
+ }
+ std::vector<char> manifest_data(manifest_len);
+ if (!zipFile->uncompressEntry(entry, manifest_data.data(), manifest_len)) {
+ fatal("Could not uncompress AndroidManifest.xml inside %s", apkPath);
+ }
+ android::ResXMLTree tree;
+ android::status_t setto_status = tree.setTo(manifest_data.data(), manifest_len, true);
+ if (setto_status != android::OK) {
+ fatal("Could not parse AndroidManifest.xml inside %s", apkPath);
+ }
+ android::ResXMLParser::event_code_t code;
+ while ((code = tree.next()) != android::ResXMLParser::BAD_DOCUMENT &&
+ code != android::ResXMLParser::END_DOCUMENT) {
+ switch (code) {
+ case android::ResXMLParser::START_TAG: {
+ size_t element_name_length;
+ const char16_t* element_name = tree.getElementName(&element_name_length);
+ if (element_name == nullptr) {
+ continue;
+ }
+ std::u16string element_name_string(element_name, element_name_length);
+ if (element_name_string == u"manifest") {
+ for (size_t i = 0; i < tree.getAttributeCount(); i++) {
+ size_t attribute_name_length;
+ const char16_t* attribute_name_text =
+ tree.getAttributeName(i, &attribute_name_length);
+ if (attribute_name_text == nullptr) {
+ continue;
+ }
+ std::u16string attribute_name_string(attribute_name_text,
+ attribute_name_length);
+ if (attribute_name_string == u"package") {
+ size_t attribute_value_length;
+ const char16_t* attribute_value_text =
+ tree.getAttributeStringValue(i, &attribute_value_length);
+ if (attribute_value_text == nullptr) {
+ continue;
+ }
+ return get_string_from_utf16(attribute_value_text,
+ attribute_value_length);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ fatal("Could not find package name tag in AndroidManifest.xml inside %s", apkPath);
}
-int extract_metadata(const char* apkPath, FILE* outputFp) {
+void extract_metadata(const char* apkPath, FILE* outputFp) {
std::string packageName = get_packagename_from_apk(apkPath);
const char* kAgentExtractCommandPattern = "/data/local/tmp/deployagent extract %s";
std::string extractCommand =
@@ -200,13 +225,10 @@
std::vector<char> extractErrorBuffer;
int statusCode;
DeployAgentFileCallback cb(outputFp, &extractErrorBuffer, &statusCode);
- int ret = send_shell_command(extractCommand, false, &cb);
-
- if (ret == 0) {
- return cb.getBytesWritten();
+ int returnCode = send_shell_command(extractCommand, false, &cb);
+ if (returnCode != 0) {
+ fatal("Executing %s returned %d\n", extractCommand.c_str(), returnCode);
}
-
- return ret;
}
static std::string get_patch_generator_command() {
@@ -229,11 +251,14 @@
adb_dir.c_str());
}
-int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath) {
+void create_patch(const char* apkPath, const char* metadataPath, const char* patchPath) {
std::string generatePatchCommand = android::base::StringPrintf(
R"(%s "%s" "%s" > "%s")", get_patch_generator_command().c_str(), apkPath, metadataPath,
patchPath);
- return system(generatePatchCommand.c_str());
+ int returnCode = system(generatePatchCommand.c_str());
+ if (returnCode != 0) {
+ fatal("Executing %s returned %d\n", generatePatchCommand.c_str(), returnCode);
+ }
}
std::string get_patch_path(const char* apkPath) {
@@ -243,36 +268,38 @@
return patchDevicePath;
}
-int apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath) {
+void apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath) {
const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -o %s";
std::string packageName = get_packagename_from_apk(apkPath);
std::string patchDevicePath = get_patch_path(apkPath);
std::vector<const char*> srcs = {patchPath};
bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
-
if (!push_ok) {
- return -1;
+ fatal("Error pushing %s to %s returned\n", patchPath, patchDevicePath.c_str());
}
std::string applyPatchCommand =
android::base::StringPrintf(kAgentApplyCommandPattern.c_str(), packageName.c_str(),
patchDevicePath.c_str(), outputPath);
- return send_shell_command(applyPatchCommand);
+ int returnCode = send_shell_command(applyPatchCommand);
+ if (returnCode != 0) {
+ fatal("Executing %s returned %d\n", applyPatchCommand.c_str(), returnCode);
+ }
}
-int install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv) {
+void install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv) {
const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -pm %s";
std::string packageName = get_packagename_from_apk(apkPath);
- std::vector<const char*> srcs;
+
std::string patchDevicePath =
android::base::StringPrintf("%s%s.patch", kDeviceAgentPath, packageName.c_str());
- srcs.push_back(patchPath);
- bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
+ std::vector<const char*> srcs{patchPath};
+ bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
if (!push_ok) {
- return -1;
+ fatal("Error pushing %s to %s returned\n", patchPath, patchDevicePath.c_str());
}
std::vector<unsigned char> applyOutputBuffer;
@@ -287,5 +314,8 @@
std::string applyPatchCommand =
android::base::StringPrintf(kAgentApplyCommandPattern.c_str(), packageName.c_str(),
patchDevicePath.c_str(), argsString.c_str());
- return send_shell_command(applyPatchCommand);
+ int returnCode = send_shell_command(applyPatchCommand);
+ if (returnCode != 0) {
+ fatal("Executing %s returned %d\n", applyPatchCommand.c_str(), returnCode);
+ }
}
diff --git a/adb/client/fastdeploy.h b/adb/client/fastdeploy.h
index e5e7663..a6b10d3 100644
--- a/adb/client/fastdeploy.h
+++ b/adb/client/fastdeploy.h
@@ -16,7 +16,7 @@
#pragma once
-#include "adb.h"
+#include <string>
enum FastDeploy_AgentUpdateStrategy {
FastDeploy_AgentUpdateAlways,
@@ -27,8 +27,8 @@
void fastdeploy_set_local_agent(bool use_localagent);
int get_device_api_level();
void update_agent(FastDeploy_AgentUpdateStrategy agentUpdateStrategy);
-int extract_metadata(const char* apkPath, FILE* outputFp);
-int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath);
-int apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath);
-int install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv);
+void extract_metadata(const char* apkPath, FILE* outputFp);
+void create_patch(const char* apkPath, const char* metadataPath, const char* patchPath);
+void apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath);
+void install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv);
std::string get_patch_path(const char* apkPath);
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 8c39a20..d55096a 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -32,6 +32,10 @@
#include <unistd.h>
#include <utime.h>
+#include <memory>
+#include <string>
+#include <vector>
+
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -47,6 +51,7 @@
#include "security_log_tags.h"
#include "sysdeps/errno.h"
+using android::base::Dirname;
using android::base::StringPrintf;
static bool should_use_fs_config(const std::string& path) {
@@ -219,7 +224,7 @@
}
if (fd < 0 && errno == ENOENT) {
- if (!secure_mkdirs(android::base::Dirname(path))) {
+ if (!secure_mkdirs(Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
goto fail;
}
@@ -327,8 +332,6 @@
#else
static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
syncmsg msg;
- unsigned int len;
- int ret;
if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
@@ -337,24 +340,28 @@
return false;
}
- len = msg.data.size;
+ unsigned int len = msg.data.size;
if (len > buffer.size()) { // TODO: resize buffer?
SendSyncFail(s, "oversize data message");
return false;
}
if (!ReadFdExactly(s, &buffer[0], len)) return false;
- ret = symlink(&buffer[0], path.c_str());
- if (ret && errno == ENOENT) {
- if (!secure_mkdirs(android::base::Dirname(path))) {
- SendSyncFailErrno(s, "secure_mkdirs failed");
+ std::string buf_link;
+ if (!android::base::Readlink(path, &buf_link) || (buf_link != &buffer[0])) {
+ adb_unlink(path.c_str());
+ auto ret = symlink(&buffer[0], path.c_str());
+ if (ret && errno == ENOENT) {
+ if (!secure_mkdirs(Dirname(path))) {
+ SendSyncFailErrno(s, "secure_mkdirs failed");
+ return false;
+ }
+ ret = symlink(&buffer[0], path.c_str());
+ }
+ if (ret) {
+ SendSyncFailErrno(s, "symlink failed");
return false;
}
- ret = symlink(&buffer[0], path.c_str());
- }
- if (ret) {
- SendSyncFailErrno(s, "symlink failed");
- return false;
}
if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
@@ -391,7 +398,8 @@
// Don't delete files before copying if they are not "regular" or symlinks.
struct stat st;
- bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+ bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) ||
+ (S_ISLNK(st.st_mode) && !S_ISLNK(mode));
if (do_unlink) {
adb_unlink(path.c_str());
}
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index 0cb2439..816134f 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include <limits>
+#include <memory>
#include <queue>
#include <string>
#include <thread>
@@ -26,7 +27,6 @@
#include "adb_io.h"
#include "fdevent_test.h"
-#include "sysdeps/memory.h"
class FdHandler {
public:
diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp
index 6869947..9a37ea2 100644
--- a/adb/sysdeps/errno.cpp
+++ b/adb/sysdeps/errno.cpp
@@ -24,10 +24,6 @@
#include "adb.h"
-#if defined(_WIN32)
-#define ETXTBSY EBUSY
-#endif
-
// Use the linux asm-generic values for errno (which are used on all android archs but mips).
#define ERRNO_VALUES() \
ERRNO_VALUE(EACCES, 13); \
diff --git a/adb/sysdeps/memory.h b/adb/sysdeps/memory.h
deleted file mode 100644
index 4108aff..0000000
--- a/adb/sysdeps/memory.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <memory>
-#include <type_traits>
-
-#if defined(_WIN32)
-// We don't have C++14 on Windows yet.
-// Reimplement std::make_unique ourselves until we do.
-
-namespace internal {
-
-template <typename T>
-struct array_known_bounds;
-
-template <typename T>
-struct array_known_bounds<T[]> {
- constexpr static bool value = false;
-};
-
-template <typename T, size_t N>
-struct array_known_bounds<T[N]> {
- constexpr static bool value = true;
-};
-
-} // namespace internal
-
-namespace std {
-
-template <typename T, typename... Args>
-typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(
- Args&&... args) {
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
-}
-
-template <typename T>
-typename std::enable_if<std::is_array<T>::value && !internal::array_known_bounds<T>::value,
- std::unique_ptr<T>>::type
-make_unique(std::size_t size) {
- return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
-}
-
-template <typename T, typename... Args>
-typename std::enable_if<std::is_array<T>::value && internal::array_known_bounds<T>::value,
- std::unique_ptr<T>>::type
-make_unique(Args&&... args) = delete;
-
-} // namespace std
-
-#endif
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 8784757..0a08fbb 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -94,6 +94,10 @@
_fh_socket_writev,
};
+#if defined(assert)
+#undef assert
+#endif
+
#define assert(cond) \
do { \
if (!(cond)) fatal("assertion failed '%s' on %s:%d\n", #cond, __FILE__, __LINE__); \
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 95df490..cabd279 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -17,7 +17,6 @@
#define TRACE_TAG TRANSPORT
#include "sysdeps.h"
-#include "sysdeps/memory.h"
#include "transport.h"
@@ -32,6 +31,7 @@
#include <algorithm>
#include <deque>
#include <list>
+#include <memory>
#include <mutex>
#include <set>
#include <thread>
diff --git a/adb/transport_fd.cpp b/adb/transport_fd.cpp
index 85f3c52..ec61279 100644
--- a/adb/transport_fd.cpp
+++ b/adb/transport_fd.cpp
@@ -17,6 +17,7 @@
#include <stdint.h>
#include <deque>
+#include <memory>
#include <mutex>
#include <string>
#include <thread>
@@ -28,7 +29,6 @@
#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "sysdeps.h"
-#include "sysdeps/memory.h"
#include "transport.h"
#include "types.h"
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 8353d89..dc87ac7 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <condition_variable>
+#include <memory>
#include <mutex>
#include <thread>
#include <unordered_map>
@@ -45,7 +46,6 @@
#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "sysdeps/chrono.h"
-#include "sysdeps/memory.h"
#if ADB_HOST
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 602970c..c471bf9 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -16,8 +16,9 @@
#define TRACE_TAG TRANSPORT
+#include <memory>
+
#include "sysdeps.h"
-#include "sysdeps/memory.h"
#include "transport.h"
#include <stdio.h>
diff --git a/adb/types.h b/adb/types.h
index 1f7008e..0c71c3a 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -25,7 +25,6 @@
#include <android-base/logging.h>
-#include "sysdeps/memory.h"
#include "sysdeps/uio.h"
// Essentially std::vector<char>, except without zero initialization or reallocation.
diff --git a/adb/types_test.cpp b/adb/types_test.cpp
index 31ab90a..1fbd2ca 100644
--- a/adb/types_test.cpp
+++ b/adb/types_test.cpp
@@ -16,7 +16,7 @@
#include <gtest/gtest.h>
-#include "sysdeps/memory.h"
+#include <memory>
#include "types.h"
static std::unique_ptr<IOVector::block_type> create_block(const std::string& string) {
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 9444fdd..be8b97b 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -22,6 +22,7 @@
#include <limits>
#include <string>
+#include <type_traits>
namespace android {
namespace base {
@@ -33,6 +34,7 @@
template <typename T>
bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
bool allow_suffixes = false) {
+ static_assert(std::is_unsigned<T>::value, "ParseUint can only be used with unsigned types");
while (isspace(*s)) {
s++;
}
@@ -96,6 +98,7 @@
bool ParseInt(const char* s, T* out,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
+ static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
while (isspace(*s)) {
s++;
}
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
index 4b91623..1a414ec 100644
--- a/base/include/android-base/utf8.h
+++ b/base/include/android-base/utf8.h
@@ -17,6 +17,7 @@
#pragma once
#ifdef _WIN32
+#include <sys/types.h>
#include <string>
#else
// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 3f663ef..6e45133 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -131,6 +131,11 @@
if (args.size() < 2) {
return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
}
+
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
+ }
+
PartitionHandle handle;
if (!OpenPartition(device, args[1], &handle)) {
return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
@@ -163,9 +168,15 @@
if (args.size() < 2) {
return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
}
+
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL,
+ "Download is not allowed on locked devices");
+ }
+
// arg[0] is the command name, arg[1] contains size of data to be downloaded
unsigned int size;
- if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) {
+ if (!android::base::ParseUint("0x" + args[1], &size, kMaxDownloadSizeDefault)) {
return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
}
device->download_data().resize(size);
@@ -203,6 +214,11 @@
return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
}
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL,
+ "set_active command is not allowed on locked devices");
+ }
+
// Slot suffix needs to be between 'a' and 'z'.
Slot slot;
if (!GetSlotNumber(args[1], &slot)) {
@@ -221,7 +237,13 @@
CommandResult ret;
auto cb = [&ret](CommandResult result) { ret = result; };
auto result = boot_control_hal->setActiveBootSlot(slot, cb);
- if (result.isOk() && ret.success) return device->WriteStatus(FastbootResult::OKAY, "");
+ if (result.isOk() && ret.success) {
+ // Save as slot suffix to match the suffix format as returned from
+ // the boot control HAL.
+ auto current_slot = "_" + args[1];
+ device->set_active_slot(current_slot);
+ return device->WriteStatus(FastbootResult::OKAY, "");
+ }
return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
}
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
index 9df43a9..bb1f988 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -19,6 +19,8 @@
#include <string>
#include <vector>
+constexpr unsigned int kMaxDownloadSizeDefault = 0x20000000;
+
class FastbootDevice;
enum class FastbootResult {
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index b843c05..6cb4892 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -57,7 +57,8 @@
transport_(std::make_unique<ClientUsbTransport>()),
boot_control_hal_(IBootControl::getService()),
health_hal_(get_health_service()),
- fastboot_hal_(IFastboot::getService()) {}
+ fastboot_hal_(IFastboot::getService()),
+ active_slot_("") {}
FastbootDevice::~FastbootDevice() {
CloseDevice();
@@ -68,6 +69,11 @@
}
std::string FastbootDevice::GetCurrentSlot() {
+ // Check if a set_active ccommand was issued earlier since the boot control HAL
+ // returns the slot that is currently booted into.
+ if (!active_slot_.empty()) {
+ return active_slot_;
+ }
// Non-A/B devices must not have boot control HALs.
if (!boot_control_hal_) {
return "";
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index 2eb7177..091aadf 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -56,6 +56,8 @@
}
android::sp<android::hardware::health::V2_0::IHealth> health_hal() { return health_hal_; }
+ void set_active_slot(const std::string& active_slot) { active_slot_ = active_slot; }
+
private:
const std::unordered_map<std::string, CommandHandler> kCommandMap;
@@ -64,4 +66,5 @@
android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
std::vector<char> download_data_;
+ std::string active_slot_;
};
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 4fc3d1d..2347496 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -72,7 +72,7 @@
}
int FlashSparseData(int fd, std::vector<char>& downloaded_data) {
- struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(), true, true);
+ struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(), true, false);
if (!file) {
return -ENOENT;
}
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 528abec..b844b9f 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -23,6 +23,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
#include <liblp/liblp.h>
@@ -82,6 +83,10 @@
}
std::optional<std::string> FindPhysicalPartition(const std::string& name) {
+ // Check for an invalid file name
+ if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) {
+ return {};
+ }
std::string path = "/dev/block/by-name/" + name;
if (access(path.c_str(), W_OK) < 0) {
return {};
@@ -164,6 +169,9 @@
bool GetDeviceLockStatus() {
std::string cmdline;
- android::base::ReadFileToString("/proc/cmdline", &cmdline);
+ // Return lock status true if unable to read kernel command line.
+ if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ return true;
+ }
return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
}
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 2de79b1..cbd2856 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -36,7 +36,6 @@
using ::android::hardware::fastboot::V1_0::Result;
using ::android::hardware::fastboot::V1_0::Status;
-constexpr int kMaxDownloadSizeDefault = 0x20000000;
constexpr char kFastbootProtocolVersion[] = "0.4";
bool GetVersion(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
@@ -289,7 +288,7 @@
bool is_zero_length;
if (LogicalPartitionExists(args[0], device->GetCurrentSlot(), &is_zero_length) &&
is_zero_length) {
- *message = "0";
+ *message = "0x0";
return true;
}
// Otherwise, open the partition as normal.
@@ -309,7 +308,14 @@
*message = "Missing argument";
return false;
}
+
std::string partition_name = args[0];
+ if (!FindPhysicalPartition(partition_name) &&
+ !LogicalPartitionExists(partition_name, device->GetCurrentSlot())) {
+ *message = "Invalid partition";
+ return false;
+ }
+
auto fastboot_hal = device->fastboot_hal();
if (!fastboot_hal) {
*message = "Fastboot HAL not found";
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5962650..e27a897 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -155,10 +155,10 @@
{ nullptr, "system_other.img", "system.sig", "system", true, ImageType::Normal },
{ "userdata", "userdata.img", "userdata.sig", "userdata", true, ImageType::Extra },
{ "vbmeta", "vbmeta.img", "vbmeta.sig", "vbmeta", true, ImageType::BootCritical },
- { "vbmeta_mainline",
- "vbmeta_mainline.img",
- "vbmeta_mainline.sig",
- "vbmeta_mainline",
+ { "vbmeta_system",
+ "vbmeta_system.img",
+ "vbmeta_system.sig",
+ "vbmeta_system",
true, ImageType::BootCritical },
{ "vendor", "vendor.img", "vendor.sig", "vendor", true, ImageType::Normal },
{ nullptr, "vendor_other.img", "vendor.sig", "vendor", true, ImageType::Normal },
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index e2076f5..c02ab1c 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -43,6 +43,7 @@
#include <thread>
#include <vector>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
#include <sparse/sparse.h>
@@ -331,8 +332,9 @@
<< cmd + " responded with a string with leading whitespace";
EXPECT_FALSE(resp.compare(0, 2, "0x"))
<< cmd + "responded with a string that does not start with 0x...";
- int64_t size = strtoll(resp.c_str(), nullptr, 16);
- EXPECT_GT(size, 0) << "'" + resp + "' is not a valid response from " + cmd;
+ uint64_t size;
+ ASSERT_TRUE(android::base::ParseUint(resp, &size))
+ << "'" + resp + "' is not a valid response from " + cmd;
}
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 3ab9732..a6ef35b 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -37,6 +37,7 @@
#include <memory>
#include <string>
#include <thread>
+#include <utility>
#include <vector>
#include <android-base/file.h>
@@ -850,56 +851,115 @@
return true;
}
-bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
- if (fs_mgr_is_checkpoint_fs(rec)) {
- if (!strcmp(rec->fs_type, "f2fs")) {
- std::string opts(rec->fs_options);
+class CheckpointManager {
+ public:
+ CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
- opts += ",checkpoint=disable";
- free(rec->fs_options);
- rec->fs_options = strdup(opts.c_str());
- } else {
- LERROR << rec->fs_type << " does not implement checkpoints.";
+ bool Update(struct fstab_rec* rec) {
+ if (!fs_mgr_is_checkpoint(rec)) {
+ return true;
}
- } else if (fs_mgr_is_checkpoint_blk(rec)) {
- call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
- android::base::unique_fd fd(
- TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
- if (!fd) {
- PERROR << "Cannot open device " << rec->blk_device;
+ if (fs_mgr_is_checkpoint_blk(rec)) {
+ call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
+ }
+
+ if (needs_checkpoint_ == UNKNOWN &&
+ !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
+ LERROR << "Failed to find if checkpointing is needed. Assuming no.";
+ needs_checkpoint_ = NO;
+ }
+
+ if (needs_checkpoint_ != YES) {
+ return true;
+ }
+
+ if (!UpdateCheckpointPartition(rec)) {
+ LERROR << "Could not set up checkpoint partition, skipping!";
return false;
}
- uint64_t size = get_block_device_size(fd) / 512;
- if (!size) {
- PERROR << "Cannot get device size";
- return false;
+ return true;
+ }
+
+ bool Revert(struct fstab_rec* rec) {
+ if (!fs_mgr_is_checkpoint(rec)) {
+ return true;
}
- android::dm::DmTable table;
- if (!table.AddTarget(
- std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
- LERROR << "Failed to add Bow target";
- return false;
+ if (device_map_.find(rec->blk_device) == device_map_.end()) {
+ return true;
}
+ std::string bow_device = rec->blk_device;
+ free(rec->blk_device);
+ rec->blk_device = strdup(device_map_[bow_device].c_str());
+ device_map_.erase(bow_device);
+
DeviceMapper& dm = DeviceMapper::Instance();
- if (!dm.CreateDevice("bow", table)) {
- PERROR << "Failed to create bow device";
- return false;
+ if (!dm.DeleteDevice("bow")) {
+ PERROR << "Failed to remove bow device";
}
- std::string name;
- if (!dm.GetDmDevicePathByName("bow", &name)) {
- PERROR << "Failed to get bow device name";
- return false;
- }
-
- rec->blk_device = strdup(name.c_str());
+ return true;
}
- return true;
-}
+
+ private:
+ bool UpdateCheckpointPartition(struct fstab_rec* rec) {
+ if (fs_mgr_is_checkpoint_fs(rec)) {
+ if (!strcmp(rec->fs_type, "f2fs")) {
+ std::string opts(rec->fs_options);
+
+ opts += ",checkpoint=disable";
+ free(rec->fs_options);
+ rec->fs_options = strdup(opts.c_str());
+ } else {
+ LERROR << rec->fs_type << " does not implement checkpoints.";
+ }
+ } else if (fs_mgr_is_checkpoint_blk(rec)) {
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
+ if (!fd) {
+ PERROR << "Cannot open device " << rec->blk_device;
+ return false;
+ }
+
+ uint64_t size = get_block_device_size(fd) / 512;
+ if (!size) {
+ PERROR << "Cannot get device size";
+ return false;
+ }
+
+ android::dm::DmTable table;
+ if (!table.AddTarget(
+ std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
+ LERROR << "Failed to add bow target";
+ return false;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ if (!dm.CreateDevice("bow", table)) {
+ PERROR << "Failed to create bow device";
+ return false;
+ }
+
+ std::string name;
+ if (!dm.GetDmDevicePathByName("bow", &name)) {
+ PERROR << "Failed to get bow device name";
+ return false;
+ }
+
+ device_map_[name] = rec->blk_device;
+ free(rec->blk_device);
+ rec->blk_device = strdup(name.c_str());
+ }
+ return true;
+ }
+
+ enum { UNKNOWN = -1, NO = 0, YES = 1 };
+ int needs_checkpoint_;
+ std::map<std::string, std::string> device_map_;
+};
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
@@ -913,7 +973,7 @@
int mret = -1;
int mount_errno = 0;
int attempted_idx = -1;
- int need_checkpoint = -1;
+ CheckpointManager checkpoint_manager;
FsManagerAvbUniquePtr avb_handle(nullptr);
if (!fstab) {
@@ -960,16 +1020,8 @@
}
}
- if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
- if (need_checkpoint == -1 &&
- !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
- LERROR << "Failed to find if checkpointing is needed. Assuming no.";
- need_checkpoint = 0;
- }
- if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
- LERROR << "Could not set up checkpoint partition, skipping!";
- continue;
- }
+ if (!checkpoint_manager.Update(&fstab->recs[i])) {
+ continue;
}
if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
@@ -1052,6 +1104,9 @@
<< " is wiped and " << fstab->recs[top_idx].mount_point
<< " " << fstab->recs[top_idx].fs_type
<< " is formattable. Format it.";
+
+ checkpoint_manager.Revert(&fstab->recs[top_idx]);
+
if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY);
@@ -1172,11 +1227,12 @@
* in turn, and stop on 1st success, or no more match.
*/
static int fs_mgr_do_mount_helper(fstab* fstab, const char* n_name, char* n_blk_device,
- char* tmp_mount_point, int need_checkpoint) {
+ char* tmp_mount_point, int needs_checkpoint) {
int i = 0;
int mount_errors = 0;
int first_mount_errno = 0;
char* mount_point;
+ CheckpointManager checkpoint_manager(needs_checkpoint);
FsManagerAvbUniquePtr avb_handle(nullptr);
if (!fstab) {
@@ -1205,16 +1261,9 @@
}
}
- if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
- if (need_checkpoint == -1 &&
- !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
- LERROR << "Failed to find if checkpointing is needed. Assuming no.";
- need_checkpoint = 0;
- }
- if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
- LERROR << "Could not set up checkpoint partition, skipping!";
- continue;
- }
+ if (!checkpoint_manager.Update(&fstab->recs[i])) {
+ LERROR << "Could not set up checkpoint partition, skipping!";
+ continue;
}
/* First check the filesystem if requested */
@@ -1291,8 +1340,8 @@
}
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
- bool needs_cp) {
- return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_cp);
+ bool needs_checkpoint) {
+ return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_checkpoint);
}
/*
@@ -1497,19 +1546,18 @@
DeviceMapper& dm = DeviceMapper::Instance();
- bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true";
-
for (int i = 0; i < fstab->num_entries; i++) {
- if (!fs_mgr_is_verified(&fstab->recs[i]) && !fs_mgr_is_avb(&fstab->recs[i])) {
+ auto fsrec = &fstab->recs[i];
+ if (!fs_mgr_is_verified(fsrec) && !fs_mgr_is_avb(fsrec)) {
continue;
}
std::string mount_point;
- if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+ if (!strcmp(fsrec->mount_point, "/")) {
// In AVB, the dm device name is vroot instead of system.
- mount_point = fs_mgr_is_avb(&fstab->recs[i]) ? "vroot" : "system";
+ mount_point = fs_mgr_is_avb(fsrec) ? "vroot" : "system";
} else {
- mount_point = basename(fstab->recs[i].mount_point);
+ mount_point = basename(fsrec->mount_point);
}
if (dm.GetState(mount_point) == DmDeviceState::INVALID) {
@@ -1517,15 +1565,14 @@
continue;
}
- const char* status = nullptr;
+ const char* status;
std::vector<DeviceMapper::TargetInfo> table;
if (!dm.GetTableStatus(mount_point, &table) || table.empty() || table[0].data.empty()) {
- if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
- status = "V";
- } else {
- PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str();
+ if (!fs_mgr_is_verifyatboot(fsrec)) {
+ PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point;
continue;
}
+ status = "V";
} else {
status = table[0].data.c_str();
}
@@ -1535,7 +1582,7 @@
// instead of [partition.vroot.verified].
if (mount_point == "vroot") mount_point = "system";
if (*status == 'C' || *status == 'V') {
- callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
+ callback(fsrec, mount_point.c_str(), mode, *status);
}
}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 95326d1..4934f5a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -29,6 +29,7 @@
#include <sys/vfs.h>
#include <unistd.h>
+#include <algorithm>
#include <map>
#include <memory>
#include <string>
@@ -40,12 +41,18 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/ext4_utils.h>
+#include <fs_mgr_dm_linear.h>
#include <fs_mgr_overlayfs.h>
#include <fstab/fstab.h>
+#include <libdm/dm.h>
+#include <liblp/builder.h>
+#include <liblp/liblp.h>
#include "fs_mgr_priv.h"
using namespace std::literals;
+using namespace android::dm;
+using namespace android::fs_mgr;
#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
@@ -71,8 +78,10 @@
namespace {
-// acceptable overlayfs backing storage
-const auto kOverlayMountPoint = "/cache"s;
+// list of acceptable overlayfs backing storage
+const auto kScratchMountPoint = "/mnt/scratch"s;
+const auto kCacheMountPoint = "/cache"s;
+const std::vector<const std::string> kOverlayMountPoints = {kScratchMountPoint, kCacheMountPoint};
// Return true if everything is mounted, but before adb is started. Right
// after 'trigger load_persist_props_action' is done.
@@ -133,14 +142,17 @@
std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
if (!fs_mgr_is_dir(mount_point)) return "";
- auto dir =
- kOverlayMountPoint + kOverlayTopDir + "/" + android::base::Basename(mount_point) + "/";
- auto upper = dir + kUpperName;
- if (!fs_mgr_is_dir(upper)) return "";
- auto work = dir + kWorkName;
- if (!fs_mgr_is_dir(work)) return "";
- if (!fs_mgr_dir_is_writable(work)) return "";
- return dir;
+ const auto base = android::base::Basename(mount_point) + "/";
+ for (const auto& overlay_mount_point : kOverlayMountPoints) {
+ auto dir = overlay_mount_point + kOverlayTopDir + "/" + base;
+ auto upper = dir + kUpperName;
+ if (!fs_mgr_is_dir(upper)) continue;
+ auto work = dir + kWorkName;
+ if (!fs_mgr_is_dir(work)) continue;
+ if (!fs_mgr_dir_is_writable(work)) continue;
+ return dir;
+ }
+ return "";
}
const auto kLowerdirOption = "lowerdir="s;
@@ -155,25 +167,9 @@
candidate + kUpperName + ",workdir=" + candidate + kWorkName;
}
-bool fs_mgr_system_root_image(const fstab* fstab) {
- if (!fstab) { // can not happen?
- // This will return empty on init first_stage_mount,
- // hence why we prefer checking the fstab instead.
- return android::base::GetBoolProperty("ro.build.system_root_image", false);
- }
- for (auto i = 0; i < fstab->num_entries; i++) {
- const auto fsrec = &fstab->recs[i];
- auto fsrec_mount_point = fsrec->mount_point;
- if (!fsrec_mount_point) continue;
- if ("/system"s == fsrec_mount_point) return false;
- }
- return true;
-}
-
-const char* fs_mgr_mount_point(const fstab* fstab, const char* mount_point) {
+const char* fs_mgr_mount_point(const char* mount_point) {
if (!mount_point) return mount_point;
if ("/"s != mount_point) return mount_point;
- if (!fs_mgr_system_root_image(fstab)) return mount_point;
return "/system";
}
@@ -184,6 +180,14 @@
return ret;
}
+bool fs_mgr_rw_access(const std::string& path) {
+ if (path.empty()) return false;
+ auto save_errno = errno;
+ auto ret = access(path.c_str(), R_OK | W_OK) == 0;
+ errno = save_errno;
+ return ret;
+}
+
// return true if system supports overlayfs
bool fs_mgr_wants_overlayfs() {
// Properties will return empty on init first_stage_mount, so speculative
@@ -197,7 +201,7 @@
return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
}
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) {
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"),
fs_mgr_free_fstab);
if (!fstab) return false;
@@ -206,10 +210,11 @@
const auto fsrec = &fstab->recs[i];
const auto fs_type = fsrec->fs_type;
if (!fs_type) continue;
- if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
+ if (overlay_only && ("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
auto fsrec_mount_point = fsrec->mount_point;
if (!fsrec_mount_point) continue;
if (mount_point != fsrec_mount_point) continue;
+ if (!overlay_only) return true;
const auto fs_options = fsrec->fs_options;
if (!fs_options) continue;
const auto options = android::base::Split(fs_options, ",");
@@ -222,13 +227,12 @@
return false;
}
-bool fs_mgr_overlayfs_verity_enabled(const std::string& basename_mount_point) {
- auto found = false;
- fs_mgr_update_verity_state(
- [&basename_mount_point, &found](fstab_rec*, const char* mount_point, int, int) {
- if (mount_point && (basename_mount_point == mount_point)) found = true;
- });
- return found;
+std::vector<std::string> fs_mgr_overlayfs_verity_enabled_list() {
+ std::vector<std::string> ret;
+ fs_mgr_update_verity_state([&ret](fstab_rec*, const char* mount_point, int, int) {
+ ret.emplace_back(mount_point);
+ });
+ return ret;
}
bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
@@ -254,7 +258,7 @@
if (!fs_mgr_overlayfs_enabled(fsrec)) return false;
- return !fs_mgr_overlayfs_verity_enabled(android::base::Basename(fsrec_mount_point));
+ return true;
}
bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr) {
@@ -371,6 +375,67 @@
return ret;
}
+uint32_t fs_mgr_overlayfs_slot_number() {
+ return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
+}
+
+std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) {
+ return "/dev/block/by-name/" + fs_mgr_get_super_partition_name(slot_number);
+}
+
+bool fs_mgr_overlayfs_has_logical(const fstab* fstab) {
+ if (!fstab) return false;
+ for (auto i = 0; i < fstab->num_entries; i++) {
+ const auto fsrec = &fstab->recs[i];
+ if (fs_mgr_is_logical(fsrec)) return true;
+ }
+ return false;
+}
+
+// reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise
+std::string scratch_device_cache;
+
+bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) {
+ // umount and delete kScratchMountPoint storage if we have logical partitions
+ if (overlay != kScratchMountPoint) return true;
+ scratch_device_cache.erase();
+ auto slot_number = fs_mgr_overlayfs_slot_number();
+ auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+ if (!fs_mgr_rw_access(super_device)) return true;
+
+ auto save_errno = errno;
+ if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
+ // Lazy umount will allow us to move on and possibly later
+ // establish a new fresh mount without requiring a reboot should
+ // the developer wish to restart. Old references should melt
+ // away or have no data. Main goal is to shut the door on the
+ // current overrides with an expectation of a subsequent reboot,
+ // thus any errors here are ignored.
+ umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+ }
+ auto builder = MetadataBuilder::New(super_device, slot_number);
+ if (!builder) {
+ errno = save_errno;
+ return true;
+ }
+ const auto partition_name = android::base::Basename(kScratchMountPoint);
+ if (builder->FindPartition(partition_name) == nullptr) {
+ errno = save_errno;
+ return true;
+ }
+ builder->RemovePartition(partition_name);
+ auto metadata = builder->Export();
+ if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+ if (change) *change = true;
+ if (!DestroyLogicalPartition(partition_name, 0s)) return false;
+ } else {
+ PERROR << "delete partition " << overlay;
+ return false;
+ }
+ errno = save_errno;
+ return true;
+}
+
bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point,
bool* change) {
const auto top = overlay + kOverlayTopDir;
@@ -404,13 +469,16 @@
save_errno = errno;
if (!rmdir(top.c_str())) {
if (change) *change = true;
+ cleanup_all = true;
} else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
ret = false;
PERROR << "rmdir " << top;
} else {
errno = save_errno;
+ cleanup_all = true;
}
}
+ if (cleanup_all) ret &= fs_mgr_overlayfs_teardown_scratch(overlay, change);
return ret;
}
@@ -445,11 +513,16 @@
std::vector<std::string> mounts;
if (!fstab) return mounts;
+ auto verity = fs_mgr_overlayfs_verity_enabled_list();
for (auto i = 0; i < fstab->num_entries; i++) {
const auto fsrec = &fstab->recs[i];
if (!fs_mgr_wants_overlayfs(fsrec)) continue;
- std::string new_mount_point(fs_mgr_mount_point(fstab, fsrec->mount_point));
+ std::string new_mount_point(fs_mgr_mount_point(fsrec->mount_point));
if (mount_point && (new_mount_point != mount_point)) continue;
+ if (std::find(verity.begin(), verity.end(), android::base::Basename(new_mount_point)) !=
+ verity.end()) {
+ continue;
+ }
auto duplicate_or_more_specific = false;
for (auto it = mounts.begin(); it != mounts.end();) {
if ((*it == new_mount_point) ||
@@ -465,19 +538,164 @@
}
if (!duplicate_or_more_specific) mounts.emplace_back(new_mount_point);
}
- // if not itemized /system or /, system as root, fake up
- // fs_mgr_wants_overlayfs evaluation of /system as candidate.
- if ((std::find(mounts.begin(), mounts.end(), "/system") == mounts.end()) &&
- !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/") &&
- !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system") &&
- (!mount_point || ("/system"s == mount_point)) &&
- !fs_mgr_overlayfs_verity_enabled("system")) {
- mounts.emplace_back("/system");
+ // if not itemized /system or /, system as root, fake one up?
+
+ // do we want or need to?
+ if (mount_point && ("/system"s != mount_point)) return mounts;
+ if (std::find(mounts.begin(), mounts.end(), "/system") != mounts.end()) return mounts;
+
+ // fs_mgr_overlayfs_verity_enabled_list says not to?
+ if (std::find(verity.begin(), verity.end(), "system") != verity.end()) return mounts;
+
+ // confirm that fstab is missing system
+ if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/")) {
+ return mounts;
}
+ if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system")) {
+ return mounts;
+ }
+
+ // We have a stunted fstab (w/o system or / ) passed in by the caller,
+ // verity claims are assumed accurate because they are collected internally
+ // from fs_mgr_fstab_default() from within fs_mgr_update_verity_state(),
+ // Can (re)evaluate /system with impunity since we know it is ever-present.
+ mounts.emplace_back("/system");
return mounts;
}
+// Mount kScratchMountPoint
+bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type) {
+ if (setfscreatecon(kOverlayfsFileContext)) {
+ PERROR << "setfscreatecon " << kOverlayfsFileContext;
+ }
+ if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) {
+ PERROR << "create " << kScratchMountPoint;
+ }
+
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> local_fstab(
+ static_cast<fstab*>(calloc(1, sizeof(fstab))), fs_mgr_free_fstab);
+ auto fsrec = static_cast<fstab_rec*>(calloc(1, sizeof(fstab_rec)));
+ local_fstab->num_entries = 1;
+ local_fstab->recs = fsrec;
+ fsrec->blk_device = strdup(device_path.c_str());
+ fsrec->mount_point = strdup(kScratchMountPoint.c_str());
+ fsrec->fs_type = strdup(mnt_type.c_str());
+ fsrec->flags = MS_RELATIME;
+ fsrec->fs_options = strdup("");
+ auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
+ auto save_errno = errno;
+ setfscreatecon(nullptr);
+ if (!mounted) rmdir(kScratchMountPoint.c_str());
+ errno = save_errno;
+ return mounted;
+}
+
+const std::string kMkF2fs("/system/bin/make_f2fs");
+const std::string kMkExt4("/system/bin/mke2fs");
+
+std::string fs_mgr_overlayfs_scratch_mount_type() {
+ if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
+ if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
+ return "auto";
+}
+
+std::string fs_mgr_overlayfs_scratch_device() {
+ if (!scratch_device_cache.empty()) return scratch_device_cache;
+
+ auto& dm = DeviceMapper::Instance();
+ const auto partition_name = android::base::Basename(kScratchMountPoint);
+ std::string path;
+ if (!dm.GetDmDevicePathByName(partition_name, &path)) return "";
+ return scratch_device_cache = path;
+}
+
+// Create and mount kScratchMountPoint storage if we have logical partitions
+bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) {
+ if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
+ auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
+ auto scratch_device = fs_mgr_overlayfs_scratch_device();
+ auto partition_exists = fs_mgr_rw_access(scratch_device);
+ if (!partition_exists) {
+ auto slot_number = fs_mgr_overlayfs_slot_number();
+ auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+ if (!fs_mgr_rw_access(super_device)) return false;
+ if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+ auto builder = MetadataBuilder::New(super_device, slot_number);
+ if (!builder) {
+ PERROR << "open " << super_device << " metadata";
+ return false;
+ }
+ const auto partition_name = android::base::Basename(kScratchMountPoint);
+ partition_exists = builder->FindPartition(partition_name) != nullptr;
+ if (!partition_exists) {
+ auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+ if (!partition) {
+ PERROR << "create " << partition_name;
+ return false;
+ }
+ auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
+ // 512MB or half the remaining available space, whichever is greater.
+ partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
+ if (!builder->ResizePartition(partition, partition_size)) {
+ PERROR << "resize " << partition_name;
+ return false;
+ }
+
+ auto metadata = builder->Export();
+ if (!metadata) {
+ LERROR << "generate new metadata " << partition_name;
+ return false;
+ }
+ if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+ LERROR << "update " << partition_name;
+ return false;
+ }
+
+ if (change) *change = true;
+ }
+
+ if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+ &scratch_device))
+ return false;
+ }
+
+ if (partition_exists) {
+ if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) {
+ if (change) *change = true;
+ return true;
+ }
+ // partition existed, but was not initialized;
+ errno = 0;
+ }
+
+ auto ret = system((mnt_type == "f2fs")
+ ? ((kMkF2fs + " -d1 " + scratch_device).c_str())
+ : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M "s + kScratchMountPoint +
+ " -O has_journal " + scratch_device)
+ .c_str()));
+ if (ret) {
+ LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " error=" << ret;
+ return false;
+ }
+
+ if (change) *change = true;
+
+ return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type);
+}
+
+bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device) {
+ if (scratch_device.empty()) return false;
+ if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return false;
+ if (fs_mgr_rw_access(scratch_device)) return true;
+ auto slot_number = fs_mgr_overlayfs_slot_number();
+ auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+ if (!fs_mgr_rw_access(super_device)) return false;
+ auto builder = MetadataBuilder::New(super_device, slot_number);
+ if (!builder) return false;
+ return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr;
+}
+
} // namespace
bool fs_mgr_overlayfs_mount_all(const fstab* fstab) {
@@ -487,14 +705,37 @@
if (!fstab) return ret;
+ auto scratch_can_be_mounted = true;
for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+ if (scratch_can_be_mounted) {
+ scratch_can_be_mounted = false;
+ auto scratch_device = fs_mgr_overlayfs_scratch_device();
+ if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) &&
+ fs_mgr_wait_for_file(scratch_device, 10s) &&
+ fs_mgr_overlayfs_mount_scratch(scratch_device,
+ fs_mgr_overlayfs_scratch_mount_type()) &&
+ !fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) {
+ umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+ rmdir(kScratchMountPoint.c_str());
+ }
+ }
if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
}
return ret;
}
-std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) {
+std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab) {
+ if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
+ return {};
+ }
+
+ for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
+ if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+ auto device = fs_mgr_overlayfs_scratch_device();
+ if (!fs_mgr_overlayfs_scratch_can_be_mounted(device)) break;
+ return {device};
+ }
return {};
}
@@ -503,10 +744,6 @@
bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
if (change) *change = false;
auto ret = false;
- if (backing && (kOverlayMountPoint != backing)) {
- errno = EINVAL;
- return ret;
- }
if (!fs_mgr_wants_overlayfs()) return ret;
if (!fs_mgr_boot_completed()) {
errno = EBUSY;
@@ -516,16 +753,32 @@
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
- if (fstab && !fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret;
- auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(fstab.get(), mount_point));
- if (fstab && mounts.empty()) return ret;
+ if (!fstab) return ret;
+ auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(mount_point));
+ if (mounts.empty()) return ret;
+
+ std::string dir;
+ for (const auto& overlay_mount_point : kOverlayMountPoints) {
+ if (backing && backing[0] && (overlay_mount_point != backing)) continue;
+ if (overlay_mount_point == kScratchMountPoint) {
+ if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) ||
+ !fs_mgr_overlayfs_has_logical(fstab.get())) {
+ continue;
+ }
+ if (!fs_mgr_overlayfs_setup_scratch(fstab.get(), change)) continue;
+ } else {
+ if (!fs_mgr_get_entry_for_mount_point(fstab.get(), overlay_mount_point)) continue;
+ }
+ dir = overlay_mount_point;
+ break;
+ }
+ if (dir.empty()) {
+ errno = ESRCH;
+ return ret;
+ }
std::string overlay;
- ret |= fs_mgr_overlayfs_setup_dir(kOverlayMountPoint, &overlay, change);
-
- if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) {
- ret = true;
- }
+ ret |= fs_mgr_overlayfs_setup_dir(dir, &overlay, change);
for (const auto& fsrec_mount_point : mounts) {
ret |= fs_mgr_overlayfs_setup_one(overlay, fsrec_mount_point, change);
}
@@ -536,11 +789,11 @@
// If something is altered, set *change.
bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) {
if (change) *change = false;
- mount_point = fs_mgr_mount_point(std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>(
- fs_mgr_read_fstab_default(), fs_mgr_free_fstab)
- .get(),
- mount_point);
- auto ret = fs_mgr_overlayfs_teardown_one(kOverlayMountPoint, mount_point ?: "", change);
+ mount_point = fs_mgr_mount_point(mount_point);
+ auto ret = true;
+ for (const auto& overlay_mount_point : kOverlayMountPoints) {
+ ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
+ }
if (!fs_mgr_wants_overlayfs()) {
// After obligatory teardown to make sure everything is clean, but if
// we didn't want overlayfs in the the first place, we do not want to
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 506e81d..5e83cfb 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -128,10 +128,10 @@
FileWaitMode wait_mode = FileWaitMode::Exists);
int fs_mgr_set_blk_ro(const char* blockdev);
-bool fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_update_for_slotselect(fstab* fstab);
bool fs_mgr_is_device_unlocked();
const std::string& get_android_dt_dir();
bool is_dt_compatible();
-int load_verity_state(struct fstab_rec* fstab, int* mode);
+int load_verity_state(fstab_rec* fstab, int* mode);
#endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a4544b2..5dabe76 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -51,8 +51,8 @@
};
// Callback function for verity status
-typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* mount_point,
- int mode, int status);
+typedef void fs_mgr_verity_state_callback(fstab_rec* fstab, const char* mount_point, int mode,
+ int status);
#define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
@@ -63,32 +63,31 @@
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
-int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
+int fs_mgr_mount_all(fstab* fstab, int mount_mode);
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
#define FS_MGR_DOMNT_SUCCESS 0
-int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
- char *tmp_mount_point);
-int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device,
- char* tmp_mount_point, bool need_cp);
-int fs_mgr_do_mount_one(struct fstab_rec *rec);
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
+ bool need_cp);
+int fs_mgr_do_mount_one(fstab_rec* rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
-struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
-void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
+fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
+void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
bool fs_mgr_load_verity_state(int* mode);
bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback);
int fs_mgr_swapon_all(struct fstab *fstab);
bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
-int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
+int fs_mgr_do_format(fstab_rec* fstab, bool reserve_footer);
#define FS_MGR_SETUP_VERITY_SKIPPED (-3)
#define FS_MGR_SETUP_VERITY_DISABLED (-2)
#define FS_MGR_SETUP_VERITY_FAIL (-1)
#define FS_MGR_SETUP_VERITY_SUCCESS 0
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
+int fs_mgr_setup_verity(fstab_rec* fstab, bool wait_for_verity_dev);
// Return the name of the super partition if it exists. If a slot number is
// specified, the super partition for the corresponding metadata slot will be
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 69dc065..bbdec5b 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -51,6 +51,7 @@
"liblp",
"libbase",
"libfs_mgr",
+ "libsparse",
],
srcs: [
"builder_test.cpp",
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 97b15bd..03fd5f9 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -150,7 +150,7 @@
}
BlockDeviceInfo device_info;
if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) {
- builder->set_block_device_info(device_info);
+ builder->UpdateBlockDeviceInfo(device_info);
}
return builder;
}
@@ -217,10 +217,6 @@
}
}
}
-
- device_info_.alignment = geometry_.alignment;
- device_info_.alignment_offset = geometry_.alignment_offset;
- device_info_.logical_block_size = geometry_.logical_block_size;
return true;
}
@@ -239,24 +235,23 @@
metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
// Check that device properties are sane.
- device_info_ = device_info;
- if (device_info_.size % LP_SECTOR_SIZE != 0) {
+ if (device_info.size % LP_SECTOR_SIZE != 0) {
LERROR << "Block device size must be a multiple of 512.";
return false;
}
- if (device_info_.logical_block_size % LP_SECTOR_SIZE != 0) {
+ if (device_info.logical_block_size % LP_SECTOR_SIZE != 0) {
LERROR << "Logical block size must be a multiple of 512.";
return false;
}
- if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) {
+ if (device_info.alignment_offset % LP_SECTOR_SIZE != 0) {
LERROR << "Alignment offset is not sector-aligned.";
return false;
}
- if (device_info_.alignment % LP_SECTOR_SIZE != 0) {
+ if (device_info.alignment % LP_SECTOR_SIZE != 0) {
LERROR << "Partition alignment is not sector-aligned.";
return false;
}
- if (device_info_.alignment_offset > device_info_.alignment) {
+ if (device_info.alignment_offset > device_info.alignment) {
LERROR << "Partition alignment offset is greater than its alignment.";
return false;
}
@@ -267,49 +262,30 @@
uint64_t reserved =
LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
uint64_t total_reserved = reserved * 2;
- if (device_info_.size < total_reserved) {
+ if (device_info.size < total_reserved) {
LERROR << "Attempting to create metadata on a block device that is too small.";
return false;
}
// Compute the first free sector, factoring in alignment.
- uint64_t free_area = AlignTo(reserved, device_info_.alignment, device_info_.alignment_offset);
- uint64_t first_sector = free_area / LP_SECTOR_SIZE;
+ uint64_t free_area_start =
+ AlignTo(total_reserved, device_info.alignment, device_info.alignment_offset);
+ uint64_t first_sector = free_area_start / LP_SECTOR_SIZE;
- // Compute the last free sector, which is inclusive. We subtract 1 to make
- // sure that logical partitions won't overlap with the same sector as the
- // backup metadata, which could happen if the block device was not aligned
- // to LP_SECTOR_SIZE.
- uint64_t last_sector = ((device_info_.size - reserved) / LP_SECTOR_SIZE) - 1;
-
- // If this check fails, it means either (1) we did not have free space to
- // allocate a single sector, or (2) we did, but the alignment was high
- // enough to bump the first sector out of range. Either way, we cannot
- // continue.
- if (first_sector > last_sector) {
- LERROR << "Not enough space to allocate any partition tables.";
+ // There must be one logical block of free space remaining (enough for one partition).
+ uint64_t minimum_disk_size = (first_sector * LP_SECTOR_SIZE) + device_info.logical_block_size;
+ if (device_info.size < minimum_disk_size) {
+ LERROR << "Device must be at least " << minimum_disk_size << " bytes, only has "
+ << device_info.size;
return false;
}
- // Finally, the size of the allocatable space must be a multiple of the
- // logical block size. If we have no more free space after this
- // computation, then we abort. Note that the last sector is inclusive,
- // so we have to account for that.
- uint64_t num_free_sectors = last_sector - first_sector + 1;
- uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
- if (num_free_sectors < sectors_per_block) {
- LERROR << "Not enough space to allocate any partition tables.";
- return false;
- }
- last_sector = first_sector + (num_free_sectors / sectors_per_block) * sectors_per_block - 1;
-
geometry_.first_logical_sector = first_sector;
- geometry_.last_logical_sector = last_sector;
geometry_.metadata_max_size = metadata_max_size;
geometry_.metadata_slot_count = metadata_slot_count;
- geometry_.alignment = device_info_.alignment;
- geometry_.alignment_offset = device_info_.alignment_offset;
- geometry_.block_device_size = device_info_.size;
+ geometry_.alignment = device_info.alignment;
+ geometry_.alignment_offset = device_info.alignment_offset;
+ geometry_.block_device_size = device_info.size;
geometry_.logical_block_size = device_info.logical_block_size;
if (!AddGroup("default", 0)) {
@@ -456,11 +432,13 @@
uint64_t last_free_extent_start =
extents.empty() ? geometry_.first_logical_sector : extents.back().end;
last_free_extent_start = AlignSector(last_free_extent_start);
- if (last_free_extent_start <= geometry_.last_logical_sector) {
- free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
+
+ uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE;
+ if (last_free_extent_start < last_sector) {
+ free_regions.emplace_back(last_free_extent_start, last_sector);
}
- const uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
+ const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
CHECK_NE(sectors_per_block, 0);
CHECK(sectors_needed % sectors_per_block == 0);
@@ -527,6 +505,7 @@
strncpy(out.name, group->name().c_str(), sizeof(out.name));
out.maximum_size = group->maximum_size();
+ group_indices[group->name()] = metadata->groups.size();
metadata->groups.push_back(out);
}
@@ -550,6 +529,14 @@
part.num_extents = static_cast<uint32_t>(partition->extents().size());
part.attributes = partition->attributes();
+ auto iter = group_indices.find(partition->group_name());
+ if (iter == group_indices.end()) {
+ LERROR << "Partition " << partition->name() << " is a member of unknown group "
+ << partition->group_name();
+ return nullptr;
+ }
+ part.group_index = iter->second;
+
for (const auto& extent : partition->extents()) {
extent->AddTo(metadata.get());
}
@@ -563,7 +550,7 @@
}
uint64_t MetadataBuilder::AllocatableSpace() const {
- return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE;
+ return geometry_.block_device_size - (geometry_.first_logical_sector * LP_SECTOR_SIZE);
}
uint64_t MetadataBuilder::UsedSpace() const {
@@ -578,32 +565,44 @@
// Note: when reading alignment info from the Kernel, we don't assume it
// is aligned to the sector size, so we round up to the nearest sector.
uint64_t lba = sector * LP_SECTOR_SIZE;
- uint64_t aligned = AlignTo(lba, device_info_.alignment, device_info_.alignment_offset);
+ uint64_t aligned = AlignTo(lba, geometry_.alignment, geometry_.alignment_offset);
return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
}
-void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
- device_info_.size = device_info.size;
+bool MetadataBuilder::GetBlockDeviceInfo(BlockDeviceInfo* info) const {
+ info->size = geometry_.block_device_size;
+ info->alignment = geometry_.alignment;
+ info->alignment_offset = geometry_.alignment_offset;
+ info->logical_block_size = geometry_.logical_block_size;
+ return true;
+}
- // Note that if the logical block size changes, we're probably in trouble:
- // we could have already built extents that will only work on the previous
- // size.
- DCHECK(partitions_.empty() ||
- device_info_.logical_block_size == device_info.logical_block_size);
+bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) {
+ if (device_info.size != geometry_.block_device_size) {
+ LERROR << "Device size does not match (got " << device_info.size << ", expected "
+ << geometry_.block_device_size << ")";
+ return false;
+ }
+ if (device_info.logical_block_size != geometry_.logical_block_size) {
+ LERROR << "Device logical block size does not match (got " << device_info.logical_block_size
+ << ", expected " << geometry_.logical_block_size << ")";
+ return false;
+ }
// The kernel does not guarantee these values are present, so we only
// replace existing values if the new values are non-zero.
if (device_info.alignment) {
- device_info_.alignment = device_info.alignment;
+ geometry_.alignment = device_info.alignment;
}
if (device_info.alignment_offset) {
- device_info_.alignment_offset = device_info.alignment_offset;
+ geometry_.alignment_offset = device_info.alignment_offset;
}
+ return true;
}
bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
// Align the space needed up to the nearest sector.
- uint64_t aligned_size = AlignTo(requested_size, device_info_.logical_block_size);
+ uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
uint64_t old_size = partition->size();
if (aligned_size > old_size) {
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index c916b44..eb65f89 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -48,8 +48,8 @@
LinearExtent* extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE);
- // The first logical sector will be (4096+1024*2)/512 = 12.
- EXPECT_EQ(extent->physical_sector(), 12);
+ // The first logical sector will be (8192+1024*4)/512 = 12.
+ EXPECT_EQ(extent->physical_sector(), 24);
// Test resizing to the same size.
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -78,7 +78,7 @@
extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(extent->physical_sector(), 12);
+ EXPECT_EQ(extent->physical_sector(), 24);
// Test shrinking to 0.
builder->ResizePartition(system, 0);
@@ -127,7 +127,6 @@
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
// Test a large alignment offset thrown in.
device_info.alignment_offset = 753664;
@@ -136,7 +135,6 @@
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
// Alignment offset without alignment doesn't mean anything.
device_info.alignment = 0;
@@ -150,8 +148,7 @@
ASSERT_NE(builder, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
- EXPECT_EQ(exported->geometry.first_logical_sector, 78);
- EXPECT_EQ(exported->geometry.last_logical_sector, 1973);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 150);
// Test a small alignment with no alignment offset.
device_info.alignment = 11 * 1024;
@@ -159,8 +156,7 @@
ASSERT_NE(builder, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
- EXPECT_EQ(exported->geometry.first_logical_sector, 72);
- EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 160);
}
TEST(liblp, InternalPartitionAlignment) {
@@ -247,11 +243,11 @@
ASSERT_NE(system2, nullptr);
ASSERT_NE(vendor1, nullptr);
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
- EXPECT_EQ(system1->physical_sector(), 12);
+ EXPECT_EQ(system1->physical_sector(), 24);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(system2->physical_sector(), 204);
+ EXPECT_EQ(system2->physical_sector(), 216);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(vendor1->physical_sector(), 140);
+ EXPECT_EQ(vendor1->physical_sector(), 152);
EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector());
EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
}
@@ -297,13 +293,10 @@
EXPECT_EQ(geometry.struct_size, sizeof(geometry));
EXPECT_EQ(geometry.metadata_max_size, 1024);
EXPECT_EQ(geometry.metadata_slot_count, 2);
- EXPECT_EQ(geometry.first_logical_sector, 12);
- EXPECT_EQ(geometry.last_logical_sector, 2035);
+ EXPECT_EQ(geometry.first_logical_sector, 24);
static const size_t kMetadataSpace =
- (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE;
- uint64_t space_at_end = kDiskSize - (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE;
- EXPECT_GE(space_at_end, kMetadataSpace);
+ ((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace);
// Verify header.
@@ -361,9 +354,9 @@
LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
- EXPECT_EQ(system1->physical_sector(), 12);
+ EXPECT_EQ(system1->physical_sector(), 24);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(system2->physical_sector(), 204);
+ EXPECT_EQ(system2->physical_sector(), 216);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
}
@@ -437,22 +430,37 @@
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
- EXPECT_EQ(builder->block_device_info().size, device_info.size);
- EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment);
- EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
- EXPECT_EQ(builder->block_device_info().logical_block_size, device_info.logical_block_size);
+ BlockDeviceInfo new_info;
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+
+ EXPECT_EQ(new_info.size, device_info.size);
+ EXPECT_EQ(new_info.alignment, device_info.alignment);
+ EXPECT_EQ(new_info.alignment_offset, device_info.alignment_offset);
+ EXPECT_EQ(new_info.logical_block_size, device_info.logical_block_size);
device_info.alignment = 0;
device_info.alignment_offset = 2048;
- builder->set_block_device_info(device_info);
- EXPECT_EQ(builder->block_device_info().alignment, 4096);
- EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
+ ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.alignment, 4096);
+ EXPECT_EQ(new_info.alignment_offset, device_info.alignment_offset);
device_info.alignment = 8192;
device_info.alignment_offset = 0;
- builder->set_block_device_info(device_info);
- EXPECT_EQ(builder->block_device_info().alignment, 8192);
- EXPECT_EQ(builder->block_device_info().alignment_offset, 2048);
+ ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.alignment, 8192);
+ EXPECT_EQ(new_info.alignment_offset, 2048);
+
+ new_info.size += 4096;
+ ASSERT_FALSE(builder->UpdateBlockDeviceInfo(new_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.size, 1024 * 1024);
+
+ new_info.logical_block_size = 512;
+ ASSERT_FALSE(builder->UpdateBlockDeviceInfo(new_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.logical_block_size, 4096);
}
TEST(liblp, InvalidBlockSize) {
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 742b1d0..8716988 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -19,8 +19,6 @@
#include <limits.h>
#include <android-base/file.h>
-#include <android-base/unique_fd.h>
-#include <sparse/sparse.h>
#include "reader.h"
#include "utility.h"
@@ -89,41 +87,36 @@
return WriteToImageFile(fd, input);
}
-// We use an object to build the sparse file since it requires that data
-// pointers be held alive until the sparse file is destroyed. It's easier
-// to do this when the data pointers are all in one place.
-class SparseBuilder {
- public:
- SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images);
-
- bool Build();
- bool Export(const char* file);
- bool IsValid() const { return file_ != nullptr; }
-
- private:
- bool AddData(const std::string& blob, uint64_t sector);
- bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
- int OpenImageFile(const std::string& file);
- bool SectorToBlock(uint64_t sector, uint32_t* block);
-
- const LpMetadata& metadata_;
- const LpMetadataGeometry& geometry_;
- uint32_t block_size_;
- std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
- std::string primary_blob_;
- std::string backup_blob_;
- std::map<std::string, std::string> images_;
- std::vector<android::base::unique_fd> temp_fds_;
-};
-
SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
const std::map<std::string, std::string>& images)
: metadata_(metadata),
geometry_(metadata.geometry),
block_size_(block_size),
- file_(sparse_file_new(block_size_, geometry_.block_device_size), sparse_file_destroy),
- images_(images) {}
+ file_(nullptr, sparse_file_destroy),
+ images_(images) {
+ if (block_size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
+ return;
+ }
+ if (metadata.geometry.block_device_size % block_size != 0) {
+ LERROR << "Device size must be a multiple of the block size, " << block_size;
+ return;
+ }
+ if (metadata.geometry.metadata_max_size % block_size != 0) {
+ LERROR << "Metadata max size must be a multiple of the block size, " << block_size;
+ return;
+ }
+
+ uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
+ if (num_blocks >= UINT_MAX) {
+ // libsparse counts blocks in unsigned 32-bit integers, so we check to
+ // make sure we're not going to overflow.
+ LERROR << "Block device is too large to encode with libsparse.";
+ return;
+ }
+
+ file_.reset(sparse_file_new(block_size_, geometry_.block_device_size));
+}
bool SparseBuilder::Export(const char* file) {
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
@@ -174,16 +167,12 @@
std::string metadata_blob = SerializeMetadata(metadata_);
metadata_blob.resize(geometry_.metadata_max_size);
- std::string all_metadata;
- for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
- all_metadata += metadata_blob;
+ // Two copies of geometry, then two copies of each metadata slot.
+ all_metadata_ += geometry_blob + geometry_blob;
+ for (size_t i = 0; i < geometry_.metadata_slot_count * 2; i++) {
+ all_metadata_ += metadata_blob;
}
-
- // Metadata immediately follows geometry, and we write the same metadata
- // to all slots. Note that we don't bother trying to write skip chunks
- // here since it's a small amount of data.
- primary_blob_ = geometry_blob + all_metadata;
- if (!AddData(primary_blob_, 0)) {
+ if (!AddData(all_metadata_, 0)) {
return false;
}
@@ -202,17 +191,6 @@
LERROR << "Partition image was specified but no partition was found.";
return false;
}
-
- // The backup area contains all metadata slots, and then geometry. Similar
- // to before we write the metadata to every slot.
- int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
- uint64_t backups_start = geometry_.block_device_size + backup_offset;
- uint64_t backup_sector = backups_start / LP_SECTOR_SIZE;
-
- backup_blob_ = all_metadata + geometry_blob;
- if (!AddData(backup_blob_, backup_sector)) {
- return false;
- }
return true;
}
@@ -336,22 +314,6 @@
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
const std::map<std::string, std::string>& images) {
- if (block_size % LP_SECTOR_SIZE != 0) {
- LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
- return false;
- }
- if (metadata.geometry.block_device_size % block_size != 0) {
- LERROR << "Device size must be a multiple of the block size, " << block_size;
- return false;
- }
- uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
- if (num_blocks >= UINT_MAX) {
- // libsparse counts blocks in unsigned 32-bit integers, so we check to
- // make sure we're not going to overflow.
- LERROR << "Block device is too large to encode with libsparse.";
- return false;
- }
-
SparseBuilder builder(metadata, block_size, images);
if (!builder.IsValid()) {
LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
index 3a999b8..a9ef8ce 100644
--- a/fs_mgr/liblp/images.h
+++ b/fs_mgr/liblp/images.h
@@ -14,7 +14,14 @@
* limitations under the License.
*/
+#include <stdint.h>
+#include <map>
+#include <memory>
+#include <string>
+
+#include <android-base/unique_fd.h>
#include <liblp/liblp.h>
+#include <sparse/sparse.h>
namespace android {
namespace fs_mgr {
@@ -25,5 +32,34 @@
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
bool WriteToImageFile(int fd, const LpMetadata& metadata);
+// We use an object to build the sparse file since it requires that data
+// pointers be held alive until the sparse file is destroyed. It's easier
+// to do this when the data pointers are all in one place.
+class SparseBuilder {
+ public:
+ SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images);
+
+ bool Build();
+ bool Export(const char* file);
+ bool IsValid() const { return file_ != nullptr; }
+
+ sparse_file* file() const { return file_.get(); }
+
+ private:
+ bool AddData(const std::string& blob, uint64_t sector);
+ bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
+ int OpenImageFile(const std::string& file);
+ bool SectorToBlock(uint64_t sector, uint32_t* block);
+
+ const LpMetadata& metadata_;
+ const LpMetadataGeometry& geometry_;
+ uint32_t block_size_;
+ std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
+ std::string all_metadata_;
+ std::map<std::string, std::string> images_;
+ std::vector<android::base::unique_fd> temp_fds_;
+};
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index a6044d0..8dbba84 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -215,10 +215,8 @@
uint64_t AllocatableSpace() const;
uint64_t UsedSpace() const;
- // Merge new block device information into previous values. Alignment values
- // are only overwritten if the new values are non-zero.
- void set_block_device_info(const BlockDeviceInfo& device_info);
- const BlockDeviceInfo& block_device_info() const { return device_info_; }
+ bool GetBlockDeviceInfo(BlockDeviceInfo* info) const;
+ bool UpdateBlockDeviceInfo(const BlockDeviceInfo& info);
private:
MetadataBuilder();
@@ -238,7 +236,6 @@
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
std::vector<std::unique_ptr<PartitionGroup>> groups_;
- BlockDeviceInfo device_info_;
};
// Read BlockDeviceInfo for a given block device. This always returns false
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 7d1a2a9..711ff95 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 3
+#define LP_METADATA_MAJOR_VERSION 5
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -58,13 +58,13 @@
* +--------------------+
* | Disk Geometry |
* +--------------------+
- * | Metadata |
+ * | Geometry Backup |
* +--------------------+
- * | Logical Partitions |
+ * | Metadata |
* +--------------------+
* | Backup Metadata |
* +--------------------+
- * | Geometry Backup |
+ * | Logical Partitions |
* +--------------------+
*/
#define LP_METADATA_DEFAULT_PARTITION_NAME "super"
@@ -72,8 +72,8 @@
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512
-/* This structure is stored at sector 0 in the first 4096 bytes of the
- * partition, and again in the very last 4096 bytes. It is never modified and
+/* This structure is stored at block 0 in the first 4096 bytes of the
+ * partition, and again in the following block. It is never modified and
* describes how logical partition information can be located.
*/
typedef struct LpMetadataGeometry {
@@ -99,17 +99,11 @@
uint32_t metadata_slot_count;
/* 48: First usable sector for allocating logical partitions. this will be
- * the first sector after the initial 4096 geometry block, followed by the
- * space consumed by metadata_max_size*metadata_slot_count.
+ * the first sector after the initial geometry blocks, followed by the
+ * space consumed by metadata_max_size*metadata_slot_count*2.
*/
uint64_t first_logical_sector;
- /* 56: Last usable sector, inclusive, for allocating logical partitions.
- * At the end of this sector will follow backup metadata slots and the
- * backup geometry block at the very end.
- */
- uint64_t last_logical_sector;
-
/* 64: Alignment for defining partitions or partition extents. For example,
* an alignment of 1MiB will require that all partitions have a size evenly
* divisible by 1MiB, and that the smallest unit the partition can grow by
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 01de3ac..92696f5 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -161,7 +161,6 @@
EXPECT_EQ(exported->geometry.metadata_max_size, imported->geometry.metadata_max_size);
EXPECT_EQ(exported->geometry.metadata_slot_count, imported->geometry.metadata_slot_count);
EXPECT_EQ(exported->geometry.first_logical_sector, imported->geometry.first_logical_sector);
- EXPECT_EQ(exported->geometry.last_logical_sector, imported->geometry.last_logical_sector);
EXPECT_EQ(exported->header.major_version, imported->header.major_version);
EXPECT_EQ(exported->header.minor_version, imported->header.minor_version);
EXPECT_EQ(exported->header.header_size, imported->header.header_size);
@@ -207,13 +206,14 @@
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
+ uint64_t last_sector = imported->geometry.block_device_size / LP_SECTOR_SIZE;
+
// Verify that we didn't overwrite anything in the logical paritition area.
// We expect the disk to be filled with 0xcc on creation so we can read
// this back and compare it.
char expected[LP_SECTOR_SIZE];
memset(expected, 0xcc, sizeof(expected));
- for (uint64_t i = imported->geometry.first_logical_sector;
- i <= imported->geometry.last_logical_sector; i++) {
+ for (uint64_t i = imported->geometry.first_logical_sector; i < last_sector; i++) {
char buffer[LP_SECTOR_SIZE];
ASSERT_GE(lseek(fd, i * LP_SECTOR_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
@@ -261,8 +261,6 @@
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
- imported->geometry.last_logical_sector--;
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
}
// Test that changing one bit of metadata is enough to break the checksum.
@@ -290,13 +288,13 @@
char corruption[LP_METADATA_GEOMETRY_SIZE];
memset(corruption, 0xff, sizeof(corruption));
- // Corrupt the first 4096 bytes of the disk.
- ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
+ // Corrupt the primary geometry.
+ ASSERT_GE(lseek(fd, GetPrimaryGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
- // Corrupt the last 4096 bytes too.
- ASSERT_GE(lseek(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END), 0);
+ // Corrupt the backup geometry.
+ ASSERT_GE(lseek(fd, GetBackupGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}
@@ -310,14 +308,16 @@
char corruption[kMetadataSize];
memset(corruption, 0xff, sizeof(corruption));
- ASSERT_GE(lseek(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET), 0);
+ off_t offset = GetPrimaryMetadataOffset(metadata->geometry, 0);
+
+ ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
- off_t offset = LP_METADATA_GEOMETRY_SIZE + kMetadataSize * 2;
+ offset = GetBackupMetadataOffset(metadata->geometry, 0);
// Corrupt the backup metadata.
- ASSERT_GE(lseek(fd, -offset, SEEK_END), 0);
+ ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}
@@ -368,9 +368,6 @@
ASSERT_GE(lseek(fd, exported->geometry.first_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
- ASSERT_GE(lseek(fd, exported->geometry.last_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
- ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
- EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
}
// Test that we can read and write image files.
@@ -535,3 +532,36 @@
ASSERT_GE(new_table->partitions.size(), 1);
ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
}
+
+// Test that writing a sparse image can be read back.
+TEST(liblp, FlashSparseImage) {
+ unique_fd fd = CreateFakeDisk();
+ ASSERT_GE(fd, 0);
+
+ BlockDeviceInfo device_info(kDiskSize, 0, 0, 512);
+ unique_ptr<MetadataBuilder> builder =
+ MetadataBuilder::New(device_info, kMetadataSize, kMetadataSlots);
+ ASSERT_NE(builder, nullptr);
+ ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+
+ unique_ptr<LpMetadata> exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+
+ // Build the sparse file.
+ SparseBuilder sparse(*exported.get(), 512, {});
+ ASSERT_TRUE(sparse.IsValid());
+ sparse_file_verbose(sparse.file());
+ ASSERT_TRUE(sparse.Build());
+
+ // Write it to the fake disk.
+ ASSERT_NE(lseek(fd.get(), 0, SEEK_SET), -1);
+ int ret = sparse_file_write(sparse.file(), fd.get(), false, false, false);
+ ASSERT_EQ(ret, 0);
+
+ // Verify that we can read both sets of metadata.
+ LpMetadataGeometry geometry;
+ ASSERT_TRUE(ReadPrimaryGeometry(fd.get(), &geometry));
+ ASSERT_TRUE(ReadBackupGeometry(fd.get(), &geometry));
+ ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
+ ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 005d493..835df9b 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -120,13 +120,9 @@
return true;
}
-// Read and validate geometry information from a block device that holds
-// logical partitions. If the information is corrupted, this will attempt
-// to read it from a secondary backup location.
-bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) {
- // Read the first 4096 bytes.
+bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
- if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed";
return false;
}
@@ -134,12 +130,12 @@
PERROR << __PRETTY_FUNCTION__ << "read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
return false;
}
- if (ParseGeometry(buffer.get(), geometry)) {
- return true;
- }
+ return ParseGeometry(buffer.get(), geometry);
+}
- // Try the backup copy in the last 4096 bytes.
- if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) {
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
+ if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed, offset " << -LP_METADATA_GEOMETRY_SIZE;
return false;
}
@@ -151,6 +147,16 @@
return ParseGeometry(buffer.get(), geometry);
}
+// Read and validate geometry information from a block device that holds
+// logical partitions. If the information is corrupted, this will attempt
+// to read it from a secondary backup location.
+bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) {
+ if (ReadPrimaryGeometry(fd, geometry)) {
+ return true;
+ }
+ return ReadBackupGeometry(fd, geometry);
+}
+
static bool ValidateTableBounds(const LpMetadataHeader& header,
const LpMetadataTableDescriptor& table) {
if (table.offset > header.tables_size) {
@@ -315,7 +321,7 @@
std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
uint32_t slot_number) {
int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
- if (SeekFile64(fd, offset, SEEK_END) < 0) {
+ if (SeekFile64(fd, offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
}
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index 9f6ca6e..24b2611 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -36,6 +36,8 @@
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
size_t size);
bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
+bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry);
+bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry);
// These functions assume a valid geometry and slot number.
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index b08f96c..2f7692f 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -56,10 +56,18 @@
return lseek(fd, offset, whence);
}
+int64_t GetPrimaryGeometryOffset() {
+ return 0;
+}
+
+int64_t GetBackupGeometryOffset() {
+ return LP_METADATA_GEOMETRY_SIZE;
+}
+
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
- int64_t offset = LP_METADATA_GEOMETRY_SIZE + geometry.metadata_max_size * slot_number;
+ int64_t offset = (LP_METADATA_GEOMETRY_SIZE * 2) + geometry.metadata_max_size * slot_number;
CHECK(offset + geometry.metadata_max_size <=
int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE));
return offset;
@@ -67,7 +75,7 @@
int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
- int64_t start = int64_t(-LP_METADATA_GEOMETRY_SIZE) -
+ int64_t start = LP_METADATA_GEOMETRY_SIZE * 2 +
int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
return start + int64_t(geometry.metadata_max_size * slot_number);
}
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 6ef5124..61e7d31 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -38,6 +38,10 @@
// error. After calling this, the position of |fd| may have changed.
bool GetDescriptorSize(int fd, uint64_t* size);
+// Return the offset of the primary or backup geometry.
+int64_t GetPrimaryGeometryOffset();
+int64_t GetBackupGeometryOffset();
+
// Return the offset of a primary metadata slot, relative to the start of the
// device.
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number);
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 7bf42ae..46ed2e6 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -37,20 +37,21 @@
16384,
4,
10000,
- 80000,
0,
0,
1024 * 1024,
4096};
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 4096 + 16384 * 3);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 8192);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 8192 + 16384);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 8192 + 16384 * 2);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 8192 + 16384 * 3);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), -4096 - 16384 * 1);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), -4096 - 16384 * 2);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), -4096 - 16384 * 3);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), -4096 - 16384 * 4);
+ static const uint64_t backup_start = 8192 + 16384 * 4;
+
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), backup_start + 16384 * 3);
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), backup_start + 16384 * 2);
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), backup_start + 16384 * 1);
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), backup_start + 16384 * 0);
}
TEST(liblp, AlignTo) {
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 2415629..5cf1a2c 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -43,8 +43,9 @@
static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
return g1.metadata_max_size == g2.metadata_max_size &&
g1.metadata_slot_count == g2.metadata_slot_count &&
- g1.first_logical_sector == g2.first_logical_sector &&
- g1.last_logical_sector == g2.last_logical_sector;
+ g1.block_device_size == g2.block_device_size &&
+ g1.logical_block_size == g2.logical_block_size &&
+ g1.first_logical_sector == g2.first_logical_sector;
}
std::string SerializeMetadata(const LpMetadata& input) {
@@ -86,15 +87,11 @@
return false;
}
- *blob = SerializeMetadata(metadata);
-
const LpMetadataHeader& header = metadata.header;
const LpMetadataGeometry& geometry = metadata.geometry;
- // Validate the usable sector range.
- if (geometry.first_logical_sector > geometry.last_logical_sector) {
- LERROR << "Logical partition metadata has invalid sector range.";
- return false;
- }
+
+ *blob = SerializeMetadata(metadata);
+
// Make sure we're writing within the space reserved.
if (blob->size() > geometry.metadata_max_size) {
LERROR << "Logical partition metadata is too large. " << blob->size() << " > "
@@ -106,15 +103,13 @@
// metadata.
uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
- if (reserved_size > blockdevice_size ||
- reserved_size > geometry.first_logical_sector * LP_SECTOR_SIZE) {
+ uint64_t total_reserved = reserved_size * 2;
+
+ if (total_reserved > blockdevice_size ||
+ total_reserved > geometry.first_logical_sector * LP_SECTOR_SIZE) {
LERROR << "Not enough space to store all logical partition metadata slots.";
return false;
}
- if (blockdevice_size - reserved_size < (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE) {
- LERROR << "Not enough space to backup all logical partition metadata slots.";
- return false;
- }
if (blockdevice_size != metadata.geometry.block_device_size) {
LERROR << "Block device size " << blockdevice_size
<< " does not match metadata requested size " << metadata.geometry.block_device_size;
@@ -130,11 +125,12 @@
}
// Make sure all linear extents have a valid range.
+ uint64_t last_sector = geometry.block_device_size / LP_SECTOR_SIZE;
for (const auto& extent : metadata.extents) {
if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
uint64_t physical_sector = extent.target_data;
if (physical_sector < geometry.first_logical_sector ||
- physical_sector + extent.num_sectors > geometry.last_logical_sector) {
+ physical_sector + extent.num_sectors > last_sector) {
LERROR << "Extent table entry is out of bounds.";
return false;
}
@@ -162,14 +158,14 @@
const std::string& blob,
const std::function<bool(int, const std::string&)>& writer) {
int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
- int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END);
+ int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET);
if (abs_offset == (int64_t)-1) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset;
return false;
}
- if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) {
+ if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) {
PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset
- << " is within logical partition bounds, sector " << geometry.last_logical_sector;
+ << " is within logical partition bounds, sector " << geometry.first_logical_sector;
return false;
}
if (!writer(fd, blob)) {
@@ -211,7 +207,7 @@
// Write geometry to the first and last 4096 bytes of the device.
std::string blob = SerializeGeometry(metadata.geometry);
- if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
return false;
}
@@ -219,7 +215,7 @@
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
return false;
}
- if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+ if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
return false;
}
diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp
index 1c339f4..43d5708 100644
--- a/gatekeeperd/IGateKeeperService.cpp
+++ b/gatekeeperd/IGateKeeperService.cpp
@@ -70,7 +70,7 @@
} else {
reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
}
- return NO_ERROR;
+ return OK;
}
case VERIFY: {
CHECK_INTERFACE(IGateKeeperService, data, reply);
@@ -102,7 +102,7 @@
} else {
reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
}
- return NO_ERROR;
+ return OK;
}
case VERIFY_CHALLENGE: {
CHECK_INTERFACE(IGateKeeperService, data, reply);
@@ -141,7 +141,7 @@
} else {
reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
}
- return NO_ERROR;
+ return OK;
}
case GET_SECURE_USER_ID: {
CHECK_INTERFACE(IGateKeeperService, data, reply);
@@ -149,20 +149,20 @@
uint64_t sid = getSecureUserId(uid);
reply->writeNoException();
reply->writeInt64(sid);
- return NO_ERROR;
+ return OK;
}
case CLEAR_SECURE_USER_ID: {
CHECK_INTERFACE(IGateKeeperService, data, reply);
uint32_t uid = data.readInt32();
clearSecureUserId(uid);
reply->writeNoException();
- return NO_ERROR;
+ return OK;
}
case REPORT_DEVICE_SETUP_COMPLETE: {
CHECK_INTERFACE(IGateKeeperService, data, reply);
reportDeviceSetupComplete();
reply->writeNoException();
- return NO_ERROR;
+ return OK;
}
default:
return BBinder::onTransact(code, data, reply, flags);
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 5f3ce36..f2818f3 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -386,7 +386,7 @@
write(fd, result, strlen(result) + 1);
}
- return NO_ERROR;
+ return OK;
}
private:
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 80c5afe..2a5667c 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -357,7 +357,7 @@
if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryChargeCounterPath);
- ret = NO_ERROR;
+ ret = OK;
} else {
ret = NAME_NOT_FOUND;
}
@@ -367,7 +367,7 @@
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCurrentNowPath);
- ret = NO_ERROR;
+ ret = OK;
} else {
ret = NAME_NOT_FOUND;
}
@@ -377,7 +377,7 @@
if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCurrentAvgPath);
- ret = NO_ERROR;
+ ret = OK;
} else {
ret = NAME_NOT_FOUND;
}
@@ -387,7 +387,7 @@
if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCapacityPath);
- ret = NO_ERROR;
+ ret = OK;
} else {
ret = NAME_NOT_FOUND;
}
@@ -403,7 +403,7 @@
case BATTERY_PROP_BATTERY_STATUS:
val->valueInt64 = getChargeStatus();
- ret = NO_ERROR;
+ ret = OK;
break;
default:
diff --git a/init/Android.mk b/init/Android.mk
index 5554995..ef08329 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -51,7 +51,8 @@
uevent_listener.cpp \
util.cpp \
-LOCAL_MODULE := init
+LOCAL_MODULE := init_first_stage
+LOCAL_MODULE_STEM := init
LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -87,8 +88,32 @@
libselinux \
libcap \
-LOCAL_REQUIRED_MODULES := \
- init_second_stage \
-
LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init_system
+ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
+LOCAL_REQUIRED_MODULES := \
+ init_first_stage \
+ init_second_stage \
+
+else
+LOCAL_REQUIRED_MODULES := \
+ init_second_stage \
+
+endif
+include $(BUILD_PHONY_PACKAGE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init_vendor
+ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
+LOCAL_REQUIRED_MODULES := \
+ init_first_stage \
+
+endif
+include $(BUILD_PHONY_PACKAGE)
+
+
diff --git a/init/README.md b/init/README.md
index 02a65d5..f938ccc 100644
--- a/init/README.md
+++ b/init/README.md
@@ -189,7 +189,7 @@
`critical`
> This is a device-critical service. If it exits more than four times in
- four minutes, the device will reboot into recovery mode.
+ four minutes, the device will reboot into bootloader.
`disabled`
> This service will not automatically start with its class.
@@ -213,7 +213,8 @@
`interface <interface name> <instance name>`
> Associates this service with a list of the HIDL services that it provides. The interface name
must be a fully-qualified name and not a value name. This is used to allow hwservicemanager to
- lazily start services.
+ lazily start services. When multiple interfaces are served, this tag should be used multiple
+ times.
For example: interface vendor.foo.bar@1.0::IBaz default
`ioprio <class> <priority>`
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 17d34e1..7da2526 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1018,7 +1018,11 @@
if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
if (e4crypt_is_native()) {
LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason;
- reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+ if (auto result = reboot_into_recovery(
+ {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+ !result) {
+ LOG(FATAL) << "Could not reboot into recovery: " << result.error();
+ }
} else {
LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
}
diff --git a/init/keychords.cpp b/init/keychords.cpp
index b8c1cfd..f5ac44f 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -41,7 +41,7 @@
Keychords::~Keychords() noexcept {
if (inotify_fd_ >= 0) {
- epoll_->UnregisterHandler(inotify_fd_);
+ epoll_->UnregisterHandler(inotify_fd_).IgnoreError();
::close(inotify_fd_);
}
while (!registration_.empty()) GeteventCloseDevice(registration_.begin()->first);
@@ -186,7 +186,11 @@
current_ |= mask & available & set;
LambdaCheck();
}
- epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); });
+ if (auto result = epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); });
+ !result) {
+ LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
+ return false;
+ }
return true;
}
@@ -208,7 +212,7 @@
auto it = registration_.find(device);
if (it == registration_.end()) return;
auto fd = (*it).second;
- epoll_->UnregisterHandler(fd);
+ epoll_->UnregisterHandler(fd).IgnoreError();
registration_.erase(it);
::close(fd);
}
@@ -266,7 +270,11 @@
}
if (inotify_fd_ >= 0) {
- epoll_->RegisterHandler(inotify_fd_, [this]() { this->InotifyHandler(); });
+ if (auto result =
+ epoll_->RegisterHandler(inotify_fd_, [this]() { this->InotifyHandler(); });
+ !result) {
+ LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
+ }
}
}
diff --git a/init/keychords_test.cpp b/init/keychords_test.cpp
index a3baeb1..e5a6fd3 100644
--- a/init/keychords_test.cpp
+++ b/init/keychords_test.cpp
@@ -213,7 +213,7 @@
}
void TestFrame::RelaxForMs(std::chrono::milliseconds wait) {
- epoll_.Wait(wait);
+ epoll_.Wait(wait).IgnoreError();
}
void TestFrame::SetChord(int key, bool value) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 866f40e..a145797 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -142,7 +142,9 @@
LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
return;
}
- service->Start();
+ if (auto result = service->Start(); !result) {
+ LOG(WARNING) << "Could not start blank_screen service: " << result.error();
+ }
}
static void ShutdownVold() {
@@ -307,15 +309,14 @@
auto shutdown_timeout = 0ms;
if (!SHUTDOWN_ZERO_TIMEOUT) {
- if (is_thermal_shutdown) {
- constexpr unsigned int thermal_shutdown_timeout = 1;
- shutdown_timeout = std::chrono::seconds(thermal_shutdown_timeout);
- } else {
- constexpr unsigned int shutdown_timeout_default = 6;
- auto shutdown_timeout_property = android::base::GetUintProperty(
- "ro.build.shutdown_timeout", shutdown_timeout_default);
- shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
+ constexpr unsigned int shutdown_timeout_default = 6;
+ constexpr unsigned int max_thermal_shutdown_timeout = 3;
+ auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
+ shutdown_timeout_default);
+ if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
+ shutdown_timeout_final = max_thermal_shutdown_timeout;
}
+ shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
}
LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
diff --git a/init/result.h b/init/result.h
index fc03962..0e3fd3d 100644
--- a/init/result.h
+++ b/init/result.h
@@ -151,7 +151,7 @@
}
template <typename T>
-class Result {
+class [[nodiscard]] Result {
public:
Result() {}
@@ -170,6 +170,8 @@
: contents_(std::in_place_index_t<1>(), std::move(result_error.error_string),
result_error.error_errno) {}
+ void IgnoreError() const {}
+
bool has_value() const { return contents_.index() == 0; }
T& value() & { return std::get<0>(contents_); }
diff --git a/init/service.cpp b/init/service.cpp
index a3e5953..0b1425d 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -369,7 +369,7 @@
return;
}
- // If we crash > 4 times in 4 minutes, reboot into recovery.
+ // If we crash > 4 times in 4 minutes, reboot into bootloader.
boot_clock::time_point now = boot_clock::now();
if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
if (now < time_crashed_ + 4min) {
diff --git a/init/service.h b/init/service.h
index e8d5ead..ee53adf 100644
--- a/init/service.h
+++ b/init/service.h
@@ -43,7 +43,7 @@
#define SVC_RUNNING 0x004 // currently active
#define SVC_RESTARTING 0x008 // waiting to restart
#define SVC_CONSOLE 0x010 // requires console
-#define SVC_CRITICAL 0x020 // will reboot into recovery if keeps crashing
+#define SVC_CRITICAL 0x020 // will reboot into bootloader if keeps crashing
#define SVC_RESET 0x040 // Use when stopping a process,
// but not disabling so it can be restarted with its class.
#define SVC_RC_DISABLED 0x080 // Remember if the disabled flag was set in the rc script.
diff --git a/init/stable_properties.h b/init/stable_properties.h
index 4972d10..baef833 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -31,6 +31,7 @@
static const std::set<std::string> kExportedActionableProperties = {
"dev.bootcomplete",
"init.svc.console",
+ "init.svc.dumpstatez",
"init.svc.mediadrm",
"init.svc.surfaceflinger",
"init.svc.zygote",
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
index 6307993..eae03e3 100644
--- a/init/subcontext_benchmark.cpp
+++ b/init/subcontext_benchmark.cpp
@@ -39,7 +39,7 @@
free(context);
while (state.KeepRunning()) {
- subcontext.Execute(std::vector<std::string>{"return_success"});
+ subcontext.Execute(std::vector<std::string>{"return_success"}).IgnoreError();
}
if (subcontext.pid() > 0) {
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 95be6af..66491dd 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -175,7 +175,7 @@
//
// When a subprocess crashes, we fatally abort from ueventd. init will restart ueventd when
// init reaps it, and the cold boot process will start again. If this continues to fail, then
- // since ueventd is marked as a critical service, init will reboot to recovery.
+ // since ueventd is marked as a critical service, init will reboot to bootloader.
//
// When a subprocess gets stuck, keep ueventd spinning waiting for it. init has a timeout for
// cold boot and will reboot to the bootloader if ueventd does not complete in time.
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 3be8ad0..845c586 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -131,6 +131,7 @@
#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
#define AID_LMKD 1069 /* low memory killer daemon */
#define AID_LLKD 1070 /* live lock daemon */
+#define AID_IORAPD 1071 /* input/output readahead and pin daemon */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/partition_utils.cpp b/libcutils/partition_utils.cpp
index 6735d6c..2211ff6 100644
--- a/libcutils/partition_utils.cpp
+++ b/libcutils/partition_utils.cpp
@@ -25,7 +25,7 @@
#include <cutils/properties.h>
-static int only_one_char(char *buf, int len, char c)
+static int only_one_char(uint8_t *buf, int len, uint8_t c)
{
int i, ret;
@@ -41,7 +41,7 @@
int partition_wiped(char *source)
{
- char buf[4096];
+ uint8_t buf[4096];
int fd, ret;
if ((fd = open(source, O_RDONLY)) < 0) {
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index ac009a9..f47b6e4 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -171,7 +171,7 @@
}
mAssembly->resize( int(pc()-base())*4 );
-
+
// the instruction cache is flushed by CodeCache
const int64_t duration = ggl_system_time() - mDuration;
const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
@@ -183,8 +183,8 @@
printf(format, name, int(pc()-base()), base(), pc(), duration);
disassemble(name);
}
-
- return NO_ERROR;
+
+ return OK;
}
uint32_t* ARMAssembler::pcForLabel(const char* label)
@@ -213,14 +213,14 @@
// multiply...
void ARMAssembler::MLA(int cc, int s,
int Rd, int Rm, int Rs, int Rn) {
- if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
+ if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
*mPC++ = (cc<<28) | (1<<21) | (s<<20) |
(Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
}
void ARMAssembler::MUL(int cc, int s,
int Rd, int Rm, int Rs) {
- if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
+ if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
*mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
}
@@ -577,4 +577,3 @@
}
}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index aebc129..8926776 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -325,7 +325,7 @@
printf(format, name, int(pc()-base()), base(), pc(), duration);
disassemble(name);
}
- return NO_ERROR;
+ return OK;
}
uint32_t* ArmToArm64Assembler::pcForLabel(const char* label)
@@ -1238,4 +1238,3 @@
}
}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index 039a725..7de8cc1 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -1421,7 +1421,7 @@
disassemble(name);
}
- return NO_ERROR;
+ return OK;
}
uint32_t* MIPSAssembler::pcForLabel(const char* label)
@@ -1953,5 +1953,3 @@
}; // namespace android:
-
-
diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c
index 735088a..8eedc60 100644
--- a/libstats/stats_event_list.c
+++ b/libstats/stats_event_list.c
@@ -125,6 +125,7 @@
void stats_log_close() {
statsd_writer_init_lock();
+ write_to_statsd = __write_to_statsd_init;
if (statsdLoggerWrite.close) {
(*statsdLoggerWrite.close)();
}
diff --git a/libsystem/include/system/camera.h b/libsystem/include/system/camera.h
index 7d79673..2ca90c3 100644
--- a/libsystem/include/system/camera.h
+++ b/libsystem/include/system/camera.h
@@ -158,8 +158,8 @@
*
* When any camera method returns error, the client can use ping command
* to see if the camera has been taken away by other clients. If the result
- * is NO_ERROR, it means the camera hardware is not released. If the result
- * is not NO_ERROR, the camera has been released and the existing client
+ * is OK, it means the camera hardware is not released. If the result
+ * is not OK, the camera has been released and the existing client
* can silently finish itself or show a dialog.
*/
CAMERA_CMD_PING = 9,
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 24ea7aa..9dc2699 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -374,6 +374,7 @@
continue;
if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
return false;
+ continue;
default:
continue;
}
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 430f6c5..17e2526 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -126,7 +126,7 @@
const std::string dex_debug_name("__dex_debug_descriptor");
for (MapInfo* info : *maps) {
- if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+ if (!(info->flags & PROT_READ) || info->offset != 0) {
continue;
}
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 4723606..56a0679 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -194,26 +194,26 @@
return true;
}
-void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) {
+bool Elf::GetInfo(Memory* memory, uint64_t* size) {
if (!IsValidElf(memory)) {
- *valid = false;
- return;
+ return false;
}
*size = 0;
- *valid = true;
- // Now read the section header information.
uint8_t class_type;
if (!memory->ReadFully(EI_CLASS, &class_type, 1)) {
- return;
+ return false;
}
+
+ // Get the maximum size of the elf data from the header.
if (class_type == ELFCLASS32) {
ElfInterface32::GetMaxSize(memory, size);
} else if (class_type == ELFCLASS64) {
ElfInterface64::GetMaxSize(memory, size);
} else {
- *valid = false;
+ return false;
}
+ return true;
}
bool Elf::IsValidPc(uint64_t pc) {
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 0c319ec..821aacf 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -174,7 +174,7 @@
const std::string descriptor_name("__jit_debug_descriptor");
for (MapInfo* info : *maps) {
- if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+ if (!(info->flags & PROT_READ) || info->offset != 0) {
continue;
}
@@ -194,10 +194,9 @@
Elf* elf = info->GetElf(memory_, true);
uint64_t descriptor_addr;
- if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr)) {
- // Search for the first non-zero entry.
- descriptor_addr += info->start;
- entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr);
+ // Find first non-empty entry (libart might be loaded multiple times).
+ if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr) && descriptor_addr != 0) {
+ entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr + info->start);
if (entry_addr_ != 0) {
break;
}
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 64005ae..52b7535 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -53,10 +53,8 @@
return nullptr;
}
- bool valid;
uint64_t max_size;
- Elf::GetInfo(memory.get(), &valid, &max_size);
- if (!valid) {
+ if (!Elf::GetInfo(memory.get(), &max_size)) {
// Init as if the whole file is an elf.
if (memory->Init(name, 0)) {
elf_offset = offset;
@@ -109,11 +107,7 @@
// first part of the elf file. This is done if the linker rosegment
// option is used.
std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
- bool valid;
- uint64_t max_size;
- Elf::GetInfo(memory.get(), &valid, &max_size);
- if (valid) {
- // Valid elf, we are done.
+ if (Elf::IsValidElf(memory.get())) {
return memory.release();
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 099cc9e..ee1cd1a 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -190,6 +190,12 @@
FillInDexFrame();
// Clear the dex pc so that we don't repeat this frame later.
regs_->set_dex_pc(0);
+
+ // Make sure there is enough room for the real frame.
+ if (frames_.size() == max_frames_) {
+ last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
+ break;
+ }
}
FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment);
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index f4cdbda..9af859d 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -94,7 +94,7 @@
static bool IsValidElf(Memory* memory);
- static void GetInfo(Memory* memory, bool* valid, uint64_t* size);
+ static bool GetInfo(Memory* memory, uint64_t* size);
static uint64_t GetLoadBias(Memory* memory);
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index d029bb0..c6d7f33 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -46,17 +46,17 @@
maps_.reset(
new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
"4000-6000 r--s 00000000 00:00 0\n"
- "6000-8000 -w-s 00000000 00:00 0\n"
- "a000-c000 r-xp 00000000 00:00 0\n"
- "c000-f000 rwxp 00000000 00:00 0\n"
- "f000-11000 r-xp 00000000 00:00 0\n"
+ "6000-8000 -wxs 00000000 00:00 0\n"
+ "a000-c000 r--p 00000000 00:00 0\n"
+ "c000-f000 rw-p 00000000 00:00 0\n"
+ "f000-11000 r--p 00000000 00:00 0\n"
"100000-110000 rw-p 0000000 00:00 0\n"
"200000-210000 rw-p 0000000 00:00 0\n"
"300000-400000 rw-p 0000000 00:00 0\n"));
ASSERT_TRUE(maps_->Parse());
- // Global variable in a section that is not readable/executable.
- MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
+ // Global variable in a section that is not readable.
+ MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
ASSERT_TRUE(map_info != nullptr);
MemoryFake* memory = new MemoryFake;
ElfFake* elf = new ElfFake(memory);
@@ -95,7 +95,7 @@
void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
void WriteDex(uint64_t dex_file);
- static constexpr size_t kMapGlobalNonReadableExectable = 3;
+ static constexpr size_t kMapGlobalNonReadable = 2;
static constexpr size_t kMapGlobalSetToZero = 4;
static constexpr size_t kMapGlobal = 5;
static constexpr size_t kMapDexFileEntries = 7;
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index c1c45f8..66f0859 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -45,11 +45,11 @@
maps_.reset(
new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
"4000-6000 r--s 00000000 00:00 0\n"
- "6000-8000 -w-s 00000000 00:00 0\n"
+ "6000-8000 -wxs 00000000 00:00 0\n"
"a000-c000 --xp 00000000 00:00 0\n"
- "c000-f000 rwxp 00000000 00:00 0\n"
- "f000-11000 r-xp 00000000 00:00 0\n"
- "12000-14000 r-xp 00000000 00:00 0\n"
+ "c000-f000 rw-p 00000000 00:00 0\n"
+ "f000-11000 r--p 00000000 00:00 0\n"
+ "12000-14000 r--p 00000000 00:00 0\n"
"100000-110000 rw-p 0000000 00:00 0\n"
"200000-210000 rw-p 0000000 00:00 0\n"));
ASSERT_TRUE(maps_->Parse());
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 4369030..831d3b5 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -946,6 +946,33 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+TEST_F(UnwinderTest, dex_pc_max_frames) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ regs_.set_pc(0x1000);
+ regs_.set_sp(0x10000);
+ regs_.FakeSetDexPc(0xa3400);
+
+ Unwinder unwinder(1, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x400U, frame->rel_pc);
+ EXPECT_EQ(0xa3400U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0xa3000U, frame->map_start);
+ EXPECT_EQ(0xa4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
// Verify format frame code.
TEST_F(UnwinderTest, format_frame_static) {
FrameData frame;
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
index b8c065d..f00272a 100644
--- a/libutils/PropertyMap.cpp
+++ b/libutils/PropertyMap.cpp
@@ -208,7 +208,7 @@
mTokenizer->nextLine();
}
- return NO_ERROR;
+ return OK;
}
} // namespace android
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 5c0b406..818b171 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -157,12 +157,12 @@
if (begin >= N) {
SharedBuffer::bufferFromData(mString)->release();
mString = getEmptyString();
- return NO_ERROR;
+ return OK;
}
if ((begin+len) > N) len = N-begin;
if (begin == 0 && len == N) {
setTo(other);
- return NO_ERROR;
+ return OK;
}
if (&other == this) {
@@ -191,7 +191,7 @@
memmove(str, other, len*sizeof(char16_t));
str[len] = 0;
mString = str;
- return NO_ERROR;
+ return OK;
}
return NO_MEMORY;
}
@@ -202,9 +202,9 @@
const size_t otherLen = other.size();
if (myLen == 0) {
setTo(other);
- return NO_ERROR;
+ return OK;
} else if (otherLen == 0) {
- return NO_ERROR;
+ return OK;
}
if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
@@ -218,7 +218,7 @@
char16_t* str = (char16_t*)buf->data();
memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
mString = str;
- return NO_ERROR;
+ return OK;
}
return NO_MEMORY;
}
@@ -228,9 +228,9 @@
const size_t myLen = size();
if (myLen == 0) {
setTo(chrs, otherLen);
- return NO_ERROR;
+ return OK;
} else if (otherLen == 0) {
- return NO_ERROR;
+ return OK;
}
if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
@@ -245,7 +245,7 @@
memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
str[myLen+otherLen] = 0;
mString = str;
- return NO_ERROR;
+ return OK;
}
return NO_MEMORY;
}
@@ -260,9 +260,9 @@
const size_t myLen = size();
if (myLen == 0) {
return setTo(chrs, len);
- return NO_ERROR;
+ return OK;
} else if (len == 0) {
- return NO_ERROR;
+ return OK;
}
if (pos > myLen) pos = myLen;
@@ -286,7 +286,7 @@
#if 0
printf("Result (%d chrs): %s\n", size(), String8(*this).string());
#endif
- return NO_ERROR;
+ return OK;
}
return NO_MEMORY;
}
@@ -357,7 +357,7 @@
edit[i] = tolower((char)v);
}
}
- return NO_ERROR;
+ return OK;
}
status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
@@ -378,7 +378,7 @@
edit[i] = withThis;
}
}
- return NO_ERROR;
+ return OK;
}
status_t String16::remove(size_t len, size_t begin)
@@ -387,11 +387,11 @@
if (begin >= N) {
SharedBuffer::bufferFromData(mString)->release();
mString = getEmptyString();
- return NO_ERROR;
+ return OK;
}
if ((begin+len) > N) len = N-begin;
if (begin == 0 && len == N) {
- return NO_ERROR;
+ return OK;
}
if (begin > 0) {
@@ -410,7 +410,7 @@
char16_t* str = (char16_t*)buf->data();
str[len] = 0;
mString = str;
- return NO_ERROR;
+ return OK;
}
return NO_MEMORY;
}
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 8d318f7..0025c56 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -230,7 +230,7 @@
const char *newString = allocFromUTF8(other, strlen(other));
SharedBuffer::bufferFromData(mString)->release();
mString = newString;
- if (mString) return NO_ERROR;
+ if (mString) return OK;
mString = getEmptyString();
return NO_MEMORY;
@@ -241,7 +241,7 @@
const char *newString = allocFromUTF8(other, len);
SharedBuffer::bufferFromData(mString)->release();
mString = newString;
- if (mString) return NO_ERROR;
+ if (mString) return OK;
mString = getEmptyString();
return NO_MEMORY;
@@ -252,7 +252,7 @@
const char *newString = allocFromUTF16(other, len);
SharedBuffer::bufferFromData(mString)->release();
mString = newString;
- if (mString) return NO_ERROR;
+ if (mString) return OK;
mString = getEmptyString();
return NO_MEMORY;
@@ -263,7 +263,7 @@
const char *newString = allocFromUTF32(other, len);
SharedBuffer::bufferFromData(mString)->release();
mString = newString;
- if (mString) return NO_ERROR;
+ if (mString) return OK;
mString = getEmptyString();
return NO_MEMORY;
@@ -274,9 +274,9 @@
const size_t otherLen = other.bytes();
if (bytes() == 0) {
setTo(other);
- return NO_ERROR;
+ return OK;
} else if (otherLen == 0) {
- return NO_ERROR;
+ return OK;
}
return real_append(other.string(), otherLen);
@@ -292,7 +292,7 @@
if (bytes() == 0) {
return setTo(other, otherLen);
} else if (otherLen == 0) {
- return NO_ERROR;
+ return OK;
}
return real_append(other, otherLen);
@@ -311,7 +311,7 @@
status_t String8::appendFormatV(const char* fmt, va_list args)
{
- int n, result = NO_ERROR;
+ int n, result = OK;
va_list tmp_args;
/* args is undefined after vsnprintf.
@@ -346,7 +346,7 @@
str += myLen;
memcpy(str, other, otherLen);
str[otherLen] = '\0';
- return NO_ERROR;
+ return OK;
}
return NO_MEMORY;
}
@@ -382,7 +382,7 @@
mString = str;
}
- return NO_ERROR;
+ return OK;
}
ssize_t String8::find(const char* other, size_t start) const
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 43ec6c1..64bc402 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -379,7 +379,7 @@
{
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
- return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR;
+ return dwWaitResult != WAIT_OBJECT_0 ? -1 : OK;
}
void Mutex::unlock()
@@ -506,7 +506,7 @@
ReleaseMutex(condState->internalMutex);
WaitForSingleObject(hMutex, INFINITE);
- return res == WAIT_OBJECT_0 ? NO_ERROR : -1;
+ return res == WAIT_OBJECT_0 ? OK : -1;
}
} WinCondition;
@@ -639,13 +639,15 @@
*/
Thread::Thread(bool canCallJava)
- : mCanCallJava(canCallJava),
- mThread(thread_id_t(-1)),
- mLock("Thread::mLock"),
- mStatus(NO_ERROR),
- mExitPending(false), mRunning(false)
+ : mCanCallJava(canCallJava),
+ mThread(thread_id_t(-1)),
+ mLock("Thread::mLock"),
+ mStatus(OK),
+ mExitPending(false),
+ mRunning(false)
#if defined(__ANDROID__)
- , mTid(-1)
+ ,
+ mTid(-1)
#endif
{
}
@@ -656,7 +658,7 @@
status_t Thread::readyToRun()
{
- return NO_ERROR;
+ return OK;
}
status_t Thread::run(const char* name, int32_t priority, size_t stack)
@@ -672,7 +674,7 @@
// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
- mStatus = NO_ERROR;
+ mStatus = OK;
mExitPending = false;
mThread = thread_id_t(-1);
@@ -700,10 +702,10 @@
}
// Do not refer to mStatus here: The thread is already running (may, in fact
- // already have exited with a valid mStatus result). The NO_ERROR indication
+ // already have exited with a valid mStatus result). The OK indication
// here merely indicates successfully starting the thread and does not
// imply successful termination/execution.
- return NO_ERROR;
+ return OK;
// Exiting scope of mLock is a memory barrier and allows new thread to run
}
@@ -728,7 +730,7 @@
if (first) {
first = false;
self->mStatus = self->readyToRun();
- result = (self->mStatus == NO_ERROR);
+ result = (self->mStatus == OK);
if (result && !self->exitPending()) {
// Binder threads (and maybe others) rely on threadLoop
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index f73d699..98dd2fd 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -48,7 +48,7 @@
status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) {
*outTokenizer = nullptr;
- int result = NO_ERROR;
+ int result = OK;
int fd = ::open(filename.string(), O_RDONLY);
if (fd < 0) {
result = -errno;
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index e16f88d..c97a19b 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -61,7 +61,7 @@
"[%p] subclasses of VectorImpl must call finish_vector()"
" in their destructor. Leaking %d bytes.",
this, (int)(mCount*mItemSize));
- // We can't call _do_destroy() here because the vtable is already gone.
+ // We can't call _do_destroy() here because the vtable is already gone.
}
VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
@@ -197,7 +197,7 @@
_do_copy(temp, item, 1);
ssize_t j = i-1;
- void* next = reinterpret_cast<char*>(array) + mItemSize*(i);
+ void* next = reinterpret_cast<char*>(array) + mItemSize*(i);
do {
_do_destroy(next, 1);
_do_copy(next, curr, 1);
@@ -214,13 +214,13 @@
}
i++;
}
-
+
if (temp) {
_do_destroy(temp, 1);
free(temp);
}
}
- return NO_ERROR;
+ return OK;
}
void VectorImpl::pop()
@@ -354,7 +354,7 @@
}
ssize_t VectorImpl::resize(size_t size) {
- ssize_t result = NO_ERROR;
+ ssize_t result = OK;
if (size > mCount) {
result = insertAt(mCount, size - mCount);
} else if (size < mCount) {
@@ -370,7 +370,7 @@
if (sb->release(SharedBuffer::eKeepStorage) == 1) {
_do_destroy(mStorage, mCount);
SharedBuffer::dealloc(sb);
- }
+ }
}
}
@@ -644,13 +644,13 @@
}
}
}
- return NO_ERROR;
+ return OK;
}
ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
{
// we've merging a sorted vector... nice!
- ssize_t err = NO_ERROR;
+ ssize_t err = OK;
if (!vector.isEmpty()) {
// first take care of the case where the vectors are sorted together
if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
@@ -677,4 +677,3 @@
/*****************************************************************************/
}; // namespace android
-
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 7093a20..1e03677 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -14,22 +14,19 @@
* limitations under the License.
*/
-#ifndef ANDROID_ERRORS_H
-#define ANDROID_ERRORS_H
+#pragma once
-#include <sys/types.h>
#include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
namespace android {
-// use this type to return error codes
-#ifdef _WIN32
-typedef int status_t;
-#else
-typedef int32_t status_t;
-#endif
-
-/* the MS C runtime lacks a few error codes */
+/**
+ * The type used to return success/failure from frameworks APIs.
+ * See the anonymous enum below for valid values.
+ */
+typedef int32_t status_t;
/*
* Error codes.
@@ -43,8 +40,8 @@
#endif
enum {
- OK = 0, // Everything's swell.
- NO_ERROR = 0, // No errors.
+ OK = 0, // Preferred constant for checking success.
+ NO_ERROR = OK, // Deprecated synonym for `OK`. Prefer `OK` because it doesn't conflict with Windows.
UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
@@ -82,7 +79,3 @@
#endif
} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_ERRORS_H
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 0a19019..9d00602 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -190,11 +190,11 @@
inline status_t flatten(void* buffer, size_t size) const {
if (size < sizeof(T)) return NO_MEMORY;
memcpy(buffer, static_cast<T const*>(this), sizeof(T));
- return NO_ERROR;
+ return OK;
}
inline status_t unflatten(void const* buffer, size_t) {
memcpy(static_cast<T*>(this), buffer, sizeof(T));
- return NO_ERROR;
+ return OK;
}
};
diff --git a/libutils/include/utils/Functor.h b/libutils/include/utils/Functor.h
index c0c8d57..c458699 100644
--- a/libutils/include/utils/Functor.h
+++ b/libutils/include/utils/Functor.h
@@ -29,7 +29,7 @@
public:
Functor() {}
virtual ~Functor() {}
- virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
+ virtual status_t operator()(int /*what*/, void* /*data*/) { return OK; }
};
} // namespace android
diff --git a/libutils/include/utils/Tokenizer.h b/libutils/include/utils/Tokenizer.h
index bb25f37..61c5ff7 100644
--- a/libutils/include/utils/Tokenizer.h
+++ b/libutils/include/utils/Tokenizer.h
@@ -37,7 +37,7 @@
/**
* Opens a file and maps it into memory.
*
- * Returns NO_ERROR and a tokenizer for the file, if successful.
+ * Returns OK and a tokenizer for the file, if successful.
* Otherwise returns an error and sets outTokenizer to NULL.
*/
static status_t open(const String8& filename, Tokenizer** outTokenizer);
@@ -45,7 +45,7 @@
/**
* Prepares to tokenize the contents of a string.
*
- * Returns NO_ERROR and a tokenizer for the string, if successful.
+ * Returns OK and a tokenizer for the string, if successful.
* Otherwise returns an error and sets outTokenizer to NULL.
*/
static status_t fromContents(const String8& filename,
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index fd3f602..3308adf 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -23,11 +23,21 @@
"-D_FILE_OFFSET_BITS=64",
],
cppflags: [
- "-Wold-style-cast",
// Incorrectly warns when C++11 empty brace {} initializer is used.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
"-Wno-missing-field-initializers",
],
+
+ // Enable -Wold-style-cast only for non-Windows targets. _islower_l,
+ // _isupper_l etc. in MinGW locale_win32.h (included from
+ // libcxx/include/__locale) has an old-style-cast.
+ target: {
+ not_windows: {
+ cppflags: [
+ "-Wold-style-cast",
+ ],
+ },
+ },
}
cc_defaults {
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 018b1a9..32d7901 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -103,7 +103,8 @@
off64_t offset;
};
-typedef void* ZipArchiveHandle;
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
/*
* Open a Zip archive, and sets handle to the value of the opaque
@@ -144,7 +145,7 @@
* this handle for any further operations without an intervening
* call to one of the OpenArchive variants.
*/
-void CloseArchive(ZipArchiveHandle handle);
+void CloseArchive(ZipArchiveHandle archive);
/*
* Find an entry in the Zip archive, by name. |entryName| must be a null
@@ -162,7 +163,7 @@
* On non-Windows platforms this method does not modify internal state and
* can be called concurrently.
*/
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data);
+int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data);
/*
* Start iterating over all entries of a zip file. The order of iteration
@@ -177,8 +178,8 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
- const ZipString* optional_suffix);
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+ const ZipString* optional_prefix, const ZipString* optional_suffix);
/*
* Advance to the next element in the zipfile in iteration order.
@@ -203,7 +204,7 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd);
+int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd);
/**
* Uncompress a given zip entry to the memory region at |begin| and of
@@ -213,9 +214,9 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size);
+int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size);
-int GetFileDescriptor(const ZipArchiveHandle handle);
+int GetFileDescriptor(const ZipArchiveHandle archive);
const char* ErrorCodeString(int32_t error_code);
@@ -226,7 +227,7 @@
* Stream the uncompressed data through the supplied function,
* passing cookie to it each time it gets called.
*/
-int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
ProcessZipEntryFunction func, void* cookie);
#endif
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6a3db6b..4221ee7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -517,8 +517,7 @@
/*
* Close a ZipArchive, closing the file and freeing the contents.
*/
-void CloseArchive(ZipArchiveHandle handle) {
- ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+void CloseArchive(ZipArchiveHandle archive) {
ALOGV("Closing archive %p", archive);
delete archive;
}
@@ -745,10 +744,8 @@
}
};
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
- const ZipString* optional_suffix) {
- ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
-
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+ const ZipString* optional_prefix, const ZipString* optional_suffix) {
if (archive == NULL || archive->hash_table == NULL) {
ALOGW("Zip: Invalid ZipArchiveHandle");
return kInvalidHandle;
@@ -766,8 +763,7 @@
delete reinterpret_cast<IterationHandle*>(cookie);
}
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data) {
- const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data) {
if (entryName.name_length == 0) {
ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
return kInvalidEntryName;
@@ -1116,8 +1112,7 @@
return 0;
}
-int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer) {
- ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+int32_t ExtractToWriter(ZipArchiveHandle archive, ZipEntry* entry, zip_archive::Writer* writer) {
const uint16_t method = entry->method;
// this should default to kUnknownCompressionMethod.
@@ -1145,18 +1140,18 @@
return return_value;
}
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
+int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size) {
MemoryWriter writer(begin, size);
- return ExtractToWriter(handle, entry, &writer);
+ return ExtractToWriter(archive, entry, &writer);
}
-int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
+int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd) {
auto writer = FileWriter::Create(fd, entry);
if (!writer.IsValid()) {
return kIoError;
}
- return ExtractToWriter(handle, entry, &writer);
+ return ExtractToWriter(archive, entry, &writer);
}
const char* ErrorCodeString(int32_t error_code) {
@@ -1173,8 +1168,8 @@
return "Unknown return code";
}
-int GetFileDescriptor(const ZipArchiveHandle handle) {
- return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
+int GetFileDescriptor(const ZipArchiveHandle archive) {
+ return archive->mapped_zip.GetFileDescriptor();
}
ZipString::ZipString(const char* entry_name) : name(reinterpret_cast<const uint8_t*>(entry_name)) {
@@ -1198,10 +1193,10 @@
void* cookie_;
};
-int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
ProcessZipEntryFunction func, void* cookie) {
ProcessWriter writer(func, cookie);
- return ExtractToWriter(handle, entry, &writer);
+ return ExtractToWriter(archive, entry, &writer);
}
#endif //! defined(_WIN32)
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index c724fce..4d39dd9 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -57,7 +57,7 @@
#define LLK_BLACKLIST_UID_PROPERTY "ro.llk.blacklist.uid"
#define LLK_BLACKLIST_UID_DEFAULT ""
#define LLK_BLACKLIST_STACK_PROPERTY "ro.llk.blacklist.process.stack"
-#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,/system/bin/keystore"
+#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,/system/bin/keystore,ueventd,apexd"
/* clang-format on */
__END_DECLS
diff --git a/lmkd/include/lmkd.h b/lmkd/include/lmkd.h
index fe6364d..e8f51da 100644
--- a/lmkd/include/lmkd.h
+++ b/lmkd/include/lmkd.h
@@ -30,6 +30,7 @@
LMK_TARGET = 0, /* Associate minfree with oom_adj_score */
LMK_PROCPRIO, /* Register a process and set its oom_adj_score */
LMK_PROCREMOVE, /* Unregister a process */
+ LMK_PROCPURGE, /* Purge all registered processes */
};
/*
@@ -142,6 +143,15 @@
return 2 * sizeof(int);
}
+/*
+ * Prepare LMK_PROCPURGE packet and return packet size in bytes.
+ * Warning: no checks performed, caller should ensure valid parameters.
+ */
+inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
+ packet[0] = htonl(LMK_PROCPURGE);
+ return sizeof(int);
+}
+
__END_DECLS
#endif /* _LMKD_H_ */
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 1980dc6..0a469e8 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -559,7 +559,7 @@
} else if (params.oomadj >= 300) {
soft_limit_mult = 1;
} else if (params.oomadj >= 200) {
- soft_limit_mult = 2;
+ soft_limit_mult = 8;
} else if (params.oomadj >= 100) {
soft_limit_mult = 10;
} else if (params.oomadj >= 0) {
@@ -612,9 +612,38 @@
}
lmkd_pack_get_procremove(packet, ¶ms);
+ /*
+ * WARNING: After pid_remove() procp is freed and can't be used!
+ * Therefore placed at the end of the function.
+ */
pid_remove(params.pid);
}
+static void cmd_procpurge() {
+ int i;
+ struct proc *procp;
+ struct proc *next;
+
+ if (use_inkernel_interface) {
+ return;
+ }
+
+ for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
+ procadjslot_list[i].next = &procadjslot_list[i];
+ procadjslot_list[i].prev = &procadjslot_list[i];
+ }
+
+ for (i = 0; i < PIDHASH_SZ; i++) {
+ procp = pidhash[i];
+ while (procp) {
+ next = procp->pidhash_next;
+ free(procp);
+ procp = next;
+ }
+ }
+ memset(&pidhash[0], 0, sizeof(pidhash));
+}
+
static void cmd_target(int ntargets, LMKD_CTRL_PACKET packet) {
int i;
struct lmk_target target;
@@ -757,6 +786,11 @@
goto wronglen;
cmd_procremove(packet);
break;
+ case LMK_PROCPURGE:
+ if (nargs != 0)
+ goto wronglen;
+ cmd_procpurge();
+ break;
default:
ALOGE("Received unknown command code %d", cmd);
return;
@@ -822,7 +856,7 @@
}
#ifdef LMKD_LOG_STATS
-static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) {
+static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) {
char key[LINE_MAX + 1];
int64_t value;
@@ -844,17 +878,10 @@
mem_st->swap_in_bytes = value;
}
-static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) {
+static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) {
FILE *fp;
char buf[PATH_MAX];
- /*
- * Per-application memory.stat files are available only when
- * per-application memcgs are enabled.
- */
- if (!per_app_memcg)
- return -1;
-
snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);
fp = fopen(buf, "r");
@@ -864,13 +891,50 @@
return -1;
}
- while (fgets(buf, PAGE_SIZE, fp) != NULL ) {
+ while (fgets(buf, PAGE_SIZE, fp) != NULL) {
memory_stat_parse_line(buf, mem_st);
}
fclose(fp);
return 0;
}
+
+static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) {
+ char path[PATH_MAX];
+ char buffer[PROC_STAT_BUFFER_SIZE];
+ int fd, ret;
+
+ snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid);
+ if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
+ ALOGE("%s open failed: %s", path, strerror(errno));
+ return -1;
+ }
+
+ ret = read(fd, buffer, sizeof(buffer));
+ if (ret < 0) {
+ ALOGE("%s read failed: %s", path, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ // field 10 is pgfault
+ // field 12 is pgmajfault
+ // field 24 is rss_in_pages
+ int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0;
+ if (sscanf(buffer,
+ "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d "
+ "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d "
+ "%*d %*d %" SCNd64 "",
+ &pgfault, &pgmajfault, &rss_in_pages) != 3) {
+ return -1;
+ }
+ mem_st->pgfault = pgfault;
+ mem_st->pgmajfault = pgmajfault;
+ mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE);
+
+ return 0;
+}
#endif
/* /prop/zoneinfo parsing routines */
@@ -1105,6 +1169,7 @@
char *taskname;
int tasksize;
int r;
+ int result = -1;
#ifdef LMKD_LOG_STATS
struct memory_stat mem_st = {};
@@ -1113,19 +1178,21 @@
taskname = proc_get_name(pid);
if (!taskname) {
- pid_remove(pid);
- return -1;
+ goto out;
}
tasksize = proc_get_size(pid);
if (tasksize <= 0) {
- pid_remove(pid);
- return -1;
+ goto out;
}
#ifdef LMKD_LOG_STATS
if (enable_stats_log) {
- memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid);
+ if (per_app_memcg) {
+ memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid);
+ } else {
+ memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid);
+ }
}
#endif
@@ -1135,25 +1202,33 @@
r = kill(pid, SIGKILL);
ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
taskname, pid, uid, procp->oomadj, tasksize * page_k);
- pid_remove(pid);
TRACE_KILL_END();
if (r) {
ALOGE("kill(%d): errno=%d", pid, errno);
- return -1;
+ goto out;
} else {
#ifdef LMKD_LOG_STATS
if (memory_stat_parse_result == 0) {
stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
mem_st.cache_in_bytes, mem_st.swap_in_bytes);
+ } else if (enable_stats_log) {
+ stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj,
+ -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1);
}
#endif
- return tasksize;
+ result = tasksize;
}
- return tasksize;
+out:
+ /*
+ * WARNING: After pid_remove() procp is freed and can't be used!
+ * Therefore placed at the end of the function.
+ */
+ pid_remove(pid);
+ return result;
}
/*
diff --git a/lmkd/statslog.h b/lmkd/statslog.h
index edebb19..8458480 100644
--- a/lmkd/statslog.h
+++ b/lmkd/statslog.h
@@ -67,6 +67,9 @@
};
#define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat"
+#define PROC_STAT_FILE_PATH "/proc/%d/stat"
+#define PROC_STAT_BUFFER_SIZE 1024
+#define BYTES_IN_KILOBYTE 1024
/**
* Logs the change in LMKD state which is used as start/stop boundaries for logging
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 658e079..bd17555 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -42,7 +42,7 @@
LogTimeEntry::wrlock();
LastLogTimes::iterator it = times.begin();
while (it != times.end()) {
- entry = (*it);
+ entry = it->get();
if (entry->mClient == client) {
if (!entry->isWatchingMultiple(mLogMask)) {
LogTimeEntry::unlock();
@@ -63,31 +63,12 @@
}
}
entry->triggerReader_Locked();
- if (entry->runningReader_Locked()) {
- LogTimeEntry::unlock();
- return;
- }
- entry->incRef_Locked();
- break;
+ LogTimeEntry::unlock();
+ return;
}
it++;
}
- if (it == times.end()) {
- // Create LogTimeEntry in notifyNewLog() ?
- if (mTail == (unsigned long)-1) {
- LogTimeEntry::unlock();
- return;
- }
- entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask,
- mPid, mStart, mTimeout);
- times.push_front(entry);
- }
-
- client->incRef();
-
- // release client and entry reference counts once done
- entry->startReader_Locked();
LogTimeEntry::unlock();
}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 543dfc3..ceaf393 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -27,36 +27,11 @@
class FlushCommand : public SocketClientCommand {
LogReader& mReader;
- bool mNonBlock;
- unsigned long mTail;
log_mask_t mLogMask;
- pid_t mPid;
- log_time mStart;
- uint64_t mTimeout;
public:
- // for opening a reader
- explicit FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail,
- log_mask_t logMask, pid_t pid, log_time start,
- uint64_t timeout)
- : mReader(reader),
- mNonBlock(nonBlock),
- mTail(tail),
- mLogMask(logMask),
- mPid(pid),
- mStart(start),
- mTimeout((start != log_time::EPOCH) ? timeout : 0) {
- }
-
- // for notification of an update
explicit FlushCommand(LogReader& reader, log_mask_t logMask)
- : mReader(reader),
- mNonBlock(false),
- mTail(-1),
- mLogMask(logMask),
- mPid(0),
- mStart(log_time::EPOCH),
- mTimeout(0) {
+ : mReader(reader), mLogMask(logMask) {
}
virtual void runSocketCommand(SocketClient* client);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index fd1b8b2..fbdbf79 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -105,10 +105,8 @@
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
- if (entry->owned_Locked()) {
- entry->triggerReader_Locked();
- }
+ LogTimeEntry* entry = times->get();
+ entry->triggerReader_Locked();
times++;
}
@@ -409,17 +407,15 @@
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
- if (entry->owned_Locked()) {
- if (!entry->mNonBlock) {
- end_always = true;
- break;
- }
- // it passing mEnd is blocked by the following checks.
- if (!end_set || (end <= entry->mEnd)) {
- end = entry->mEnd;
- end_set = true;
- }
+ LogTimeEntry* entry = times->get();
+ if (!entry->mNonBlock) {
+ end_always = true;
+ break;
+ }
+ // it passing mEnd is blocked by the following checks.
+ if (!end_set || (end <= entry->mEnd)) {
+ end = entry->mEnd;
+ end_set = true;
}
times++;
}
@@ -710,8 +706,8 @@
// Region locked?
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
- if (entry->owned_Locked() && entry->isWatching(id) &&
+ LogTimeEntry* entry = times->get();
+ if (entry->isWatching(id) &&
(!oldest || (oldest->mStart > entry->mStart) ||
((oldest->mStart == entry->mStart) &&
(entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
@@ -1052,9 +1048,9 @@
LogTimeEntry::wrlock();
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
+ LogTimeEntry* entry = times->get();
// Killer punch
- if (entry->owned_Locked() && entry->isWatching(id)) {
+ if (entry->isWatching(id)) {
entry->release_Locked();
}
times++;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 2b6556d..13c7af3 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -41,6 +41,7 @@
runOnEachSocket(&command);
}
+// Note returning false will release the SocketClient instance.
bool LogReader::onDataAvailable(SocketClient* cli) {
static bool name_set;
if (!name_set) {
@@ -57,6 +58,18 @@
}
buffer[len] = '\0';
+ // Clients are only allowed to send one command, disconnect them if they
+ // send another.
+ LogTimeEntry::wrlock();
+ for (const auto& entry : mLogbuf.mTimes) {
+ if (entry->mClient == cli) {
+ entry->release_Locked();
+ LogTimeEntry::unlock();
+ return false;
+ }
+ }
+ LogTimeEntry::unlock();
+
unsigned long tail = 0;
static const char _tail[] = " tail=";
char* cp = strstr(buffer, _tail);
@@ -199,14 +212,25 @@
cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail,
logMask, (int)pid, sequence.nsec(), timeout);
- FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
+ LogTimeEntry::wrlock();
+ auto entry = std::make_unique<LogTimeEntry>(
+ *this, cli, nonBlock, tail, logMask, pid, sequence, timeout);
+ if (!entry->startReader_Locked()) {
+ LogTimeEntry::unlock();
+ return false;
+ }
+
+ // release client and entry reference counts once done
+ cli->incRef();
+ mLogbuf.mTimes.emplace_front(std::move(entry));
// Set acceptable upper limit to wait for slow reader processing b/27242723
struct timeval t = { LOGD_SNDTIMEO, 0 };
setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
sizeof(t));
- command.runSocketCommand(cli);
+ LogTimeEntry::unlock();
+
return true;
}
@@ -215,9 +239,8 @@
LogTimeEntry::wrlock();
LastLogTimes::iterator it = times.begin();
while (it != times.end()) {
- LogTimeEntry* entry = (*it);
+ LogTimeEntry* entry = it->get();
if (entry->mClient == cli) {
- times.erase(it);
entry->release_Locked();
break;
}
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 7a6f84b..1715501 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -30,11 +30,7 @@
LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
bool nonBlock, unsigned long tail, log_mask_t logMask,
pid_t pid, log_time start, uint64_t timeout)
- : mRefCount(1),
- mRelease(false),
- mError(false),
- threadRunning(false),
- leadingDropped(false),
+ : leadingDropped(false),
mReader(reader),
mLogMask(logMask),
mPid(pid),
@@ -52,65 +48,21 @@
cleanSkip_Locked();
}
-void LogTimeEntry::startReader_Locked(void) {
+bool LogTimeEntry::startReader_Locked() {
pthread_attr_t attr;
- threadRunning = true;
-
if (!pthread_attr_init(&attr)) {
if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
this)) {
pthread_attr_destroy(&attr);
- return;
+ return true;
}
}
pthread_attr_destroy(&attr);
}
- threadRunning = false;
- if (mClient) {
- mClient->decRef();
- }
- decRef_Locked();
-}
-void LogTimeEntry::threadStop(void* obj) {
- LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
-
- wrlock();
-
- if (me->mNonBlock) {
- me->error_Locked();
- }
-
- SocketClient* client = me->mClient;
-
- if (me->isError_Locked()) {
- LogReader& reader = me->mReader;
- LastLogTimes& times = reader.logbuf().mTimes;
-
- LastLogTimes::iterator it = times.begin();
- while (it != times.end()) {
- if (*it == me) {
- times.erase(it);
- me->release_nodelete_Locked();
- break;
- }
- it++;
- }
-
- me->mClient = nullptr;
- reader.release(client);
- }
-
- if (client) {
- client->decRef();
- }
-
- me->threadRunning = false;
- me->decRef_Locked();
-
- unlock();
+ return false;
}
void* LogTimeEntry::threadStart(void* obj) {
@@ -118,13 +70,7 @@
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
- pthread_cleanup_push(threadStop, obj);
-
SocketClient* client = me->mClient;
- if (!client) {
- me->error();
- return nullptr;
- }
LogBuffer& logbuf = me->mReader.logbuf();
@@ -137,14 +83,14 @@
log_time start = me->mStart;
- while (me->threadRunning && !me->isError_Locked()) {
+ while (!me->mRelease) {
if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
if (pthread_cond_timedwait(&me->threadTriggeredCondition,
×Lock, &me->mTimeout) == ETIMEDOUT) {
me->mTimeout.tv_sec = 0;
me->mTimeout.tv_nsec = 0;
}
- if (!me->threadRunning || me->isError_Locked()) {
+ if (me->mRelease) {
break;
}
}
@@ -162,13 +108,12 @@
wrlock();
if (start == LogBufferElement::FLUSH_ERROR) {
- me->error_Locked();
break;
}
me->mStart = start + log_time(0, 1);
- if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
+ if (me->mNonBlock || me->mRelease) {
break;
}
@@ -179,9 +124,21 @@
}
}
- unlock();
+ LogReader& reader = me->mReader;
+ reader.release(client);
- pthread_cleanup_pop(true);
+ client->decRef();
+
+ LastLogTimes& times = reader.logbuf().mTimes;
+ auto it =
+ std::find_if(times.begin(), times.end(),
+ [&me](const auto& other) { return other.get() == me; });
+
+ if (it != times.end()) {
+ times.erase(it);
+ }
+
+ unlock();
return nullptr;
}
@@ -247,10 +204,6 @@
goto skip;
}
- if (me->isError_Locked()) {
- goto stop;
- }
-
if (!me->mTail) {
goto ok;
}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 76d016c..f4e165f 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -22,6 +22,7 @@
#include <time.h>
#include <list>
+#include <memory>
#include <log/log.h>
#include <sysutils/SocketClient.h>
@@ -33,16 +34,12 @@
class LogTimeEntry {
static pthread_mutex_t timesLock;
- unsigned int mRefCount;
- bool mRelease;
- bool mError;
- bool threadRunning;
+ bool mRelease = false;
bool leadingDropped;
pthread_cond_t threadTriggeredCondition;
pthread_t mThread;
LogReader& mReader;
static void* threadStart(void* me);
- static void threadStop(void* me);
const log_mask_t mLogMask;
const pid_t mPid;
unsigned int skipAhead[LOG_ID_MAX];
@@ -73,11 +70,8 @@
pthread_mutex_unlock(×Lock);
}
- void startReader_Locked(void);
+ bool startReader_Locked();
- bool runningReader_Locked(void) const {
- return threadRunning || mRelease || mError || mNonBlock;
- }
void triggerReader_Locked(void) {
pthread_cond_signal(&threadTriggeredCondition);
}
@@ -87,54 +81,11 @@
}
void cleanSkip_Locked(void);
- // These called after LogTimeEntry removed from list, lock implicitly held
- void release_nodelete_Locked(void) {
- mRelease = true;
- pthread_cond_signal(&threadTriggeredCondition);
- // assumes caller code path will call decRef_Locked()
- }
-
void release_Locked(void) {
mRelease = true;
pthread_cond_signal(&threadTriggeredCondition);
- if (mRefCount || threadRunning) {
- return;
- }
- // No one else is holding a reference to this
- delete this;
}
- // Called to mark socket in jeopardy
- void error_Locked(void) {
- mError = true;
- }
- void error(void) {
- wrlock();
- error_Locked();
- unlock();
- }
-
- bool isError_Locked(void) const {
- return mRelease || mError;
- }
-
- // Mark Used
- // Locking implied, grabbed when protection around loop iteration
- void incRef_Locked(void) {
- ++mRefCount;
- }
-
- bool owned_Locked(void) const {
- return mRefCount != 0;
- }
-
- void decRef_Locked(void) {
- if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
- return;
- }
- // No one else is holding a reference to this
- delete this;
- }
bool isWatching(log_id_t id) const {
return mLogMask & (1 << id);
}
@@ -146,6 +97,6 @@
static int FilterSecondPass(const LogBufferElement* element, void* me);
};
-typedef std::list<LogTimeEntry*> LastLogTimes;
+typedef std::list<std::unique_ptr<LogTimeEntry>> LastLogTimes;
#endif // _LOGD_LOG_TIMES_H__
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index a4c3955..393e204 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -67,6 +67,13 @@
LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES) $(ASAN_EXTRACT_FILES)
endif
+EXPORT_GLOBAL_HWASAN_OPTIONS :=
+ifneq ($(filter hwaddress,$(SANITIZE_TARGET)),)
+ ifneq ($(HWADDRESS_SANITIZER_GLOBAL_OPTIONS),)
+ EXPORT_GLOBAL_HWASAN_OPTIONS := export HWASAN_OPTIONS $(HWADDRESS_SANITIZER_GLOBAL_OPTIONS)
+ endif
+endif
+
EXPORT_GLOBAL_GCOV_OPTIONS :=
ifeq ($(NATIVE_COVERAGE),true)
EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/gcov
@@ -117,6 +124,7 @@
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/lib64 $(TARGET_ROOT_OUT)/odm/lib64
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/overlay $(TARGET_ROOT_OUT)/odm/overlay
LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
@@ -151,6 +159,7 @@
$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_ASAN_OPTIONS%?$(EXPORT_GLOBAL_ASAN_OPTIONS)?g' $@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
+ $(hide) sed -i -e 's?%EXPORT_GLOBAL_HWASAN_OPTIONS%?$(EXPORT_GLOBAL_HWASAN_OPTIONS)?g' $@
bcp_md5 :=
bcp_dep :=
diff --git a/rootdir/OWNERS b/rootdir/OWNERS
index 6029ae7..ca22eb8 100644
--- a/rootdir/OWNERS
+++ b/rootdir/OWNERS
@@ -1,3 +1,4 @@
+ccross@google.com
jeffv@google.com
jiyong@google.com
smoreland@google.com
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 2e2ab74..4576776 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -11,3 +11,4 @@
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
%EXPORT_GLOBAL_ASAN_OPTIONS%
%EXPORT_GLOBAL_GCOV_OPTIONS%
+ %EXPORT_GLOBAL_HWASAN_OPTIONS%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6a6a8f9..21d234f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -336,6 +336,8 @@
start servicemanager
start hwservicemanager
start vndservicemanager
+ start vold
+ exec - system system -- /system/bin/vdc checkpoint markBootAttempt
# Once everything is setup, no need to modify /.
# The bind+remount combination allows this to work in containers.
@@ -398,6 +400,10 @@
class_start early_hal
on post-fs-data
+ # Start checkpoint before we touch data
+ start vold
+ exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint
+
# We chown/chmod /data again so because mount is run as root + defaults
chown system system /data
chmod 0771 /data
@@ -405,8 +411,6 @@
restorecon /data
# Make sure we have the device encryption key.
- start vold
- exec - system system -- /system/bin/vdc checkpoint prepareDriveForCheckpoint /data
installkey /data
# Start bootcharting as soon as possible after the data partition is
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index 17ea25b..45f1d4d 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -161,7 +161,7 @@
storaged_sp->update_uid_io_interval(time_window);
}
- return NO_ERROR;
+ return OK;
}
binder::Status StoragedService::onUserStarted(int32_t userId) {
diff --git a/storaged/uid_info.cpp b/storaged/uid_info.cpp
index 58e3fd2..0f718de 100644
--- a/storaged/uid_info.cpp
+++ b/storaged/uid_info.cpp
@@ -32,7 +32,7 @@
parcel->writeCString(task_it.second.comm.c_str());
parcel->write(&task_it.second.io, sizeof(task_it.second.io));
}
- return NO_ERROR;
+ return OK;
}
status_t UidInfo::readFromParcel(const Parcel* parcel) {
@@ -48,5 +48,5 @@
parcel->read(&task.io, sizeof(task.io));
tasks[task.pid] = task;
}
- return NO_ERROR;
+ return OK;
}