Merge "remount: Add checkpoint instructions with warning"
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index 610eebf..a4b9307 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -191,16 +191,30 @@
// Iterate over the endpoints for this interface and see if there
// are any that do bulk in/out.
- for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
+ for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; ++endpoint) {
UInt8 transferType;
- UInt16 maxPacketSize;
+ UInt16 endPointMaxPacketSize = 0;
UInt8 interval;
+
+ // Attempt to retrieve the 'true' packet-size from supported interface.
+ kr = (*interface)
+ ->GetEndpointProperties(interface, 0, endpoint,
+ kUSBOut,
+ &transferType,
+ &endPointMaxPacketSize, &interval);
+ if (kr == kIOReturnSuccess && !endPointMaxPacketSize) {
+ ERR("GetEndpointProperties() returned zero len packet-size");
+ }
+
+ UInt16 pipePropMaxPacketSize;
UInt8 number;
UInt8 direction;
+ // Proceed with extracting the transfer direction, so we can fill in the
+ // appropriate fields (bulkIn or bulkOut).
kr = (*interface)->GetPipeProperties(interface, endpoint,
&direction,
- &number, &transferType, &maxPacketSize, &interval);
+ &number, &transferType, &pipePropMaxPacketSize, &interval);
if (kr == 0) {
if (transferType != kUSBBulk) {
@@ -216,7 +230,8 @@
}
if (handle->info.ifc_protocol == 0x01) {
- handle->zero_mask = maxPacketSize - 1;
+ handle->zero_mask = (endPointMaxPacketSize == 0) ?
+ pipePropMaxPacketSize - 1 : endPointMaxPacketSize - 1;
}
} else {
ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 798bc73..c7b83a8 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -120,6 +120,12 @@
void EnqueueCompressBlocks(const void* buffer, size_t num_blocks);
bool GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf);
void Finalize();
+ static std::basic_string<uint8_t> Compress(CowCompressionAlgorithm compression,
+ const void* data, size_t length);
+
+ static bool CompressBlocks(CowCompressionAlgorithm compression, size_t block_size,
+ const void* buffer, size_t num_blocks,
+ std::vector<std::basic_string<uint8_t>>* compressed_data);
private:
struct CompressWork {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index cdff06e..9eb89b6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -395,6 +395,10 @@
// first-stage to decide whether to launch snapuserd.
bool IsSnapuserdRequired();
+ // This is primarily used to device reboot. If OTA update is in progress,
+ // init will avoid killing processes
+ bool IsUserspaceSnapshotUpdateInProgress();
+
enum class SnapshotDriver {
DM_SNAPSHOT,
DM_USER,
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
index 4d9b748..9b50986 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
@@ -32,9 +32,13 @@
namespace android {
namespace snapshot {
-
std::basic_string<uint8_t> CompressWorker::Compress(const void* data, size_t length) {
- switch (compression_) {
+ return Compress(compression_, data, length);
+}
+
+std::basic_string<uint8_t> CompressWorker::Compress(CowCompressionAlgorithm compression,
+ const void* data, size_t length) {
+ switch (compression) {
case kCowCompressGz: {
const auto bound = compressBound(length);
std::basic_string<uint8_t> buffer(bound, '\0');
@@ -94,17 +98,22 @@
return buffer;
}
default:
- LOG(ERROR) << "unhandled compression type: " << compression_;
+ LOG(ERROR) << "unhandled compression type: " << compression;
break;
}
return {};
}
-
bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks,
std::vector<std::basic_string<uint8_t>>* compressed_data) {
+ return CompressBlocks(compression_, block_size_, buffer, num_blocks, compressed_data);
+}
+
+bool CompressWorker::CompressBlocks(CowCompressionAlgorithm compression, size_t block_size,
+ const void* buffer, size_t num_blocks,
+ std::vector<std::basic_string<uint8_t>>* compressed_data) {
const uint8_t* iter = reinterpret_cast<const uint8_t*>(buffer);
while (num_blocks) {
- auto data = Compress(iter, block_size_);
+ auto data = Compress(compression, iter, block_size);
if (data.empty()) {
PLOG(ERROR) << "CompressBlocks: Compression failed";
return false;
@@ -116,7 +125,7 @@
compressed_data->emplace_back(std::move(data));
num_blocks -= 1;
- iter += block_size_;
+ iter += block_size;
}
return true;
}
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
index 2d5e4bc..3932fad 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
@@ -275,6 +275,10 @@
}
void CowWriter::InitWorkers() {
+ if (num_compress_threads_ <= 1) {
+ LOG(INFO) << "Not creating new threads for compression.";
+ return;
+ }
for (int i = 0; i < num_compress_threads_; i++) {
auto wt = std::make_unique<CompressWorker>(compression_, header_.block_size);
threads_.emplace_back(std::async(std::launch::async, &CompressWorker::RunThread, wt.get()));
@@ -447,6 +451,10 @@
size_t num_blocks_per_thread = num_blocks / num_threads;
const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
compressed_buf_.clear();
+ if (num_threads <= 1) {
+ return CompressWorker::CompressBlocks(compression_, options_.block_size, data, num_blocks,
+ &compressed_buf_);
+ }
// Submit the blocks per thread. The retrieval of
// compressed buffers has to be done in the same order.
@@ -490,13 +498,12 @@
while (num_blocks) {
size_t pending_blocks = (std::min(kProcessingBlocks, num_blocks));
- if (compression_) {
+ if (compression_ && num_compress_threads_ > 1) {
if (!CompressBlocks(pending_blocks, iter)) {
return false;
}
buf_iter_ = compressed_buf_.begin();
CHECK(pending_blocks == compressed_buf_.size());
- iter += (pending_blocks * header_.block_size);
}
num_blocks -= pending_blocks;
@@ -512,7 +519,17 @@
}
if (compression_) {
- auto data = std::move(*buf_iter_);
+ auto data = [&, this]() {
+ if (num_compress_threads_ > 1) {
+ auto data = std::move(*buf_iter_);
+ buf_iter_++;
+ return data;
+ } else {
+ auto data =
+ CompressWorker::Compress(compression_, iter, header_.block_size);
+ return data;
+ }
+ }();
op.compression = compression_;
op.data_length = static_cast<uint16_t>(data.size());
@@ -520,15 +537,14 @@
PLOG(ERROR) << "AddRawBlocks: write failed";
return false;
}
- buf_iter_++;
} else {
op.data_length = static_cast<uint16_t>(header_.block_size);
if (!WriteOperation(op, iter, header_.block_size)) {
PLOG(ERROR) << "AddRawBlocks: write failed";
return false;
}
- iter += header_.block_size;
}
+ iter += header_.block_size;
i += 1;
pending_blocks -= 1;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 6fed09c..10d2f18 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -4349,5 +4349,16 @@
return status.source_build_fingerprint();
}
+bool SnapshotManager::IsUserspaceSnapshotUpdateInProgress() {
+ auto slot = GetCurrentSlot();
+ if (slot == Slot::Target) {
+ if (IsSnapuserdRequired()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/healthd/Android.bp b/healthd/Android.bp
index a090b74..76b6ad0 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -2,17 +2,8 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_library_headers {
- name: "libhealthd_headers",
- vendor_available: true,
- recovery_available: true,
- export_include_dirs: ["include"],
- header_libs: ["libbatteryservice_headers"],
- export_header_lib_headers: ["libbatteryservice_headers"],
-}
-
-cc_library_static {
- name: "libbatterymonitor",
+cc_defaults {
+ name: "libbatterymonitor_defaults",
srcs: ["BatteryMonitor.cpp"],
cflags: ["-Wall", "-Werror"],
vendor_available: true,
@@ -25,6 +16,66 @@
// Need HealthInfo definition from headers of these shared
// libraries. Clients don't need to link to these.
"android.hardware.health@2.1",
+ ],
+ header_libs: ["libhealthd_headers"],
+ export_header_lib_headers: ["libhealthd_headers"],
+}
+
+cc_defaults {
+ name: "libhealthd_charger_ui_defaults",
+ vendor_available: true,
+ export_include_dirs: [
+ "include",
+ "include_charger",
+ ],
+
+ static_libs: [
+ "libcharger_sysprop",
+ "libhealthd_draw",
+ "libhealthloop",
+ "libminui",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libpng",
+ "libsuspend",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libhealthd_headers",
+ ],
+
+ srcs: [
+ "healthd_mode_charger.cpp",
+ "AnimationParser.cpp",
+ ],
+
+ target: {
+ vendor: {
+ exclude_static_libs: [
+ "libcharger_sysprop",
+ ],
+ },
+ },
+}
+
+cc_library_headers {
+ name: "libhealthd_headers",
+ vendor_available: true,
+ recovery_available: true,
+ export_include_dirs: ["include"],
+ header_libs: ["libbatteryservice_headers"],
+ export_header_lib_headers: ["libbatteryservice_headers"],
+}
+
+cc_library_static {
+ name: "libbatterymonitor",
+ defaults: ["libbatterymonitor_defaults"],
+ static_libs: [
"android.hardware.health-V1-ndk",
],
whole_static_libs: [
@@ -32,8 +83,20 @@
// BatteryMonitor.
"android.hardware.health-translate-ndk",
],
- header_libs: ["libhealthd_headers"],
- export_header_lib_headers: ["libhealthd_headers"],
+}
+
+// TODO(b/251425963): remove when android.hardware.health is upgraded to V2.
+cc_library_static {
+ name: "libbatterymonitor-V1",
+ defaults: ["libbatterymonitor_defaults"],
+ static_libs: [
+ "android.hardware.health-V1-ndk",
+ ],
+ whole_static_libs: [
+ // Need to translate HIDL to AIDL to support legacy APIs in
+ // BatteryMonitor.
+ "android.hardware.health-translate-V1-ndk",
+ ],
}
cc_defaults {
@@ -136,50 +199,31 @@
cc_library_static {
name: "libhealthd_charger_ui",
- vendor_available: true,
- export_include_dirs: [
- "include",
- "include_charger",
- ],
+ defaults: ["libhealthd_charger_ui_defaults"],
static_libs: [
"android.hardware.health-V1-ndk",
"android.hardware.health-translate-ndk",
- "libcharger_sysprop",
- "libhealthd_draw",
- "libhealthloop",
- "libminui",
- ],
-
- shared_libs: [
- "libbase",
- "libcutils",
- "liblog",
- "libpng",
- "libsuspend",
- "libutils",
- ],
-
- header_libs: [
- "libhealthd_headers",
],
export_static_lib_headers: [
"android.hardware.health-V1-ndk",
],
+}
- srcs: [
- "healthd_mode_charger.cpp",
- "AnimationParser.cpp",
+// TODO(b/251425963): remove when android.hardware.health is upgraded to V2.
+cc_library_static {
+ name: "libhealthd_charger_ui-V1",
+ defaults: ["libhealthd_charger_ui_defaults"],
+
+ static_libs: [
+ "android.hardware.health-V1-ndk",
+ "android.hardware.health-translate-V1-ndk",
],
- target: {
- vendor: {
- exclude_static_libs: [
- "libcharger_sysprop",
- ],
- },
- },
+ export_static_lib_headers: [
+ "android.hardware.health-V1-ndk",
+ ],
}
cc_library_static {
diff --git a/init/README.md b/init/README.md
index 957eb9e..4a5d0ec 100644
--- a/init/README.md
+++ b/init/README.md
@@ -244,6 +244,10 @@
"r", "w" or "rw". For native executables see libcutils
android\_get\_control\_file().
+`gentle_kill`
+> This service will be sent SIGTERM instead of SIGKILL when stopped. After a 200 ms timeout, it will
+ be sent SIGKILL.
+
`group <groupname> [ <groupname>\* ]`
> Change to 'groupname' before exec'ing this service. Additional
groupnames beyond the (required) first one are used to set the
diff --git a/init/apex_init_util.cpp b/init/apex_init_util.cpp
index d618a6e..c818f8f 100644
--- a/init/apex_init_util.cpp
+++ b/init/apex_init_util.cpp
@@ -18,7 +18,6 @@
#include <glob.h>
-#include <map>
#include <vector>
#include <android-base/logging.h>
@@ -66,18 +65,20 @@
}
static Result<void> ParseConfigs(const std::vector<std::string>& configs) {
- Parser parser = CreateApexConfigParser(ActionManager::GetInstance(),
- ServiceList::GetInstance());
- bool success = true;
+ Parser parser =
+ CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance());
+ std::vector<std::string> errors;
for (const auto& c : configs) {
- success &= parser.ParseConfigFile(c);
+ auto result = parser.ParseConfigFile(c);
+ // We should handle other config files even when there's an error.
+ if (!result.ok()) {
+ errors.push_back(result.error().message());
+ }
}
-
- if (success) {
- return {};
- } else {
- return Error() << "Unable to parse apex configs";
+ if (!errors.empty()) {
+ return Error() << "Unable to parse apex configs: " << base::Join(errors, "|");
}
+ return {};
}
Result<void> ParseApexConfigs(const std::string& apex_name) {
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 1ab69ac..1e69ede 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -16,6 +16,7 @@
#include <functional>
#include <string_view>
+#include <thread>
#include <type_traits>
#include <android-base/file.h>
@@ -642,6 +643,91 @@
ASSERT_LE(curr_limit.rlim_max, max_limit);
}
+static std::vector<const char*> ConvertToArgv(const std::vector<std::string>& args) {
+ std::vector<const char*> argv;
+ argv.reserve(args.size() + 1);
+ for (const auto& arg : args) {
+ if (argv.empty()) {
+ LOG(DEBUG) << arg;
+ } else {
+ LOG(DEBUG) << " " << arg;
+ }
+ argv.emplace_back(arg.data());
+ }
+ argv.emplace_back(nullptr);
+ return argv;
+}
+
+pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
+ auto argv = ConvertToArgv(args);
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ execvp(argv[0], const_cast<char**>(argv.data()));
+ PLOG(ERROR) << "exec in ForkExecvpAsync init test";
+ _exit(EXIT_FAILURE);
+ }
+ if (pid == -1) {
+ PLOG(ERROR) << "fork in ForkExecvpAsync init test";
+ return -1;
+ }
+ return pid;
+}
+
+TEST(init, GentleKill) {
+ std::string init_script = R"init(
+service test_gentle_kill /system/bin/sleep 1000
+ disabled
+ oneshot
+ gentle_kill
+ user root
+ group root
+ seclabel u:r:toolbox:s0
+)init";
+
+ ActionManager action_manager;
+ ServiceList service_list;
+ TestInitText(init_script, BuiltinFunctionMap(), {}, &action_manager, &service_list);
+ ASSERT_EQ(std::distance(service_list.begin(), service_list.end()), 1);
+
+ auto service = service_list.begin()->get();
+ ASSERT_NE(service, nullptr);
+ ASSERT_RESULT_OK(service->Start());
+ const pid_t pid = service->pid();
+ ASSERT_GT(pid, 0);
+ EXPECT_NE(getsid(pid), 0);
+
+ TemporaryFile logfile;
+ logfile.DoNotRemove();
+ ASSERT_TRUE(logfile.fd != -1);
+
+ std::vector<std::string> cmd;
+ cmd.push_back("system/bin/strace");
+ cmd.push_back("-o");
+ cmd.push_back(logfile.path);
+ cmd.push_back("-e");
+ cmd.push_back("signal");
+ cmd.push_back("-p");
+ cmd.push_back(std::to_string(pid));
+ pid_t strace_pid = ForkExecvpAsync(cmd);
+
+ // Give strace a moment to connect
+ std::this_thread::sleep_for(1s);
+ service->Stop();
+
+ int status;
+ waitpid(strace_pid, &status, 0);
+
+ std::string logs;
+ android::base::ReadFdToString(logfile.fd, &logs);
+ int pos = logs.find("killed by SIGTERM");
+ ASSERT_NE(pos, (int)std::string::npos);
+}
+
class TestCaseLogger : public ::testing::EmptyTestEventListener {
void OnTestStart(const ::testing::TestInfo& test_info) override {
#ifdef __ANDROID__
diff --git a/init/parser.cpp b/init/parser.cpp
index 0a388db..adb41ad 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -141,19 +141,19 @@
return true;
}
-bool Parser::ParseConfigFile(const std::string& path) {
+Result<void> Parser::ParseConfigFile(const std::string& path) {
LOG(INFO) << "Parsing file " << path << "...";
android::base::Timer t;
auto config_contents = ReadFile(path);
if (!config_contents.ok()) {
- LOG(INFO) << "Unable to read config file '" << path << "': " << config_contents.error();
- return false;
+ return Error() << "Unable to read config file '" << path
+ << "': " << config_contents.error();
}
ParseData(path, &config_contents.value());
LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
- return true;
+ return {};
}
bool Parser::ParseConfigDir(const std::string& path) {
@@ -176,8 +176,8 @@
// Sort first so we load files in a consistent order (bug 31996208)
std::sort(files.begin(), files.end());
for (const auto& file : files) {
- if (!ParseConfigFile(file)) {
- LOG(ERROR) << "could not import file '" << file << "'";
+ if (auto result = ParseConfigFile(file); !result.ok()) {
+ LOG(ERROR) << "could not import file '" << file << "': " << result.error();
}
}
return true;
@@ -187,7 +187,11 @@
if (is_dir(path.c_str())) {
return ParseConfigDir(path);
}
- return ParseConfigFile(path);
+ auto result = ParseConfigFile(path);
+ if (!result.ok()) {
+ LOG(INFO) << result.error();
+ }
+ return result.ok();
}
} // namespace init
diff --git a/init/parser.h b/init/parser.h
index 95b0cd7..980ae0c 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -72,7 +72,7 @@
Parser();
bool ParseConfig(const std::string& path);
- bool ParseConfigFile(const std::string& path);
+ Result<void> ParseConfigFile(const std::string& path);
void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
void AddSingleLineParser(const std::string& prefix, LineCallback callback);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index a3fc534..27a7876 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -51,6 +51,7 @@
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <fs_mgr.h>
+#include <libsnapshot/snapshot.h>
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
@@ -422,11 +423,31 @@
if (run_fsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
return UMOUNT_STAT_ERROR;
}
-
+ auto sm = snapshot::SnapshotManager::New();
+ bool ota_update_in_progress = false;
+ if (sm->IsUserspaceSnapshotUpdateInProgress()) {
+ LOG(INFO) << "OTA update in progress";
+ ota_update_in_progress = true;
+ }
UmountStat stat = UmountPartitions(timeout - t.duration());
if (stat != UMOUNT_STAT_SUCCESS) {
LOG(INFO) << "umount timeout, last resort, kill all and try";
if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
+ // Since umount timedout, we will try to kill all processes
+ // and do one more attempt to umount the partitions.
+ //
+ // However, if OTA update is in progress, we don't want
+ // to kill the snapuserd daemon as the daemon will
+ // be serving I/O requests. Killing the daemon will
+ // end up with I/O failures. If the update is in progress,
+ // we will just return the umount failure status immediately.
+ // This is ok, given the fact that killing the processes
+ // and doing an umount is just a last effort. We are
+ // still not doing fsck when all processes are killed.
+ //
+ if (ota_update_in_progress) {
+ return stat;
+ }
KillAllProcesses();
// even if it succeeds, still it is timeout and do not run fsck with all processes killed
UmountStat st = UmountPartitions(0ms);
diff --git a/init/service.cpp b/init/service.cpp
index b9b3309..87d9c3a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -26,6 +26,7 @@
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
+#include <thread>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -887,6 +888,10 @@
}
if (pid_) {
+ if (flags_ & SVC_GENTLE_KILL) {
+ KillProcessGroup(SIGTERM);
+ if (!process_cgroup_empty()) std::this_thread::sleep_for(200ms);
+ }
KillProcessGroup(SIGKILL);
NotifyStateChange("stopping");
} else {
diff --git a/init/service.h b/init/service.h
index f9749d2..3ef8902 100644
--- a/init/service.h
+++ b/init/service.h
@@ -56,6 +56,8 @@
// should not be killed during shutdown
#define SVC_TEMPORARY 0x1000 // This service was started by 'exec' and should be removed from the
// service list once it is reaped.
+#define SVC_GENTLE_KILL 0x2000 // This service should be stopped with SIGTERM instead of SIGKILL
+ // Will still be SIGKILLed after timeout period of 200 ms
#define NR_SVC_SUPP_GIDS 12 // twelve supplementary groups
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 24a2024..3563084 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -151,6 +151,11 @@
return {};
}
+Result<void> ServiceParser::ParseGentleKill(std::vector<std::string>&& args) {
+ service_->flags_ |= SVC_GENTLE_KILL;
+ return {};
+}
+
Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) {
auto gid = DecodeUid(args[1]);
if (!gid.ok()) {
@@ -584,6 +589,7 @@
{"disabled", {0, 0, &ServiceParser::ParseDisabled}},
{"enter_namespace", {2, 2, &ServiceParser::ParseEnterNamespace}},
{"file", {2, 2, &ServiceParser::ParseFile}},
+ {"gentle_kill", {0, 0, &ServiceParser::ParseGentleKill}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
{"interface", {2, 2, &ServiceParser::ParseInterface}},
{"ioprio", {2, 2, &ServiceParser::ParseIoprio}},
diff --git a/init/service_parser.h b/init/service_parser.h
index 54503dd..670a5c6 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -53,6 +53,7 @@
Result<void> ParseDisabled(std::vector<std::string>&& args);
Result<void> ParseEnterNamespace(std::vector<std::string>&& args);
Result<void> ParseGroup(std::vector<std::string>&& args);
+ Result<void> ParseGentleKill(std::vector<std::string>&& args);
Result<void> ParsePriority(std::vector<std::string>&& args);
Result<void> ParseInterface(std::vector<std::string>&& args);
Result<void> ParseIoprio(std::vector<std::string>&& args);
diff --git a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
index 3188337..6728cc6 100644
--- a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
+++ b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
@@ -60,6 +60,10 @@
if (prctl(PR_SET_TAGGED_ADDR_CTRL, res & ~PR_MTE_TCF_SYNC, 0, 0, 0) == -1) abort();
}
std::unique_ptr<volatile char[]> f(new char[1]);
+ // This out-of-bounds is on purpose: we are testing MTE, which is designed to turn
+ // out-of-bound errors into segfaults.
+ // This binary gets run by src/com/android/tests/init/MteUpgradeTest.java, which
+ // asserts that it crashes as expected.
f[17] = 'x';
char buf[1];
read(1, buf, 1);
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index bb71bf3..9a281c2 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -284,6 +284,8 @@
dsm_detect.update_mean();
dsm_detect.update_std();
+ // FixLater: avoid floating point loop counters
+ // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
for (double i = 0; i < 2 * dsm_detect.mSigma; i += 0.5) {
struct disk_perf test_perf;
struct disk_perf test_mean = dsm_detect.mMean;