Merge "Fix shutdown animation cannot be shown"
diff --git a/TEST_MAPPING b/TEST_MAPPING
deleted file mode 100644
index da7fca1..0000000
--- a/TEST_MAPPING
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "presubmit": [
- {
- "name": "adbd_test"
- },
- {
- "name": "adb_crypto_test"
- },
- {
- "name": "adb_pairing_auth_test"
- },
- {
- "name": "adb_pairing_connection_test"
- },
- {
- "name": "adb_tls_connection_test"
- },
- {
- "name": "CtsFsMgrTestCases"
- },
- {
- "name": "CtsInitTestCases"
- },
- {
- "name": "debuggerd_test"
- },
- {
- "name": "fs_mgr_vendor_overlay_test"
- },
- {
- "name": "init_kill_services_test"
- },
- {
- "name": "libpackagelistparser_test"
- },
- {
- "name": "libcutils_test"
- },
- {
- "name": "libmodprobe_tests"
- },
- {
- "name": "libprocinfo_test"
- },
- {
- "name": "libutils_test"
- },
- {
- "name": "memunreachable_test"
- },
- {
- "name": "memunreachable_unit_test"
- },
- {
- "name": "memunreachable_binder_test"
- },
- {
- "name": "propertyinfoserializer_tests"
- }
- ],
- "imports": [
- {
- "path": "frameworks/base/tests/StagedInstallTest"
- }
- ]
-}
diff --git a/debuggerd/TEST_MAPPING b/debuggerd/TEST_MAPPING
new file mode 100644
index 0000000..d5327db
--- /dev/null
+++ b/debuggerd/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "debuggerd_test"
+ }
+ ]
+}
diff --git a/fastboot/README.md b/fastboot/README.md
index c224448..d3b6c1a 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -27,16 +27,16 @@
1. Host sends a command, which is an ascii string in a single
packet no greater than 64 bytes.
-2. Client response with a single packet no greater than 64 bytes.
+2. Client response with a single packet no greater than 256 bytes.
The first four bytes of the response are "OKAY", "FAIL", "DATA",
or "INFO". Additional bytes may contain an (ascii) informative
message.
- a. INFO -> the remaining 60 bytes are an informative message
+ a. INFO -> the remaining 252 bytes are an informative message
(providing progress or diagnostic messages). They should
be displayed and then step #2 repeats
- b. FAIL -> the requested command failed. The remaining 60 bytes
+ b. FAIL -> the requested command failed. The remaining 252 bytes
of the response (if present) provide a textual failure message
to present to the user. Stop.
@@ -53,13 +53,13 @@
until the client has sent or received the number of bytes indicated
in the "DATA" response above.
-4. Client responds with a single packet no greater than 64 bytes.
+4. Client responds with a single packet no greater than 256 bytes.
The first four bytes of the response are "OKAY", "FAIL", or "INFO".
Similar to #2:
- a. INFO -> display the remaining 60 bytes and return to #4
+ a. INFO -> display the remaining 252 bytes and return to #4
- b. FAIL -> display the remaining 60 bytes (if present) as a failure
+ b. FAIL -> display the remaining 252 bytes (if present) as a failure
reason and consider the command failed. Stop.
c. OKAY -> success. Go to #5
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index 5a14b63..3096905 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -28,6 +28,10 @@
#include "socket.h"
+#ifndef _WIN32
+#include <sys/select.h>
+#endif
+
#include <android-base/errors.h>
#include <android-base/stringprintf.h>
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index d4fc2b9..7ae526f 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -65,6 +65,7 @@
"-D_FILE_OFFSET_BITS=64",
],
srcs: [
+ "blockdev.cpp",
"file_wait.cpp",
"fs_mgr.cpp",
"fs_mgr_format.cpp",
@@ -126,10 +127,19 @@
export_header_lib_headers: [
"libfiemap_headers",
],
- required: [
- "e2freefrag",
- "e2fsdroid",
- ],
+ target: {
+ platform: {
+ required: [
+ "e2freefrag",
+ "e2fsdroid",
+ ],
+ },
+ recovery: {
+ required: [
+ "e2fsdroid.recovery",
+ ],
+ },
+ },
}
// Two variants of libfs_mgr are provided: libfs_mgr and libfs_mgr_binder.
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 84709b6..432aa4f 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -1,6 +1,9 @@
{
"presubmit": [
{
+ "name": "CtsFsMgrTestCases"
+ },
+ {
"name": "libdm_test"
},
{
@@ -13,6 +16,9 @@
"name": "fiemap_writer_test"
},
{
+ "name": "fs_mgr_vendor_overlay_test"
+ },
+ {
"name": "vts_libsnapshot_test"
},
{
diff --git a/fs_mgr/blockdev.cpp b/fs_mgr/blockdev.cpp
new file mode 100644
index 0000000..14b217c
--- /dev/null
+++ b/fs_mgr/blockdev.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 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 <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include <dirent.h>
+#include <libdm/dm.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include "blockdev.h"
+
+using android::base::Basename;
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+using android::base::ResultError;
+using android::base::StartsWith;
+using android::base::StringPrintf;
+using android::base::unique_fd;
+using android::dm::DeviceMapper;
+
+// Return the parent device of a partition. Converts e.g. "sda26" into "sda".
+static std::string PartitionParent(const std::string& blockdev) {
+ if (blockdev.find('/') != std::string::npos) {
+ LOG(ERROR) << __func__ << ": invalid argument " << blockdev;
+ return blockdev;
+ }
+ auto dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/sys/class/block"), closedir};
+ if (!dir) {
+ return blockdev;
+ }
+ for (struct dirent* ent = readdir(dir.get()); ent; ent = readdir(dir.get())) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+ std::string path = StringPrintf("/sys/class/block/%s/%s", ent->d_name, blockdev.c_str());
+ struct stat statbuf;
+ if (stat(path.c_str(), &statbuf) >= 0) {
+ return ent->d_name;
+ }
+ }
+ return blockdev;
+}
+
+// Convert a major:minor pair into a block device name.
+static std::string BlockdevName(dev_t dev) {
+ auto dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/dev/block"), closedir};
+ if (!dir) {
+ return {};
+ }
+ for (struct dirent* ent = readdir(dir.get()); ent; ent = readdir(dir.get())) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+ const std::string path = std::string("/dev/block/") + ent->d_name;
+ struct stat statbuf;
+ if (stat(path.c_str(), &statbuf) >= 0 && dev == statbuf.st_rdev) {
+ return ent->d_name;
+ }
+ }
+ return {};
+}
+
+// Trim whitespace from the end of a string.
+static void rtrim(std::string& s) {
+ s.erase(s.find_last_not_of('\n') + 1, s.length());
+}
+
+// For file `file_path`, retrieve the block device backing the filesystem on
+// which the file exists and return the queue depth of the block device.
+static Result<uint32_t> BlockDeviceQueueDepth(const std::string& file_path) {
+ struct stat statbuf;
+ int res = stat(file_path.c_str(), &statbuf);
+ if (res < 0) {
+ return ErrnoError() << "stat(" << file_path << ")";
+ }
+ std::string blockdev = "/dev/block/" + BlockdevName(statbuf.st_dev);
+ LOG(DEBUG) << __func__ << ": " << file_path << " -> " << blockdev;
+ if (blockdev.empty()) {
+ const std::string err_msg =
+ StringPrintf("Failed to convert %u:%u (path %s)", major(statbuf.st_dev),
+ minor(statbuf.st_dev), file_path.c_str());
+ return ResultError(err_msg, 0);
+ }
+ auto& dm = DeviceMapper::Instance();
+ for (;;) {
+ std::optional<std::string> child = dm.GetParentBlockDeviceByPath(blockdev);
+ if (!child) {
+ break;
+ }
+ LOG(DEBUG) << __func__ << ": " << blockdev << " -> " << *child;
+ blockdev = *child;
+ }
+ std::optional<std::string> maybe_blockdev = android::dm::ExtractBlockDeviceName(blockdev);
+ if (!maybe_blockdev) {
+ return ResultError("Failed to remove /dev/block/ prefix from " + blockdev, 0);
+ }
+ blockdev = PartitionParent(*maybe_blockdev);
+ LOG(DEBUG) << __func__ << ": "
+ << "Partition parent: " << blockdev;
+ const std::string nr_tags_path =
+ StringPrintf("/sys/class/block/%s/mq/0/nr_tags", blockdev.c_str());
+ std::string nr_tags;
+ if (!android::base::ReadFileToString(nr_tags_path, &nr_tags)) {
+ return ResultError("Failed to read " + nr_tags_path, 0);
+ }
+ rtrim(nr_tags);
+ LOG(DEBUG) << __func__ << ": " << file_path << " is backed by /dev/" << blockdev
+ << " and that block device supports queue depth " << nr_tags;
+ return strtol(nr_tags.c_str(), NULL, 0);
+}
+
+// Set 'nr_requests' of `loop_device_path` to the queue depth of the block
+// device backing `file_path`.
+Result<void> ConfigureQueueDepth(const std::string& loop_device_path,
+ const std::string& file_path) {
+ if (!StartsWith(loop_device_path, "/dev/")) {
+ return Error() << "Invalid argument " << loop_device_path;
+ }
+
+ const std::string loop_device_name = Basename(loop_device_path);
+
+ const Result<uint32_t> qd = BlockDeviceQueueDepth(file_path);
+ if (!qd.ok()) {
+ LOG(DEBUG) << __func__ << ": "
+ << "BlockDeviceQueueDepth() returned " << qd.error();
+ return ResultError(qd.error());
+ }
+ const std::string nr_requests = StringPrintf("%u", *qd);
+ const std::string sysfs_path =
+ StringPrintf("/sys/class/block/%s/queue/nr_requests", loop_device_name.c_str());
+ unique_fd sysfs_fd(open(sysfs_path.c_str(), O_RDWR | O_CLOEXEC));
+ if (sysfs_fd == -1) {
+ return ErrnoError() << "Failed to open " << sysfs_path;
+ }
+
+ const int res = write(sysfs_fd.get(), nr_requests.data(), nr_requests.length());
+ if (res < 0) {
+ return ErrnoError() << "Failed to write to " << sysfs_path;
+ }
+ return {};
+}
diff --git a/fs_mgr/blockdev.h b/fs_mgr/blockdev.h
new file mode 100644
index 0000000..2c0d68a
--- /dev/null
+++ b/fs_mgr/blockdev.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2021 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 <android-base/result.h>
+#include <string>
+
+android::base::Result<void> ConfigureQueueDepth(const std::string& loop_device_path,
+ const std::string& file_path);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index ec66144..5f15aad 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -72,6 +72,7 @@
#include <log/log_properties.h>
#include <logwrap/logwrap.h>
+#include "blockdev.h"
#include "fs_mgr_priv.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
@@ -2110,6 +2111,8 @@
ConfigureIoScheduler(loop_device);
+ ConfigureQueueDepth(loop_device, "/");
+
// set block size & direct IO
unique_fd loop_fd(TEMP_FAILURE_RETRY(open(loop_device.c_str(), O_RDWR | O_CLOEXEC)));
if (loop_fd.get() == -1) {
diff --git a/fs_mgr/fs_mgr_roots.cpp b/fs_mgr/fs_mgr_roots.cpp
index fdaffbe..d275320 100644
--- a/fs_mgr/fs_mgr_roots.cpp
+++ b/fs_mgr/fs_mgr_roots.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "android-base/file.h"
#include "fs_mgr/roots.h"
#include <sys/mount.h>
@@ -39,18 +40,26 @@
while (true) {
auto entry = GetEntryForMountPoint(fstab, str);
if (entry != nullptr) return entry;
- if (str == "/") break;
- auto slash = str.find_last_of('/');
- if (slash == std::string::npos) break;
- if (slash == 0) {
- str = "/";
- } else {
- str = str.substr(0, slash);
- }
+ str = android::base::Dirname(str);
+ if (!str.compare(".") || !str.compare("/")) break;
}
return nullptr;
}
+std::vector<FstabEntry*> GetEntriesForPath(Fstab* fstab, const std::string& path) {
+ std::vector<FstabEntry*> entries;
+ if (path.empty()) return entries;
+
+ std::string str(path);
+ while (true) {
+ entries = GetEntriesForMountPoint(fstab, str);
+ if (!entries.empty()) return entries;
+ str = android::base::Dirname(str);
+ if (!str.compare(".") || !str.compare("/")) break;
+ }
+ return entries;
+}
+
enum class MountState {
ERROR = -1,
NOT_MOUNTED = 0,
@@ -71,12 +80,7 @@
return MountState::NOT_MOUNTED;
}
-bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_pt) {
- auto rec = GetEntryForPath(fstab, path);
- if (rec == nullptr) {
- LERROR << "unknown volume for path [" << path << "]";
- return false;
- }
+bool TryPathMount(FstabEntry* rec, const std::string& mount_pt) {
if (rec->fs_type == "ramdisk") {
// The ramdisk is always mounted.
return true;
@@ -136,6 +140,21 @@
return true;
}
+bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_point) {
+ auto entries = GetEntriesForPath(fstab, path);
+ if (entries.empty()) {
+ LERROR << "unknown volume for path [" << path << "]";
+ return false;
+ }
+
+ for (auto entry : entries) {
+ if (TryPathMount(entry, mount_point)) return true;
+ }
+
+ LERROR << "Failed to mount for path [" << path << "]";
+ return false;
+}
+
bool EnsurePathUnmounted(Fstab* fstab, const std::string& path) {
auto rec = GetEntryForPath(fstab, path);
if (rec == nullptr) {
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 8e3d5a5..4034e30 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -578,34 +578,30 @@
return std::string{spec.target_type, sizeof(spec.target_type)};
}
-static bool ExtractBlockDeviceName(const std::string& path, std::string* name) {
+std::optional<std::string> ExtractBlockDeviceName(const std::string& path) {
static constexpr std::string_view kDevBlockPrefix("/dev/block/");
if (android::base::StartsWith(path, kDevBlockPrefix)) {
- *name = path.substr(kDevBlockPrefix.length());
- return true;
+ return path.substr(kDevBlockPrefix.length());
}
- return false;
+ return {};
}
bool DeviceMapper::IsDmBlockDevice(const std::string& path) {
- std::string name;
- if (!ExtractBlockDeviceName(path, &name)) {
- return false;
- }
- return android::base::StartsWith(name, "dm-");
+ std::optional<std::string> name = ExtractBlockDeviceName(path);
+ return name && android::base::StartsWith(*name, "dm-");
}
std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string& path) {
- std::string name;
- if (!ExtractBlockDeviceName(path, &name)) {
+ std::optional<std::string> name = ExtractBlockDeviceName(path);
+ if (!name) {
LOG(WARNING) << path << " is not a block device";
return std::nullopt;
}
- if (!android::base::StartsWith(name, "dm-")) {
+ if (!android::base::StartsWith(*name, "dm-")) {
LOG(WARNING) << path << " is not a dm device";
return std::nullopt;
}
- std::string dm_name_file = "/sys/block/" + name + "/dm/name";
+ std::string dm_name_file = "/sys/block/" + *name + "/dm/name";
std::string dm_name;
if (!android::base::ReadFileToString(dm_name_file, &dm_name)) {
PLOG(ERROR) << "Failed to read file " << dm_name_file;
@@ -616,16 +612,16 @@
}
std::optional<std::string> DeviceMapper::GetParentBlockDeviceByPath(const std::string& path) {
- std::string name;
- if (!ExtractBlockDeviceName(path, &name)) {
+ std::optional<std::string> name = ExtractBlockDeviceName(path);
+ if (!name) {
LOG(WARNING) << path << " is not a block device";
return std::nullopt;
}
- if (!android::base::StartsWith(name, "dm-")) {
+ if (!android::base::StartsWith(*name, "dm-")) {
// Reached bottom of the device mapper stack.
return std::nullopt;
}
- auto slaves_dir = "/sys/block/" + name + "/slaves";
+ auto slaves_dir = "/sys/block/" + *name + "/slaves";
auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(slaves_dir.c_str()), closedir);
if (dir == nullptr) {
PLOG(ERROR) << "Failed to open: " << slaves_dir;
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 31c3003..7e01b85 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -51,6 +51,10 @@
static constexpr uint64_t kSectorSize = 512;
+// Returns `path` without /dev/block prefix if and only if `path` starts with
+// that prefix.
+std::optional<std::string> ExtractBlockDeviceName(const std::string& path);
+
class DeviceMapper final {
public:
class DmBlockDevice final {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
index 0457986..3655c01 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
@@ -36,6 +36,8 @@
MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t), (override));
MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
+ MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t),
+ (override));
MOCK_METHOD(bool, EmitZeroBlocks, (uint64_t, uint64_t), (override));
MOCK_METHOD(bool, EmitLabel, (uint64_t), (override));
MOCK_METHOD(bool, EmitSequenceData, (size_t, const uint32_t*), (override));
diff --git a/init/Android.bp b/init/Android.bp
index a04d2db..5d09687 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -236,6 +236,7 @@
"init.rc",
"ueventd.rc",
"e2fsdroid",
+ "extra_free_kbytes.sh",
"make_f2fs",
"mke2fs",
"sload_f2fs",
@@ -552,3 +553,8 @@
},
},
}
+
+sh_binary {
+ name: "extra_free_kbytes.sh",
+ src: "extra_free_kbytes.sh",
+}
diff --git a/init/TEST_MAPPING b/init/TEST_MAPPING
new file mode 100644
index 0000000..905d41e
--- /dev/null
+++ b/init/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsInitTestCases"
+ },
+ {
+ "name": "init_kill_services_test"
+ }
+ ]
+}
diff --git a/init/extra_free_kbytes.sh b/init/extra_free_kbytes.sh
new file mode 100755
index 0000000..aeaa912
--- /dev/null
+++ b/init/extra_free_kbytes.sh
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+# Script implements watermark_scale calculation which results in the same low
+# watermark as if extra_free_kbytes tunable were to be used.
+#
+# Usage: extra_free_kbytes.sh <extra_free_kbytes value>
+#
+# extra_free_kbytes is distributed between zones based on
+# zone.managed_pages/vm_total_pages ratio, where vm_total_pages is the sum of
+# zone.managed_pages for all zones (zone.high used in this calculation is 0
+# when this is calculated). Therefore for each zone its share is calculated as:
+#
+# extra_free_pages = extra_free_kbytes / page_size
+# extra_share = extra_free_pages * managed_pages / vm_total_pages
+#
+# This extra_share is added to the low and high watermarks:
+#
+# low = min + max(min / 4, managed_pages * (watermark_scale / 10000)) + extra_share
+# high = min + 2 * max(min / 4, managed_pages * (watermark_scale / 10000)) + extra_share
+#
+# Because Android uses extra_free_kbytes to adjust the low watermark, we ignore
+# the difference in how watermark_scale and extra_free_kbytes affect the high
+# watermark and will match the low watermark only.
+#
+# To eliminate extra_share and compansate the difference with watermark_scale,
+# a new watermark_scale_new is calculated as:
+#
+# (1) max(min / 4, managed_pages * (watermark_scale / 10000)) + extra_share =
+# max(min / 4, managed_pages * (watermark_scale_new / 10000))
+#
+# Two cases to consider:
+# A. managed_pages * (watermark_scale / 10000) > min / 4
+# The formula (1) becomes:
+#
+# managed_pages * (watermark_scale / 10000) + extra_share =
+# managed_pages * (watermark_scale_new / 10000)
+#
+# after simplifying and substituting extra_share formula becomes:
+#
+# (2) watermark_scale_new = watermark_scale + extra_free_pages / vm_total_pages * 10000
+#
+# B. managed_pages * (watermark_scale / 10000) < min / 4
+# The formula (1) becomes:
+#
+# min / 4 + extra_share = max(min / 4, managed_pages * (watermark_scale_new / 10000))
+#
+# after calculating watermark_scale_new, if (managed_pages * (watermark_scale_new / 10000))
+# is still smaller than min / 4 then we can't compensate extra_share with
+# watermark_scale anyway. Therefore calculation becomes:
+#
+# watermark_scale_new = (min / 4 + extra_share) / managed_pages * 10000
+#
+# after simplifying and substituting extra_share formula becomes:
+#
+# (3) watermark_scale_new = (min / 4) * 10000 / managed_pages + extra_free_pages / vm_total_pages * 10000
+#
+# After defining watermark_delta = extra_free_pages / vm_total_pages * 10000:
+#
+# if (managed_pages * (watermark_scale / 10000) > min / 4)
+# watermark_scale_new = watermark_scale + watermark_delta
+# else
+# watermark_scale_new = (min / 4) * 10000 / managed_pages + watermark_delta
+#
+
+if [ "$#" -ne 1 ]
+then
+ echo "Usage: $0 <extra_free_kbytes value>"
+ exit
+fi
+
+extra_free_kbytes=$1
+
+# if extra_free_kbytes knob exists, use it and exit
+if [ -e /proc/sys/vm/extra_free_kbytes ]
+then
+ echo $extra_free_kbytes > /proc/sys/vm/extra_free_kbytes
+ exit
+fi
+
+watermark_scale=`cat /proc/sys/vm/watermark_scale_factor`
+
+# convert extra_free_kbytes to pages
+page_size=$(getconf PAGESIZE)
+page_size_kb=$((page_size/1024))
+extra_free_pg=$((extra_free_kbytes/page_size_kb))
+
+managed=($(grep managed /proc/zoneinfo | awk '{print $2}'))
+length=${#managed[@]}
+min=($(grep "min" /proc/zoneinfo | awk '{print $2}'))
+
+# calculate vm_total_pages.
+# WARNING: if the final low watermark differs from the original, the source of
+# the error is likely vm_total_pages which is impossible to get exact from the
+# userspace. Grep for "Total pages" in the kernel logs to see the actual
+# vm_total_pages and plug it in the calculation to confirm the source of the
+# error. Error caused by this inaccuracy is normally within 1% range.
+vm_total_pages=0
+i=0
+while [ $i -lt $length ]
+do
+ vm_total_pages=$((vm_total_pages + managed[i]))
+ i=$((i+1))
+done
+
+# calculate watermark_scale_new for each zone and choose the max
+max_watermark_scale=0
+i=0
+while [ $i -lt $length ]
+do
+ # skip unmanaged zones
+ if [ ${managed[i]} -eq 0 ]
+ then
+ i=$((i+1))
+ continue
+ fi
+
+ base_margin=$((min[i] / 4))
+ calc_margin=$(echo "${managed[i]} * $watermark_scale / 10000" | bc)
+ # round the value by adding 0.5 and truncating the decimal part
+ watermark_delta=$(echo "x=($extra_free_pg / ($vm_total_pages / 10000) + 0.5); scale = 0; x/1" | bc -l)
+ if [ $calc_margin -gt $base_margin ]
+ then
+ watermark_scale_new=$(echo "$watermark_scale + $watermark_delta" | bc)
+ else
+ watermark_scale_new=$(echo "$base_margin / (${managed[i]} / 10000) + $watermark_delta" | bc)
+ fi
+
+ if [ $max_watermark_scale -lt $watermark_scale_new ]
+ then
+ max_watermark_scale=$watermark_scale_new
+ fi
+
+ i=$((i+1))
+done
+
+echo $max_watermark_scale > /proc/sys/vm/watermark_scale_factor
diff --git a/init/host_builtin_map.py b/init/host_builtin_map.py
index 6afcb17..41c86ac 100755
--- a/init/host_builtin_map.py
+++ b/init/host_builtin_map.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""Generates the builtins map to be used by host_init_verifier.
It copies the builtin function map from builtins.cpp, then replaces do_xxx() functions with the
@@ -39,8 +39,7 @@
match = DO_REGEX.match(line)
if match:
if match.group(1) in check_functions:
- print line.replace('do_', 'check_'),
+ line = line.replace('do_', 'check_')
else:
- print FUNCTION_REGEX.sub('check_stub', line),
- else:
- print line,
+ line = FUNCTION_REGEX.sub('check_stub', line)
+ print(line, end=' ')
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 593913b..1681627 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -1037,6 +1037,20 @@
return;
}
}
+ } else if (reboot_target == "quiescent") {
+ bootloader_message boot = {};
+ if (std::string err; !read_bootloader_message(&boot, &err)) {
+ LOG(ERROR) << "Failed to read bootloader message: " << err;
+ }
+ // Update the boot command field if it's empty, and preserve
+ // the other arguments in the bootloader message.
+ if (!CommandIsPresent(&boot)) {
+ strlcpy(boot.command, "boot-quiescent", sizeof(boot.command));
+ if (std::string err; !write_bootloader_message(boot, &err)) {
+ LOG(ERROR) << "Failed to set bootloader message: " << err;
+ return;
+ }
+ }
} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
reboot_target == "fastboot") {
std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
diff --git a/libcutils/TEST_MAPPING b/libcutils/TEST_MAPPING
new file mode 100644
index 0000000..e512ab7
--- /dev/null
+++ b/libcutils/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libcutils_test"
+ }
+ ]
+}
diff --git a/libmodprobe/TEST_MAPPING b/libmodprobe/TEST_MAPPING
new file mode 100644
index 0000000..526b1e4
--- /dev/null
+++ b/libmodprobe/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libmodprobe_tests"
+ }
+ ]
+}
diff --git a/libpackagelistparser/TEST_MAPPING b/libpackagelistparser/TEST_MAPPING
new file mode 100644
index 0000000..51773f9
--- /dev/null
+++ b/libpackagelistparser/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libpackagelistparser_test"
+ }
+ ]
+}
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 0b4b640..3f9aeb2 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -85,11 +85,11 @@
srcs: ["simg_dump.py"],
version: {
py2: {
- embedded_launcher: true,
- enabled: true,
+ enabled: false,
},
py3: {
- enabled: false,
+ embedded_launcher: true,
+ enabled: true,
},
},
}
diff --git a/libsparse/simg_dump.py b/libsparse/simg_dump.py
index 82a03ad..b0b3b22 100755
--- a/libsparse/simg_dump.py
+++ b/libsparse/simg_dump.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
# Copyright (C) 2012 The Android Open Source Project
#
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import print_function
import csv
import getopt
import hashlib
@@ -47,7 +46,7 @@
opts, args = getopt.getopt(sys.argv[1:],
"vsc:",
["verbose", "showhash", "csvfile"])
- except getopt.GetoptError, e:
+ except getopt.GetoptError as e:
print(e)
usage(me)
for o, a in opts:
diff --git a/libutils/TEST_MAPPING b/libutils/TEST_MAPPING
new file mode 100644
index 0000000..c8ef45c
--- /dev/null
+++ b/libutils/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libutils_test"
+ }
+ ]
+}
diff --git a/property_service/TEST_MAPPING b/property_service/TEST_MAPPING
new file mode 100644
index 0000000..fcdc86a
--- /dev/null
+++ b/property_service/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "propertyinfoserializer_tests"
+ }
+ ]
+}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ab0aff5..9371617 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1138,7 +1138,7 @@
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
- write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
+ exec -- /system/bin/extra_free_kbytes.sh ${sys.sysctl.extra_free_kbytes}
# Allow users to drop caches
on property:perf.drop_caches=3
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
index c0e9fce..20db638 100755
--- a/toolbox/generate-input.h-labels.py
+++ b/toolbox/generate-input.h-labels.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (C) 2015 The Android Open Source Project
#
@@ -16,7 +16,7 @@
#
# pylint: disable=bad-indentation,bad-continuation
-from __future__ import print_function
+
import os
import re
import sys
diff --git a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
index 0956fe6..2d44009 100644
--- a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
@@ -25,6 +25,8 @@
#include <unistd.h>
#include <algorithm>
+#include <variant>
+#include <vector>
#include <log/log.h>
#include <trusty/tipc.h>
@@ -46,8 +48,27 @@
return 0;
}
-int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
- uint32_t* out_size) {
+class VectorEraser {
+ public:
+ VectorEraser(std::vector<uint8_t>* v) : _v(v) {}
+ ~VectorEraser() {
+ if (_v) {
+ std::fill(const_cast<volatile uint8_t*>(_v->data()),
+ const_cast<volatile uint8_t*>(_v->data() + _v->size()), 0);
+ }
+ }
+ void disarm() { _v = nullptr; }
+ VectorEraser(const VectorEraser&) = delete;
+ VectorEraser& operator=(const VectorEraser&) = delete;
+ VectorEraser(VectorEraser&& other) = delete;
+ VectorEraser& operator=(VectorEraser&&) = delete;
+
+ private:
+ std::vector<uint8_t>* _v;
+};
+
+std::variant<int, std::vector<uint8_t>> trusty_keymaster_call_2(uint32_t cmd, void* in,
+ uint32_t in_size) {
if (handle_ < 0) {
ALOGE("not connected\n");
return -EINVAL;
@@ -70,15 +91,38 @@
ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
return -errno;
}
- size_t out_max_size = *out_size;
- *out_size = 0;
+
+ std::vector<uint8_t> out(TRUSTY_KEYMASTER_RECV_BUF_SIZE);
+ VectorEraser out_eraser(&out);
+ uint8_t* write_pos = out.data();
+ uint8_t* out_end = out.data() + out.size();
+
struct iovec iov[2];
struct keymaster_message header;
iov[0] = {.iov_base = &header, .iov_len = sizeof(struct keymaster_message)};
while (true) {
- iov[1] = {.iov_base = out + *out_size,
- .iov_len = std::min<uint32_t>(KEYMASTER_MAX_BUFFER_LENGTH,
- out_max_size - *out_size)};
+ if (out_end - write_pos < KEYMASTER_MAX_BUFFER_LENGTH) {
+ // In stead of using std::vector.resize(), allocate a new one to have chance
+ // at zeroing the old buffer.
+ std::vector<uint8_t> new_out(out.size() + KEYMASTER_MAX_BUFFER_LENGTH);
+ // After the swap below this erases the old out buffer.
+ VectorEraser new_out_eraser(&new_out);
+ std::copy(out.data(), write_pos, new_out.begin());
+
+ auto write_offset = write_pos - out.data();
+
+ std::swap(new_out, out);
+
+ write_pos = out.data() + write_offset;
+ out_end = out.data() + out.size();
+ }
+ size_t buffer_size = 0;
+ if (__builtin_sub_overflow(reinterpret_cast<uintptr_t>(out_end),
+ reinterpret_cast<uintptr_t>(write_pos), &buffer_size)) {
+ return -EOVERFLOW;
+ }
+ iov[1] = {.iov_base = write_pos, .iov_len = buffer_size};
+
rc = readv(handle_, iov, 2);
if (rc < 0) {
ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
@@ -95,13 +139,36 @@
ALOGE("invalid command (%d)", header.cmd);
return -EINVAL;
}
- *out_size += ((size_t)rc - sizeof(struct keymaster_message));
+ write_pos += ((size_t)rc - sizeof(struct keymaster_message));
if (header.cmd & KEYMASTER_STOP_BIT) {
break;
}
}
- return rc;
+ out.resize(write_pos - out.data());
+ out_eraser.disarm();
+ return out;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size) {
+ auto result = trusty_keymaster_call_2(cmd, in, in_size);
+ if (auto out_buffer = std::get_if<std::vector<uint8_t>>(&result)) {
+ if (out_buffer->size() <= *out_size) {
+ std::copy(out_buffer->begin(), out_buffer->end(), out);
+ std::fill(const_cast<volatile uint8_t*>(&*out_buffer->begin()),
+ const_cast<volatile uint8_t*>(&*out_buffer->end()), 0);
+
+ *out_size = out_buffer->size();
+ return 0;
+ } else {
+ ALOGE("Message was to large (%zu) for the provided buffer (%u)", out_buffer->size(),
+ *out_size);
+ return -EMSGSIZE;
+ }
+ } else {
+ return std::get<int>(result);
+ }
}
void trusty_keymaster_disconnect() {
@@ -155,28 +222,27 @@
req.Serialize(send_buf, send_buf + req_size);
// Send it
- uint8_t recv_buf[TRUSTY_KEYMASTER_RECV_BUF_SIZE];
- keymaster::Eraser recv_buf_eraser(recv_buf, TRUSTY_KEYMASTER_RECV_BUF_SIZE);
- uint32_t rsp_size = TRUSTY_KEYMASTER_RECV_BUF_SIZE;
- int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
- if (rc < 0) {
+ auto response = trusty_keymaster_call_2(command, send_buf, req_size);
+ if (auto response_buffer = std::get_if<std::vector<uint8_t>>(&response)) {
+ keymaster::Eraser response_buffer_erasor(response_buffer->data(), response_buffer->size());
+ ALOGV("Received %zu byte response\n", response_buffer->size());
+
+ const uint8_t* p = response_buffer->data();
+ if (!rsp->Deserialize(&p, p + response_buffer->size())) {
+ ALOGE("Error deserializing response of size %zu\n", response_buffer->size());
+ return KM_ERROR_UNKNOWN_ERROR;
+ } else if (rsp->error != KM_ERROR_OK) {
+ ALOGE("Response of size %zu contained error code %d\n", response_buffer->size(),
+ (int)rsp->error);
+ }
+ return rsp->error;
+ } else {
+ auto rc = std::get<int>(response);
// Reset the connection on tipc error
trusty_keymaster_disconnect();
trusty_keymaster_connect();
ALOGE("tipc error: %d\n", rc);
// TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
return translate_error(rc);
- } else {
- ALOGV("Received %d byte response\n", rsp_size);
}
-
- const uint8_t* p = recv_buf;
- if (!rsp->Deserialize(&p, p + rsp_size)) {
- ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
- return KM_ERROR_UNKNOWN_ERROR;
- } else if (rsp->error != KM_ERROR_OK) {
- ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
- return rsp->error;
- }
- return rsp->error;
}