Merge changes from topic 'exec-start-update-verifier'
* changes:
init.rc: launch update_verifier with exec_start
init: add exec_start command
diff --git a/.clang-format-2 b/.clang-format-2
index aab4665..41591ce 100644
--- a/.clang-format-2
+++ b/.clang-format-2
@@ -1,4 +1,5 @@
BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
diff --git a/.clang-format-4 b/.clang-format-4
index 1497447..ae4a451 100644
--- a/.clang-format-4
+++ b/.clang-format-4
@@ -1,5 +1,6 @@
BasedOnStyle: Google
AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4de5e57..041586c 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -62,15 +62,14 @@
// Waits for the system property `key` to have the value `expected_value`.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
-bool WaitForProperty(const std::string& key,
- const std::string& expected_value,
- std::chrono::milliseconds relative_timeout);
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
+ std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
// Waits for the system property `key` to be created.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
-bool WaitForPropertyCreation(const std::string& key,
- std::chrono::milliseconds relative_timeout);
+bool WaitForPropertyCreation(const std::string& key, std::chrono::milliseconds relative_timeout =
+ std::chrono::milliseconds::max());
} // namespace base
} // namespace android
diff --git a/base/properties.cpp b/base/properties.cpp
index 32c0128..816bca0 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -101,22 +101,24 @@
}
// TODO: chrono_utils?
-static void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
+static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
ts.tv_sec = s.count();
ts.tv_nsec = ns.count();
}
+// TODO: boot_clock?
using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
-static void UpdateTimeSpec(timespec& ts,
- const AbsTime& timeout) {
+static void UpdateTimeSpec(timespec& ts, std::chrono::milliseconds relative_timeout,
+ const AbsTime& start_time) {
auto now = std::chrono::steady_clock::now();
- auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
- if (remaining_timeout < 0ns) {
+ auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ if (time_elapsed >= relative_timeout) {
ts = { 0, 0 };
} else {
+ auto remaining_timeout = relative_timeout - time_elapsed;
DurationToTimeSpec(ts, remaining_timeout);
}
}
@@ -127,11 +129,7 @@
// Returns nullptr on timeout.
static const prop_info* WaitForPropertyCreation(const std::string& key,
const std::chrono::milliseconds& relative_timeout,
- AbsTime& absolute_timeout) {
- // TODO: boot_clock?
- auto now = std::chrono::steady_clock::now();
- absolute_timeout = now + relative_timeout;
-
+ const AbsTime& start_time) {
// Find the property's prop_info*.
const prop_info* pi;
unsigned global_serial = 0;
@@ -139,17 +137,16 @@
// The property doesn't even exist yet.
// Wait for a global change and then look again.
timespec ts;
- UpdateTimeSpec(ts, absolute_timeout);
+ UpdateTimeSpec(ts, relative_timeout, start_time);
if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
}
return pi;
}
-bool WaitForProperty(const std::string& key,
- const std::string& expected_value,
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
std::chrono::milliseconds relative_timeout) {
- AbsTime absolute_timeout;
- const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
+ auto start_time = std::chrono::steady_clock::now();
+ const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, start_time);
if (pi == nullptr) return false;
WaitForPropertyData data;
@@ -162,7 +159,7 @@
if (data.done) return true;
// It didn't, so wait for the property to change before checking again.
- UpdateTimeSpec(ts, absolute_timeout);
+ UpdateTimeSpec(ts, relative_timeout, start_time);
uint32_t unused;
if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
}
@@ -170,8 +167,8 @@
bool WaitForPropertyCreation(const std::string& key,
std::chrono::milliseconds relative_timeout) {
- AbsTime absolute_timeout;
- return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
+ auto start_time = std::chrono::steady_clock::now();
+ return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
}
} // namespace base
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index 1bbe482..de5f3dc 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -151,6 +151,38 @@
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
}
+TEST(properties, WaitForProperty_MaxTimeout) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ std::this_thread::sleep_for(500ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+ flag = true;
+ // Test that this does not immediately return false due to overflow issues with the timeout.
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b"));
+ thread.join();
+}
+
+TEST(properties, WaitForProperty_NegativeTimeout) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ std::this_thread::sleep_for(500ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+ flag = true;
+ // Assert that this immediately returns with a negative timeout
+ ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms));
+ thread.join();
+}
+
TEST(properties, WaitForPropertyCreation) {
std::thread thread([&]() {
std::this_thread::sleep_for(100ms);
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 2d6c7f5..024bc3d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -161,6 +161,7 @@
target: {
android: {
srcs: [
+ "client/debuggerd_client_test.cpp",
"debuggerd_test.cpp",
"util.cpp"
],
@@ -171,6 +172,7 @@
"libbacktrace",
"libbase",
"libcutils",
+ "libdebuggerd_client",
],
static_libs: [
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index f2975d1..b9fb512 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -19,12 +19,14 @@
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
+#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
@@ -33,6 +35,8 @@
#include <debuggerd/protocol.h>
#include <debuggerd/util.h>
+using namespace std::chrono_literals;
+
using android::base::unique_fd;
static bool send_signal(pid_t pid, bool backtrace) {
@@ -45,28 +49,31 @@
return true;
}
+template <typename Duration>
+static void populate_timeval(struct timeval* tv, const Duration& duration) {
+ auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
+ auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration - seconds);
+ tv->tv_sec = static_cast<long>(seconds.count());
+ tv->tv_usec = static_cast<long>(microseconds.count());
+}
+
bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type,
int timeout_ms) {
LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
unique_fd sockfd;
const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
- auto set_timeout = [timeout_ms, &sockfd, &end]() {
+ auto time_left = [timeout_ms, &end]() { return end - std::chrono::steady_clock::now(); };
+ auto set_timeout = [timeout_ms, &time_left](int sockfd) {
if (timeout_ms <= 0) {
return true;
}
- auto now = std::chrono::steady_clock::now();
- if (now > end) {
+ auto remaining = time_left();
+ if (remaining < decltype(remaining)::zero()) {
return false;
}
-
- auto time_left = std::chrono::duration_cast<std::chrono::microseconds>(end - now);
- auto seconds = std::chrono::duration_cast<std::chrono::seconds>(time_left);
- auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(time_left - seconds);
- struct timeval timeout = {
- .tv_sec = static_cast<long>(seconds.count()),
- .tv_usec = static_cast<long>(microseconds.count()),
- };
+ struct timeval timeout;
+ populate_timeval(&timeout, remaining);
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) {
return false;
@@ -84,7 +91,7 @@
return false;
}
- if (!set_timeout()) {
+ if (!set_timeout(sockfd)) {
PLOG(ERROR) << "libdebugger_client: failed to set timeout";
return false;
}
@@ -96,11 +103,19 @@
}
InterceptRequest req = {.pid = pid };
- if (!set_timeout()) {
+ if (!set_timeout(sockfd)) {
PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+ return false;
}
- if (send_fd(sockfd.get(), &req, sizeof(req), std::move(output_fd)) != sizeof(req)) {
+ // Create an intermediate pipe to pass to the other end.
+ unique_fd pipe_read, pipe_write;
+ if (!Pipe(&pipe_read, &pipe_write)) {
+ PLOG(ERROR) << "libdebuggerd_client: failed to create pipe";
+ return false;
+ }
+
+ if (send_fd(sockfd.get(), &req, sizeof(req), std::move(pipe_write)) != sizeof(req)) {
PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
return false;
}
@@ -108,8 +123,9 @@
bool backtrace = dump_type == kDebuggerdBacktrace;
send_signal(pid, backtrace);
- if (!set_timeout()) {
- PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+ if (!set_timeout(sockfd)) {
+ PLOG(ERROR) << "libdebuggerd_client: failed to set timeout";
+ return false;
}
InterceptResponse response;
@@ -127,6 +143,48 @@
if (response.success != 1) {
response.error_message[sizeof(response.error_message) - 1] = '\0';
LOG(ERROR) << "libdebuggerd_client: tombstoned reported failure: " << response.error_message;
+ return false;
+ }
+
+ // Forward output from the pipe to the output fd.
+ while (true) {
+ auto remaining_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_left());
+ if (remaining_ms <= 1ms) {
+ LOG(ERROR) << "libdebuggerd_client: timeout expired";
+ return false;
+ }
+
+ struct pollfd pfd = {
+ .fd = pipe_read.get(), .events = POLLIN, .revents = 0,
+ };
+
+ rc = poll(&pfd, 1, remaining_ms.count());
+ if (rc == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ PLOG(ERROR) << "libdebuggerd_client: error while polling";
+ return false;
+ }
+ } else if (rc == 0) {
+ LOG(ERROR) << "libdebuggerd_client: timeout expired";
+ return false;
+ }
+
+ char buf[1024];
+ rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), buf, sizeof(buf)));
+ if (rc == 0) {
+ // Done.
+ break;
+ } else if (rc == -1) {
+ PLOG(ERROR) << "libdebuggerd_client: error while reading";
+ return false;
+ }
+
+ if (!android::base::WriteFully(output_fd.get(), buf, rc)) {
+ PLOG(ERROR) << "libdebuggerd_client: error while writing";
+ return false;
+ }
}
LOG(INFO) << "libdebuggerd_client: done dumping process " << pid;
diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp
new file mode 100644
index 0000000..86d0314
--- /dev/null
+++ b/debuggerd/client/debuggerd_client_test.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017, 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 <debuggerd/client.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include <debuggerd/util.h>
+
+using namespace std::chrono_literals;
+using android::base::unique_fd;
+
+TEST(debuggerd_client, race) {
+ static constexpr int THREAD_COUNT = 1024;
+ pid_t forkpid = fork();
+
+ ASSERT_NE(-1, forkpid);
+
+ if (forkpid == 0) {
+ // Spawn a bunch of threads, to make crash_dump take longer.
+ std::vector<std::thread> threads;
+ for (int i = 0; i < THREAD_COUNT; ++i) {
+ threads.emplace_back([]() {
+ while (true) {
+ std::this_thread::sleep_for(60s);
+ }
+ });
+ }
+
+ std::this_thread::sleep_for(60s);
+ exit(0);
+ }
+
+ unique_fd pipe_read, pipe_write;
+ ASSERT_TRUE(Pipe(&pipe_read, &pipe_write));
+
+ // 64 kB should be enough for everyone.
+ constexpr int PIPE_SIZE = 64 * 1024 * 1024;
+ ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE));
+
+ // Wait for a bit to let the child spawn all of its threads.
+ std::this_thread::sleep_for(250ms);
+
+ ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(pipe_write), kDebuggerdBacktrace, 10000));
+ // Immediately kill the forked child, to make sure that the dump didn't return early.
+ ASSERT_EQ(0, kill(forkpid, SIGKILL)) << strerror(errno);
+
+ // Check the output.
+ std::string result;
+ ASSERT_TRUE(android::base::ReadFdToString(pipe_read.get(), &result));
+
+ // Look for "----- end <PID> -----"
+ int found_end = 0;
+
+ std::string expected_end = android::base::StringPrintf("----- end %d -----", forkpid);
+
+ std::vector<std::string> lines = android::base::Split(result, "\n");
+ for (const std::string& line : lines) {
+ if (line == expected_end) {
+ ++found_end;
+ }
+ }
+
+ EXPECT_EQ(1, found_end) << "\nOutput: \n" << result;
+}
diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp
index be4d2dd..66e5e58 100644
--- a/demangle/demangle.cpp
+++ b/demangle/demangle.cpp
@@ -20,22 +20,25 @@
#include <string.h>
#include <unistd.h>
+#include <cctype>
#include <string>
#include <demangle.h>
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
-void usage(const char* prog_name) {
- printf("Usage: %s [-c] <NAME_TO_DEMANGLE>\n", prog_name);
- printf(" -c\n");
- printf(" Compare the results of __cxa_demangle against the current\n");
- printf(" demangler.\n");
+static void Usage(const char* prog_name) {
+ printf("usage: %s [-c] [NAME_TO_DEMANGLE...]\n", prog_name);
+ printf("\n");
+ printf("Demangles C++ mangled names if supplied on the command-line, or found\n");
+ printf("reading from stdin otherwise.\n");
+ printf("\n");
+ printf("-c\tCompare against __cxa_demangle\n");
+ printf("\n");
}
-std::string DemangleWithCxa(const char* name) {
+static std::string DemangleWithCxa(const char* name) {
const char* cxa_demangle = __cxa_demangle(name, nullptr, nullptr, nullptr);
-
if (cxa_demangle == nullptr) {
return name;
}
@@ -54,6 +57,49 @@
return demangled_str;
}
+static void Compare(const char* name, const std::string& demangled_name) {
+ std::string cxa_demangled_name(DemangleWithCxa(name));
+ if (cxa_demangled_name != demangled_name) {
+ printf("\nMismatch!\n");
+ printf("\tmangled name: %s\n", name);
+ printf("\tour demangle: %s\n", demangled_name.c_str());
+ printf("\tcxa demangle: %s\n", cxa_demangled_name.c_str());
+ exit(1);
+ }
+}
+
+static int Filter(bool compare) {
+ char* line = nullptr;
+ size_t line_length = 0;
+
+ while ((getline(&line, &line_length, stdin)) != -1) {
+ char* p = line;
+ char* name;
+ while ((name = strstr(p, "_Z")) != nullptr) {
+ // Output anything before the identifier.
+ *name = 0;
+ printf("%s", p);
+ *name = '_';
+
+ // Extract the identifier.
+ p = name;
+ while (*p && (std::isalnum(*p) || *p == '_' || *p == '.' || *p == '$')) ++p;
+
+ // Demangle and output.
+ std::string identifier(name, p);
+ std::string demangled_name = demangle(identifier.c_str());
+ printf("%s", demangled_name.c_str());
+
+ if (compare) Compare(identifier.c_str(), demangled_name);
+ }
+ // Output anything after the last identifier.
+ printf("%s", p);
+ }
+
+ free(line);
+ return 0;
+}
+
int main(int argc, char** argv) {
#ifdef __BIONIC__
const char* prog_name = getprogname();
@@ -67,31 +113,21 @@
if (opt_char == 'c') {
compare = true;
} else {
- usage(prog_name);
+ Usage(prog_name);
return 1;
}
}
- if (optind >= argc || argc - optind != 1) {
- printf("Must supply a single argument.\n\n");
- usage(prog_name);
- return 1;
- }
- const char* name = argv[optind];
- std::string demangled_name = demangle(name);
+ // With no arguments, act as a filter.
+ if (optind == argc) return Filter(compare);
- printf("%s\n", demangled_name.c_str());
+ // Otherwise demangle each argument.
+ while (optind < argc) {
+ const char* name = argv[optind++];
+ std::string demangled_name = demangle(name);
+ printf("%s\n", demangled_name.c_str());
- if (compare) {
- std::string cxa_demangle_str(DemangleWithCxa(name));
-
- if (cxa_demangle_str != demangled_name) {
- printf("Mismatch\n");
- printf("cxa demangle: %s\n", cxa_demangle_str.c_str());
- return 1;
- } else {
- printf("Match\n");
- }
+ if (compare) Compare(name, demangled_name);
}
return 0;
}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index dd8c7e7..2c14c9b 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -78,7 +78,7 @@
// access. fs_mgr_test_access() will test a few iterations if the
// path doesn't exist yet.
if (fs_mgr_test_access(path.c_str()) < 0) {
- return AVB_IO_RESULT_ERROR_IO;
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
}
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index 5b2f218..cffa6ce 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -56,7 +56,7 @@
return true;
}
- LERROR << "Error finding '" << key << "' in device tree";
+ LINFO << "Error finding '" << key << "' in device tree";
}
return false;
diff --git a/init/README.md b/init/README.md
index 1b2690c..0d8f495 100644
--- a/init/README.md
+++ b/init/README.md
@@ -192,16 +192,17 @@
`oneshot`
> Do not restart the service when it exits.
-`class <name>`
-> Specify a class name for the service. All services in a
+`class <name> [ <name>\* ]`
+> Specify class names for the service. All services in a
named class may be started or stopped together. A service
is in the class "default" if one is not specified via the
- class option.
+ class option. Additional classnames beyond the (required) first
+ one are used to group services.
`onrestart`
> Execute a Command (see below) when service restarts.
-`writepid <file...>`
+`writepid <file> [ <file>\* ]`
> Write the child's pid to the given files when it forks. Meant for
cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
@@ -279,6 +280,9 @@
currently running, without disabling them. They can be restarted
later using `class_start`.
+`class_restart <serviceclass>`
+> Restarts all services of the specified class.
+
`copy <src> <dst>`
> Copies a file. Similar to write, but useful for binary/large
amounts of data.
@@ -364,7 +368,8 @@
"sys.powerctl" system property, used to implement rebooting.
`restart <service>`
-> Like stop, but doesn't disable the service.
+> Stops and restarts a running service, does nothing if the service is currently
+ restarting, otherwise, it just starts the service.
`restorecon <path> [ <path>\* ]`
> Restore the file named by _path_ to the security context specified
diff --git a/init/action.cpp b/init/action.cpp
index 1bba0f2..2ccf0bc 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -18,14 +18,14 @@
#include <errno.h>
-#include <android-base/strings.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include "builtins.h"
#include "error.h"
#include "init_parser.h"
#include "log.h"
-#include "property_service.h"
#include "util.h"
using android::base::Join;
@@ -219,9 +219,8 @@
found = true;
}
} else {
- std::string prop_val = property_get(trigger_name.c_str());
- if (prop_val.empty() || (trigger_value != "*" &&
- trigger_value != prop_val)) {
+ std::string prop_val = android::base::GetProperty(trigger_name, "");
+ if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) {
return false;
}
}
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 4a9c32e..beabea1 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -16,8 +16,6 @@
#include "bootchart.h"
-#include "property_service.h"
-
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -39,6 +37,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
using android::base::StringPrintf;
@@ -72,7 +71,7 @@
utsname uts;
if (uname(&uts) == -1) return;
- std::string fingerprint = property_get("ro.build.fingerprint");
+ std::string fingerprint = android::base::GetProperty("ro.build.fingerprint", "");
if (fingerprint.empty()) return;
std::string kernel_cmdline;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index c860e40..02e314f 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -45,16 +45,16 @@
#include <selinux/selinux.h>
#include <selinux/label.h>
-#include <fs_mgr.h>
#include <android-base/file.h>
#include <android-base/parseint.h>
-#include <android-base/strings.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <bootloader_message/bootloader_message.h>
-#include <cutils/partition_utils.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/ext4_crypt.h>
#include <ext4_utils/ext4_crypt_init_extensions.h>
+#include <fs_mgr.h>
#include <logwrap/logwrap.h>
#include "action.h"
@@ -148,6 +148,12 @@
return 0;
}
+static int do_class_restart(const std::vector<std::string>& args) {
+ ServiceManager::GetInstance().
+ ForEachServiceInClass(args[1], [] (Service* s) { s->Restart(); });
+ return 0;
+}
+
static int do_domainname(const std::vector<std::string>& args) {
return write_file("/proc/sys/kernel/domainname", args[1].c_str()) ? 0 : 1;
}
@@ -866,8 +872,7 @@
}
static bool is_file_crypto() {
- std::string value = property_get("ro.crypto.type");
- return value == "file";
+ return android::base::GetProperty("ro.crypto.type", "") == "file";
}
static int do_installkey(const std::vector<std::string>& args) {
@@ -890,6 +895,7 @@
{"chmod", {2, 2, do_chmod}},
{"chown", {2, 3, do_chown}},
{"class_reset", {1, 1, do_class_reset}},
+ {"class_restart", {1, 1, do_class_restart}},
{"class_start", {1, 1, do_class_start}},
{"class_stop", {1, 1, do_class_stop}},
{"copy", {2, 2, do_copy}},
diff --git a/init/init.cpp b/init/init.cpp
index 5447007..4249115 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -41,13 +41,10 @@
#include <selinux/android.h>
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <cutils/fs.h>
-#include <cutils/iosched_policy.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
#include <libavb/libavb.h>
#include <private/android_filesystem_config.h>
@@ -72,6 +69,7 @@
#include "util.h"
#include "watchdogd.h"
+using android::base::GetProperty;
using android::base::StringPrintf;
struct selabel_handle *sehandle;
@@ -138,7 +136,7 @@
if (waiting_for_prop) {
return false;
}
- if (property_get(name) != value) {
+ if (GetProperty(name, "") != value) {
// Current property value is not equal to expected value
wait_prop_name = name;
wait_prop_value = value;
@@ -426,7 +424,7 @@
static int console_init_action(const std::vector<std::string>& args)
{
- std::string console = property_get("ro.boot.console");
+ std::string console = GetProperty("ro.boot.console", "");
if (!console.empty()) {
default_console = "/dev/" + console;
}
@@ -450,11 +448,11 @@
}
static void export_oem_lock_status() {
- if (property_get("ro.oem_unlock_supported") != "1") {
+ if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) {
return;
}
- std::string value = property_get("ro.boot.verifiedbootstate");
+ std::string value = GetProperty("ro.boot.verifiedbootstate", "");
if (!value.empty()) {
property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
@@ -475,7 +473,7 @@
{ "ro.boot.revision", "ro.revision", "0", },
};
for (size_t i = 0; i < arraysize(prop_map); i++) {
- std::string value = property_get(prop_map[i].src_prop);
+ std::string value = GetProperty(prop_map[i].src_prop, "");
property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value);
}
}
@@ -1252,7 +1250,7 @@
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
- std::string bootscript = property_get("ro.boot.init_rc");
+ std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");
parser.set_is_system_etc_init_loaded(
@@ -1292,7 +1290,7 @@
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
// Don't mount filesystems or start core system services in charger mode.
- std::string bootmode = property_get("ro.bootmode");
+ std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
diff --git a/init/init.h b/init/init.h
index 1a05d98..fe850ef 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,9 +19,6 @@
#include <string>
-class Action;
-class Service;
-
extern const char *ENV[32];
extern std::string default_console;
extern struct selabel_handle *sehandle;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 3dbb2f0..5801ea8 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -23,9 +23,10 @@
#include <linux/keychord.h>
#include <unistd.h>
+#include <android-base/properties.h>
+
#include "init.h"
#include "log.h"
-#include "property_service.h"
#include "service.h"
static struct input_keychord *keychords = 0;
@@ -74,7 +75,7 @@
}
// Only handle keychords if adb is enabled.
- std::string adb_enabled = property_get("init.svc.adbd");
+ std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
if (adb_enabled == "running") {
Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
if (svc) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 983e684..a4d8b5f 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -30,10 +30,6 @@
#include <memory>
#include <vector>
-#include <cutils/misc.h>
-#include <cutils/sockets.h>
-#include <cutils/multiuser.h>
-
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -118,12 +114,6 @@
return check_mac_perms(ctl_name, sctx, cr);
}
-std::string property_get(const char* name) {
- char value[PROP_VALUE_MAX] = {0};
- __system_property_get(name, value);
- return value;
-}
-
static void write_persistent_property(const char *name, const char *value)
{
char tempPath[PATH_MAX];
@@ -592,10 +582,7 @@
static void load_override_properties() {
if (ALLOW_LOCAL_PROP_OVERRIDE) {
- std::string debuggable = property_get("ro.debuggable");
- if (debuggable == "1") {
- load_properties_from_file("/data/local.prop", NULL);
- }
+ load_properties_from_file("/data/local.prop", NULL);
}
}
diff --git a/init/property_service.h b/init/property_service.h
index 5d59473..994da63 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,7 +32,6 @@
void load_persist_props(void);
void load_system_props(void);
void start_property_service(void);
-std::string property_get(const char* name);
uint32_t property_set(const std::string& name, const std::string& value);
bool is_legal_property_name(const std::string& name);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 261a437..2844d78 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -32,17 +32,15 @@
#include <android-base/file.h>
#include <android-base/macros.h>
-#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
-#include <cutils/partition_utils.h>
#include <fs_mgr.h>
#include <logwrap/logwrap.h>
#include "log.h"
-#include "property_service.h"
#include "reboot.h"
#include "service.h"
#include "util.h"
@@ -342,12 +340,9 @@
abort();
}
- std::string timeout = property_get("ro.build.shutdown_timeout");
/* TODO update default waiting time based on usage data */
- unsigned int shutdownTimeout = 10; // default value
- if (android::base::ParseUint(timeout, &shutdownTimeout)) {
- LOG(INFO) << "ro.build.shutdown_timeout set:" << shutdownTimeout;
- }
+ unsigned int shutdownTimeout = android::base::GetUintProperty("ro.build.shutdown_timeout", 10u);
+ LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
for (const char* name : shutdown_critical_services) {
diff --git a/init/service.cpp b/init/service.cpp
index a6efe52..ede6364 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
#include <android-base/file.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <system/thread_defs.h>
@@ -149,27 +150,44 @@
: name(name), value(value) {
}
-Service::Service(const std::string& name, const std::string& classname,
- const std::vector<std::string>& args)
- : name_(name), classname_(classname), flags_(0), pid_(0),
- crash_count_(0), uid_(0), gid_(0), namespace_flags_(0),
- seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
- priority_(0), oom_score_adjust_(-1000), args_(args) {
+Service::Service(const std::string& name, const std::vector<std::string>& args)
+ : name_(name),
+ classnames_({"default"}),
+ flags_(0),
+ pid_(0),
+ crash_count_(0),
+ uid_(0),
+ gid_(0),
+ namespace_flags_(0),
+ seclabel_(""),
+ ioprio_class_(IoSchedClass_NONE),
+ ioprio_pri_(0),
+ priority_(0),
+ oom_score_adjust_(-1000),
+ args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
-Service::Service(const std::string& name, const std::string& classname,
- unsigned flags, uid_t uid, gid_t gid,
- const std::vector<gid_t>& supp_gids,
- const CapSet& capabilities, unsigned namespace_flags,
- const std::string& seclabel,
+Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
+ const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
+ unsigned namespace_flags, const std::string& seclabel,
const std::vector<std::string>& args)
- : name_(name), classname_(classname), flags_(flags), pid_(0),
- crash_count_(0), uid_(uid), gid_(gid),
- supp_gids_(supp_gids), capabilities_(capabilities),
- namespace_flags_(namespace_flags), seclabel_(seclabel),
- ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
- oom_score_adjust_(-1000), args_(args) {
+ : name_(name),
+ classnames_({"default"}),
+ flags_(flags),
+ pid_(0),
+ crash_count_(0),
+ uid_(uid),
+ gid_(gid),
+ supp_gids_(supp_gids),
+ capabilities_(capabilities),
+ namespace_flags_(namespace_flags),
+ seclabel_(seclabel),
+ ioprio_class_(IoSchedClass_NONE),
+ ioprio_pri_(0),
+ priority_(0),
+ oom_score_adjust_(-1000),
+ args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -300,7 +318,7 @@
void Service::DumpState() const {
LOG(INFO) << "service " << name_;
- LOG(INFO) << " class '" << classname_ << "'";
+ LOG(INFO) << " class '" << android::base::Join(classnames_, " ") << "'";
LOG(INFO) << " exec "<< android::base::Join(args_, " ");
std::for_each(descriptors_.begin(), descriptors_.end(),
[] (const auto& info) { LOG(INFO) << *info; });
@@ -337,7 +355,7 @@
}
bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
- classname_ = args[1];
+ classnames_ = std::set<std::string>(args.begin() + 1, args.end());
return true;
}
@@ -519,10 +537,11 @@
Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
+ // clang-format off
static const Map option_parsers = {
{"capabilities",
{1, kMax, &Service::ParseCapabilities}},
- {"class", {1, 1, &Service::ParseClass}},
+ {"class", {1, kMax, &Service::ParseClass}},
{"console", {0, 1, &Service::ParseConsole}},
{"critical", {0, 0, &Service::ParseCritical}},
{"disabled", {0, 0, &Service::ParseDisabled}},
@@ -542,6 +561,7 @@
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
+ // clang-format on
return option_parsers;
}
@@ -653,7 +673,7 @@
if (iter == writepid_files_.end()) {
// There were no "writepid" instructions for cpusets, check if the system default
// cpuset is specified to be used for the process.
- std::string default_cpuset = property_get("ro.cpuset.default");
+ std::string default_cpuset = android::base::GetProperty("ro.cpuset.default", "");
if (!default_cpuset.empty()) {
// Make sure the cpuset name starts and ends with '/'.
// A single '/' means the 'root' cpuset.
@@ -933,8 +953,8 @@
}
}
- auto svc_p = std::make_unique<Service>(name, "default", flags, uid, gid, supp_gids,
- no_capabilities, namespace_flags, seclabel, str_args);
+ auto svc_p = std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
+ namespace_flags, seclabel, str_args);
Service* svc = svc_p.get();
services_.emplace_back(std::move(svc_p));
@@ -984,7 +1004,7 @@
void ServiceManager::ForEachServiceInClass(const std::string& classname,
void (*func)(Service* svc)) const {
for (const auto& s : services_) {
- if (classname == s->classname()) {
+ if (s->classnames().find(classname) != s->classnames().end()) {
func(s.get());
}
}
@@ -1083,7 +1103,7 @@
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
- service_ = std::make_unique<Service>(name, "default", str_args);
+ service_ = std::make_unique<Service>(name, str_args);
return true;
}
diff --git a/init/service.h b/init/service.h
index 3ca7c32..f08a03f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -22,6 +22,7 @@
#include <cutils/iosched_policy.h>
#include <memory>
+#include <set>
#include <string>
#include <vector>
@@ -64,12 +65,10 @@
};
class Service {
-public:
- Service(const std::string& name, const std::string& classname,
- const std::vector<std::string>& args);
+ public:
+ Service(const std::string& name, const std::vector<std::string>& args);
- Service(const std::string& name, const std::string& classname,
- unsigned flags, uid_t uid, gid_t gid,
+ Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
unsigned namespace_flags, const std::string& seclabel,
const std::vector<std::string>& args);
@@ -88,10 +87,10 @@
void Reap();
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
- bool IsShutdownCritical() { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
+ bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
const std::string& name() const { return name_; }
- const std::string& classname() const { return classname_; }
+ const std::set<std::string>& classnames() const { return classnames_; }
unsigned flags() const { return flags_; }
pid_t pid() const { return pid_; }
uid_t uid() const { return uid_; }
@@ -104,7 +103,7 @@
void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
const std::vector<std::string>& args() const { return args_; }
-private:
+ private:
using OptionParser = bool (Service::*) (const std::vector<std::string>& args,
std::string* err);
class OptionParserMap;
@@ -140,7 +139,7 @@
bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
std::string name_;
- std::string classname_;
+ std::set<std::string> classnames_;
std::string console_;
unsigned flags_;
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 1041b82..5e3acac 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -24,8 +24,6 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
#include "action.h"
#include "init.h"
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 915afbd..f27be64 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -26,6 +26,7 @@
#include <sys/types.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <selinux/selinux.h>
@@ -34,7 +35,6 @@
#include "util.h"
#include "devices.h"
#include "ueventd_parser.h"
-#include "property_service.h"
int ueventd_main(int argc, char **argv)
{
@@ -71,7 +71,7 @@
* TODO: cleanup platform ueventd.rc to remove vendor specific
* device node entries (b/34968103)
*/
- std::string hardware = property_get("ro.hardware");
+ std::string hardware = android::base::GetProperty("ro.hardware", "");
ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
device_init();
diff --git a/init/util.cpp b/init/util.cpp
index 0ba9800..8a19939 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -38,6 +38,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -48,7 +49,6 @@
#include "init.h"
#include "log.h"
-#include "property_service.h"
#include "reboot.h"
#include "util.h"
@@ -395,7 +395,7 @@
return false;
}
- std::string prop_val = property_get(prop_name.c_str());
+ std::string prop_val = android::base::GetProperty(prop_name, "");
if (prop_val.empty()) {
if (def_val.empty()) {
LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'";
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
index e0e6a34..96ca566 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.c
@@ -17,6 +17,7 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,7 +42,7 @@
}
int load_canned_fs_config(const char* fn) {
- char line[PATH_MAX + 200];
+ char buf[PATH_MAX + 200];
FILE* f;
f = fopen(fn, "r");
@@ -50,17 +51,21 @@
return -1;
}
- while (fgets(line, sizeof(line), f)) {
+ while (fgets(buf, sizeof(buf), f)) {
Path* p;
char* token;
+ char* line = buf;
+ bool rootdir;
while (canned_used >= canned_alloc) {
canned_alloc = (canned_alloc+1) * 2;
canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
}
p = canned_data + canned_used;
- p->path = strdup(strtok(line, " "));
- p->uid = atoi(strtok(NULL, " "));
+ if (line[0] == '/') line++;
+ rootdir = line[0] == ' ';
+ p->path = strdup(rootdir ? "" : strtok(line, " "));
+ p->uid = atoi(strtok(rootdir ? line : NULL, " "));
p->gid = atoi(strtok(NULL, " "));
p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal
p->capabilities = 0;
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 40144cf..73ca518 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -51,13 +51,8 @@
static pthread_once_t the_once = PTHREAD_ONCE_INIT;
-static int __sys_supports_schedgroups = -1;
static int __sys_supports_timerslack = -1;
-// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
-static int bg_cgroup_fd = -1;
-static int fg_cgroup_fd = -1;
-
// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
static int system_bg_cpuset_fd = -1;
static int bg_cpuset_fd = -1;
@@ -151,23 +146,6 @@
static void __initialize() {
const char* filename;
- if (!access("/dev/cpuctl/tasks", W_OK)) {
- __sys_supports_schedgroups = 1;
-
- filename = "/dev/cpuctl/tasks";
- fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
- if (fg_cgroup_fd < 0) {
- SLOGE("open of %s failed: %s\n", filename, strerror(errno));
- }
-
- filename = "/dev/cpuctl/bg_non_interactive/tasks";
- bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
- if (bg_cgroup_fd < 0) {
- SLOGE("open of %s failed: %s\n", filename, strerror(errno));
- }
- } else {
- __sys_supports_schedgroups = 0;
- }
if (cpusets_enabled()) {
if (!access("/dev/cpuset/tasks", W_OK)) {
@@ -276,48 +254,26 @@
}
pthread_once(&the_once, __initialize);
- if (__sys_supports_schedgroups) {
- char grpBuf[32];
+ char grpBuf[32];
- if (cpusets_enabled()) {
- if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0)
- return -1;
- if (grpBuf[0] == '\0') {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "foreground")) {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "background")) {
- *policy = SP_BACKGROUND;
- } else if (!strcmp(grpBuf, "top-app")) {
- *policy = SP_TOP_APP;
- } else {
- errno = ERANGE;
- return -1;
- }
- } else {
- if (getCGroupSubsys(tid, "cpu", grpBuf, sizeof(grpBuf)) < 0)
- return -1;
- if (grpBuf[0] == '\0') {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "bg_non_interactive")) {
- *policy = SP_BACKGROUND;
- } else {
- errno = ERANGE;
- return -1;
- }
- }
- } else {
- int rc = sched_getscheduler(tid);
- if (rc < 0)
- return -1;
- else if (rc == SCHED_NORMAL)
+ if (cpusets_enabled()) {
+ if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0) return -1;
+ if (grpBuf[0] == '\0') {
*policy = SP_FOREGROUND;
- else if (rc == SCHED_BATCH)
+ } else if (!strcmp(grpBuf, "foreground")) {
+ *policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "background")) {
*policy = SP_BACKGROUND;
- else {
+ } else if (!strcmp(grpBuf, "top-app")) {
+ *policy = SP_TOP_APP;
+ } else {
errno = ERANGE;
return -1;
}
+ } else {
+ // In b/34193533, we removed bg_non_interactive cgroup, so now
+ // all threads are in FOREGROUND cgroup
+ *policy = SP_FOREGROUND;
}
return 0;
}
@@ -440,49 +396,30 @@
}
#endif
- if (__sys_supports_schedgroups) {
- int fd = -1;
+ if (schedboost_enabled()) {
int boost_fd = -1;
switch (policy) {
case SP_BACKGROUND:
- fd = bg_cgroup_fd;
boost_fd = bg_schedboost_fd;
break;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
- fd = fg_cgroup_fd;
boost_fd = fg_schedboost_fd;
break;
case SP_TOP_APP:
- fd = fg_cgroup_fd;
boost_fd = ta_schedboost_fd;
break;
default:
- fd = -1;
boost_fd = -1;
break;
}
- if (fd > 0 && add_tid_to_cgroup(tid, fd) != 0) {
+ if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
if (errno != ESRCH && errno != ENOENT)
return -errno;
}
- if (schedboost_enabled()) {
- if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
- if (errno != ESRCH && errno != ENOENT)
- return -errno;
- }
- }
- } else {
- struct sched_param param;
-
- param.sched_priority = 0;
- sched_setscheduler(tid,
- (policy == SP_BACKGROUND) ?
- SCHED_BATCH : SCHED_NORMAL,
- ¶m);
}
if (__sys_supports_timerslack) {
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 81356fe..04a620c 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -235,7 +235,9 @@
}
iovec[1].iov_len = entry.len;
- log_time retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mRealTime;
+ log_time retval = reader->sendDatav(iovec, 1 + (entry.len != 0))
+ ? FLUSH_ERROR
+ : mRealTime;
if (buffer) free(buffer);
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index 381df5a..8fcd17f 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -30,6 +30,19 @@
#include "android-base/logging.h"
+// The name of the directory that holds a staged time zone update distro. If this exists it should
+// replace the one in CURRENT_DIR_NAME.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* STAGED_DIR_NAME = "/staged";
+
+// The name of the directory that holds the (optional) installed time zone update distro.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* CURRENT_DIR_NAME = "/current";
+
+// The name of a file in the staged dir that indicates the staged operation is an "uninstall".
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* UNINSTALL_TOMBSTONE_FILE_NAME = "/STAGED_UNINSTALL_TOMBSTONE";
+
// The name of the file containing the distro version information.
// See also libcore.tzdata.shared2.TimeZoneDistro / libcore.tzdata.shared2.DistroVersion.
static const char* DISTRO_VERSION_FILENAME = "/distro_version";
@@ -75,7 +88,6 @@
static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
-
static void usage() {
std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
"\n"
@@ -184,7 +196,7 @@
return 0;
}
-enum PathStatus { ERR, NONE, IS_DIR, NOT_DIR };
+enum PathStatus { ERR, NONE, IS_DIR, IS_REG, UNKNOWN };
static PathStatus checkPath(const std::string& path) {
struct stat buf;
@@ -195,7 +207,31 @@
}
return NONE;
}
- return S_ISDIR(buf.st_mode) ? IS_DIR : NOT_DIR;
+ return S_ISDIR(buf.st_mode) ? IS_DIR : S_ISREG(buf.st_mode) ? IS_REG : UNKNOWN;
+}
+
+/*
+ * Deletes fileToDelete and returns true if it is successful. If fileToDelete is not a file or
+ * cannot be accessed this method returns false.
+ */
+static bool deleteFile(const std::string& fileToDelete) {
+ // Check whether the file exists.
+ PathStatus pathStatus = checkPath(fileToDelete);
+ if (pathStatus == NONE) {
+ LOG(INFO) << "Path " << fileToDelete << " does not exist";
+ return true;
+ }
+ if (pathStatus != IS_REG) {
+ LOG(WARNING) << "Path " << fileToDelete << " failed to stat() or is not a file.";
+ return false;
+ }
+
+ // Attempt the deletion.
+ int rc = unlink(fileToDelete.c_str());
+ if (rc != 0) {
+ PLOG(WARNING) << "unlink() failed for " << fileToDelete;
+ }
+ return rc == 0;
}
/*
@@ -260,8 +296,7 @@
std::string dataUpdatesDirName(dataZoneInfoDir);
dataUpdatesDirName += "/updates";
LOG(INFO) << "Removing: " << dataUpdatesDirName;
- bool deleted = deleteDir(dataUpdatesDirName);
- if (!deleted) {
+ if (!deleteDir(dataUpdatesDirName)) {
LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
<< " was not successful";
}
@@ -270,14 +305,151 @@
/*
* Deletes the timezone update distro directory.
*/
-static void deleteUpdateDistroDir(std::string& distroDirName) {
+static void deleteUpdateDistroDir(const std::string& distroDirName) {
LOG(INFO) << "Removing: " << distroDirName;
- bool deleted = deleteDir(distroDirName);
- if (!deleted) {
+ if (!deleteDir(distroDirName)) {
LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
}
}
+static void handleStagedUninstall(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName,
+ const PathStatus dataCurrentDirStatus) {
+ LOG(INFO) << "Staged operation is an uninstall.";
+
+ // Delete the current install directory.
+ switch (dataCurrentDirStatus) {
+ case NONE:
+ // This is unexpected: No uninstall should be staged if there is nothing to
+ // uninstall. Carry on anyway.
+ LOG(WARNING) << "No current install to delete.";
+ break;
+ case IS_DIR:
+ // This is normal. Delete the current install dir.
+ if (!deleteDir(dataCurrentDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens we don't know whether we were able to delete or not. We don't
+ // delete the staged operation so it will be retried next boot unless overridden.
+ return;
+ }
+ break;
+ case IS_REG:
+ default:
+ // This is unexpected: We can try to delete the unexpected file and carry on.
+ LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+ << " is not actually a directory. Attempting deletion.";
+ if (!deleteFile(dataCurrentDirName)) {
+ LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+ return;
+ }
+ break;
+ }
+
+ // Delete the staged uninstall dir.
+ if (!deleteDir(dataStagedDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens we don't know whether we were able to delete the staged operation
+ // or not.
+ return;
+ }
+ LOG(INFO) << "Staged uninstall complete.";
+}
+
+static void handleStagedInstall(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName,
+ const PathStatus dataCurrentDirStatus) {
+ LOG(INFO) << "Staged operation is an install.";
+
+ switch (dataCurrentDirStatus) {
+ case NONE:
+ // This is expected: This is the first install.
+ LOG(INFO) << "No current install to replace.";
+ break;
+ case IS_DIR:
+ // This is expected: We are replacing an existing install.
+ // Delete the current dir so we can replace it.
+ if (!deleteDir(dataCurrentDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens, we cannot proceed.
+ return;
+ }
+ break;
+ case IS_REG:
+ default:
+ // This is unexpected: We can try to delete the unexpected file and carry on.
+ LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+ << " is not actually a directory. Attempting deletion.";
+ if (!deleteFile(dataCurrentDirName)) {
+ LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+ return;
+ }
+ break;
+ }
+
+ // Move the staged dir so it is the new current dir, completing the install.
+ LOG(INFO) << "Moving " << dataStagedDirName << " to " << dataCurrentDirName;
+ int rc = rename(dataStagedDirName.c_str(), dataCurrentDirName.c_str());
+ if (rc == -1) {
+ PLOG(WARNING) << "Unable to rename directory from " << dataStagedDirName << " to "
+ << &dataCurrentDirName[0];
+ return;
+ }
+
+ LOG(INFO) << "Staged install complete.";
+}
+/*
+ * Process a staged operation if there is one.
+ */
+static void processStagedOperation(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName) {
+ PathStatus dataStagedDirStatus = checkPath(dataStagedDirName);
+
+ // Exit early for the common case.
+ if (dataStagedDirStatus == NONE) {
+ LOG(DEBUG) << "No staged time zone operation.";
+ return;
+ }
+
+ // Check known directory names are in a good starting state.
+ if (dataStagedDirStatus != IS_DIR) {
+ LOG(WARNING) << "Staged distro dir " << dataStagedDirName
+ << " could not be accessed or is not a directory."
+ << " stagedDirStatus=" << dataStagedDirStatus;
+ return;
+ }
+
+ // dataStagedDirStatus == IS_DIR.
+
+ // Work out whether there is anything currently installed.
+ PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
+ if (dataCurrentDirStatus == ERR) {
+ LOG(WARNING) << "Current install dir " << dataCurrentDirName << " could not be accessed"
+ << " dataCurrentDirStatus=" << dataCurrentDirStatus;
+ return;
+ }
+
+ // We must perform the staged operation.
+
+ // Check to see if the staged directory contains an uninstall or an install operation.
+ std::string uninstallTombStoneFile(dataStagedDirName);
+ uninstallTombStoneFile += UNINSTALL_TOMBSTONE_FILE_NAME;
+ int uninstallTombStoneFileStatus = checkPath(uninstallTombStoneFile);
+ if (uninstallTombStoneFileStatus != IS_REG && uninstallTombStoneFileStatus != NONE) {
+ // Error case.
+ LOG(WARNING) << "Unable to determine if the staged operation is an uninstall.";
+ return;
+ }
+ if (uninstallTombStoneFileStatus == IS_REG) {
+ handleStagedUninstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+ } else {
+ // uninstallTombStoneFileStatus == NONE meaning this is a staged install.
+ handleStagedInstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+ }
+}
+
/*
* After a platform update it is likely that timezone data found on the system partition will be
* newer than the version found in the data partition. This tool detects this case and removes the
@@ -300,15 +472,25 @@
const char* systemZoneInfoDir = argv[1];
const char* dataZoneInfoDir = argv[2];
- // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+ std::string dataStagedDirName(dataZoneInfoDir);
+ dataStagedDirName += STAGED_DIR_NAME;
+
std::string dataCurrentDirName(dataZoneInfoDir);
- dataCurrentDirName += "/current";
- int dataCurrentDirStatus = checkPath(dataCurrentDirName);
+ dataCurrentDirName += CURRENT_DIR_NAME;
+
+ // Check for an process any staged operation.
+ // If the staged operation could not be handled we still have to validate the current installed
+ // directory so we do not check for errors and do not quit early.
+ processStagedOperation(dataStagedDirName, dataCurrentDirName);
+
+ // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+ PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
if (dataCurrentDirStatus == NONE) {
LOG(INFO) << "timezone distro dir " << dataCurrentDirName
<< " does not exist. No action required.";
return 0;
}
+
// If the distro directory path is not a directory or we can't stat() the path, exit with a
// warning: either there's a problem accessing storage or the world is not as it should be;
// nothing to do.