Merge "Build toolbox with _FILE_OFFSET_BITS=64."
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f584021..413d11e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1039,9 +1039,7 @@
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
{"rm", {1, 1, {true, do_rm}}},
{"rmdir", {1, 1, {true, do_rmdir}}},
- // TODO: setprop should be run in the subcontext, but property service needs to be split
- // out from init before that is possible.
- {"setprop", {2, 2, {false, do_setprop}}},
+ {"setprop", {2, 2, {true, do_setprop}}},
{"setrlimit", {3, 3, {false, do_setrlimit}}},
{"start", {1, 1, {false, do_start}}},
{"stop", {1, 1, {false, do_stop}}},
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 79f7f25..0cb9e63 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -84,6 +84,10 @@
static PropertyInfoAreaFile property_info_area;
+uint32_t InitPropertySet(const std::string& name, const std::string& value);
+
+uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
+
void CreateSerializedPropertyInfo();
void property_init() {
@@ -97,7 +101,7 @@
}
}
static bool CheckMacPerms(const std::string& name, const char* target_context,
- const char* source_context, struct ucred* cr) {
+ const char* source_context, const ucred& cr) {
if (!target_context || !source_context) {
return false;
}
@@ -105,7 +109,7 @@
property_audit_data audit_data;
audit_data.name = name.c_str();
- audit_data.cr = cr;
+ audit_data.cr = &cr;
bool has_access = (selinux_check_access(source_context, target_context, "property_service",
"set", &audit_data) == 0);
@@ -257,7 +261,7 @@
return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
}
-uint32_t property_set(const std::string& name, const std::string& value) {
+uint32_t PropertySet(const std::string& name, const std::string& value) {
if (name == "selinux.restorecon_recursive") {
return PropertySetAsync(name, value, RestoreconRecursiveAsync);
}
@@ -265,206 +269,208 @@
return PropertySetImpl(name, value);
}
+uint32_t InitPropertySet(const std::string& name, const std::string& value) {
+ if (StartsWith(name, "ctl.")) {
+ LOG(ERROR) << "Do not set ctl. properties from init; call the Service functions directly";
+ return PROP_ERROR_INVALID_NAME;
+ }
+
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(name.c_str(), nullptr, &type);
+
+ if (type == nullptr || !CheckType(type, value)) {
+ LOG(ERROR) << "property_set: name: '" << name << "' type check failed, type: '"
+ << (type ?: "(null)") << "' value: '" << value << "'";
+ return PROP_ERROR_INVALID_VALUE;
+ }
+
+ return PropertySet(name, value);
+}
+
class SocketConnection {
- public:
- SocketConnection(int socket, const struct ucred& cred)
- : socket_(socket), cred_(cred) {}
+ public:
+ SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
- ~SocketConnection() {
- close(socket_);
- }
+ ~SocketConnection() { close(socket_); }
- bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
- return RecvFully(value, sizeof(*value), timeout_ms);
- }
-
- bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
- return RecvFully(chars, size, timeout_ms);
- }
-
- bool RecvString(std::string* value, uint32_t* timeout_ms) {
- uint32_t len = 0;
- if (!RecvUint32(&len, timeout_ms)) {
- return false;
+ bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
+ return RecvFully(value, sizeof(*value), timeout_ms);
}
- if (len == 0) {
- *value = "";
- return true;
+ bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
+ return RecvFully(chars, size, timeout_ms);
}
- // http://b/35166374: don't allow init to make arbitrarily large allocations.
- if (len > 0xffff) {
- LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
- errno = ENOMEM;
- return false;
- }
-
- std::vector<char> chars(len);
- if (!RecvChars(&chars[0], len, timeout_ms)) {
- return false;
- }
-
- *value = std::string(&chars[0], len);
- return true;
- }
-
- bool SendUint32(uint32_t value) {
- int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
- return result == sizeof(value);
- }
-
- int socket() {
- return socket_;
- }
-
- const struct ucred& cred() {
- return cred_;
- }
-
- private:
- bool PollIn(uint32_t* timeout_ms) {
- struct pollfd ufds[1];
- ufds[0].fd = socket_;
- ufds[0].events = POLLIN;
- ufds[0].revents = 0;
- while (*timeout_ms > 0) {
- auto start_time = std::chrono::steady_clock::now();
- int nr = poll(ufds, 1, *timeout_ms);
- auto now = std::chrono::steady_clock::now();
- auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
- uint64_t millis = time_elapsed.count();
- *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
-
- if (nr > 0) {
- return true;
- }
-
- if (nr == 0) {
- // Timeout
- break;
- }
-
- if (nr < 0 && errno != EINTR) {
- PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message";
- return false;
- } else { // errno == EINTR
- // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
- // to avoid slowing init down by causing EINTR with under millisecond timeout.
- if (*timeout_ms > 0) {
- --(*timeout_ms);
+ bool RecvString(std::string* value, uint32_t* timeout_ms) {
+ uint32_t len = 0;
+ if (!RecvUint32(&len, timeout_ms)) {
+ return false;
}
- }
+
+ if (len == 0) {
+ *value = "";
+ return true;
+ }
+
+ // http://b/35166374: don't allow init to make arbitrarily large allocations.
+ if (len > 0xffff) {
+ LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
+ errno = ENOMEM;
+ return false;
+ }
+
+ std::vector<char> chars(len);
+ if (!RecvChars(&chars[0], len, timeout_ms)) {
+ return false;
+ }
+
+ *value = std::string(&chars[0], len);
+ return true;
}
- LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message.";
- return false;
- }
-
- bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
- size_t bytes_left = size;
- char* data = static_cast<char*>(data_ptr);
- while (*timeout_ms > 0 && bytes_left > 0) {
- if (!PollIn(timeout_ms)) {
- return false;
- }
-
- int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
- if (result <= 0) {
- return false;
- }
-
- bytes_left -= result;
- data += result;
+ bool SendUint32(uint32_t value) {
+ int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
+ return result == sizeof(value);
}
- return bytes_left == 0;
- }
+ int socket() { return socket_; }
- int socket_;
- struct ucred cred_;
+ const ucred& cred() { return cred_; }
- DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
+ std::string source_context() const {
+ char* source_context = nullptr;
+ getpeercon(socket_, &source_context);
+ std::string result = source_context;
+ freecon(source_context);
+ return result;
+ }
+
+ private:
+ bool PollIn(uint32_t* timeout_ms) {
+ struct pollfd ufds[1];
+ ufds[0].fd = socket_;
+ ufds[0].events = POLLIN;
+ ufds[0].revents = 0;
+ while (*timeout_ms > 0) {
+ auto start_time = std::chrono::steady_clock::now();
+ int nr = poll(ufds, 1, *timeout_ms);
+ auto now = std::chrono::steady_clock::now();
+ auto time_elapsed =
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ uint64_t millis = time_elapsed.count();
+ *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
+
+ if (nr > 0) {
+ return true;
+ }
+
+ if (nr == 0) {
+ // Timeout
+ break;
+ }
+
+ if (nr < 0 && errno != EINTR) {
+ PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid
+ << " to send property message";
+ return false;
+ } else { // errno == EINTR
+ // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
+ // to avoid slowing init down by causing EINTR with under millisecond timeout.
+ if (*timeout_ms > 0) {
+ --(*timeout_ms);
+ }
+ }
+ }
+
+ LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid
+ << " to send property message.";
+ return false;
+ }
+
+ bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
+ size_t bytes_left = size;
+ char* data = static_cast<char*>(data_ptr);
+ while (*timeout_ms > 0 && bytes_left > 0) {
+ if (!PollIn(timeout_ms)) {
+ return false;
+ }
+
+ int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
+ if (result <= 0) {
+ return false;
+ }
+
+ bytes_left -= result;
+ data += result;
+ }
+
+ return bytes_left == 0;
+ }
+
+ int socket_;
+ ucred cred_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
};
-static void handle_property_set(SocketConnection& socket,
- const std::string& name,
- const std::string& value,
- bool legacy_protocol) {
- const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
- if (!is_legal_property_name(name)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
- socket.SendUint32(PROP_ERROR_INVALID_NAME);
- return;
- }
+// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
+uint32_t HandlePropertySet(const std::string& name, const std::string& value,
+ const std::string& source_context, const ucred& cr) {
+ if (!is_legal_property_name(name)) {
+ LOG(ERROR) << "PropertySet: illegal property name \"" << name << "\"";
+ return PROP_ERROR_INVALID_NAME;
+ }
- struct ucred cr = socket.cred();
- char* source_ctx = nullptr;
- getpeercon(socket.socket(), &source_ctx);
- std::string source_context = source_ctx;
- freecon(source_ctx);
+ if (StartsWith(name, "ctl.")) {
+ // ctl. properties have their name ctl.<action> and their value is the name of the service
+ // to apply that action to. Permissions for these actions are based on the service, so we
+ // must create a fake name of ctl.<service> to check permissions.
+ auto control_string = "ctl." + value;
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
+ if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) {
+ LOG(ERROR) << "PropertySet: Unable to " << (name.c_str() + 4) << " service ctl ["
+ << value << "]"
+ << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
+ return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+ }
- if (StartsWith(name, "ctl.")) {
- // ctl. properties have their name ctl.<action> and their value is the name of the service to
- // apply that action to. Permissions for these actions are based on the service, so we must
- // create a fake name of ctl.<service> to check permissions.
- auto control_string = "ctl." + value;
- const char* target_context = nullptr;
- const char* type = nullptr;
- property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
- if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
- << " service ctl [" << value << "]"
- << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
- }
- return;
- }
+ handle_control_message(name.c_str() + 4, value.c_str());
+ return PROP_SUCCESS;
+ }
- handle_control_message(name.c_str() + 4, value.c_str());
- if (!legacy_protocol) {
- socket.SendUint32(PROP_SUCCESS);
- }
- } else {
- const char* target_context = nullptr;
- const char* type = nullptr;
- property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
- if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid
- << " name:" << name;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
- }
- return;
- }
- if (type == nullptr || !CheckType(type, value)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '"
- << (type ?: "(null)") << "' value: '" << value << "'";
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_INVALID_VALUE);
- }
- return;
- }
- // sys.powerctl is a special property that is used to make the device reboot. We want to log
- // any process that sets this property to be able to accurately blame the cause of a shutdown.
- if (name == "sys.powerctl") {
- std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
- std::string process_cmdline;
- std::string process_log_string;
- if (ReadFileToString(cmdline_path, &process_cmdline)) {
- // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
- process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
- }
- LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
- << process_log_string;
- }
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
- uint32_t result = property_set(name, value);
- if (!legacy_protocol) {
- socket.SendUint32(result);
- }
- }
+ if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
+ LOG(ERROR) << "PropertySet: permission denied uid:" << cr.uid << " name:" << name;
+ return PROP_ERROR_PERMISSION_DENIED;
+ }
+
+ if (type == nullptr || !CheckType(type, value)) {
+ LOG(ERROR) << "PropertySet: name: '" << name << "' type check failed, type: '"
+ << (type ?: "(null)") << "' value: '" << value << "'";
+ return PROP_ERROR_INVALID_VALUE;
+ }
+
+ // sys.powerctl is a special property that is used to make the device reboot. We want to log
+ // any process that sets this property to be able to accurately blame the cause of a shutdown.
+ if (name == "sys.powerctl") {
+ std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
+ std::string process_cmdline;
+ std::string process_log_string;
+ if (ReadFileToString(cmdline_path, &process_cmdline)) {
+ // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
+ // path.
+ process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
+ }
+ LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
+ << process_log_string;
+ }
+
+ return PropertySet(name, value);
}
static void handle_property_set_fd() {
@@ -475,7 +481,7 @@
return;
}
- struct ucred cr;
+ ucred cr;
socklen_t cr_size = sizeof(cr);
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
@@ -507,7 +513,7 @@
prop_name[PROP_NAME_MAX-1] = 0;
prop_value[PROP_VALUE_MAX-1] = 0;
- handle_property_set(socket, prop_value, prop_value, true);
+ HandlePropertySet(prop_value, prop_value, socket.source_context(), socket.cred());
break;
}
@@ -521,7 +527,8 @@
return;
}
- handle_property_set(socket, name, value, false);
+ auto result = HandlePropertySet(name, value, socket.source_context(), socket.cred());
+ socket.SendUint32(result);
break;
}
diff --git a/init/property_service.h b/init/property_service.h
index a55e79c..8161b40 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -25,10 +25,15 @@
namespace init {
struct property_audit_data {
- ucred *cr;
+ const ucred* cr;
const char* name;
};
+extern uint32_t (*property_set)(const std::string& name, const std::string& value);
+
+uint32_t HandlePropertySet(const std::string& name, const std::string& value,
+ const std::string& source_context, const ucred& cr);
+
extern bool PropertyChildReap(pid_t pid);
void property_init(void);
@@ -36,7 +41,6 @@
void load_persist_props(void);
void load_system_props(void);
void start_property_service(void);
-uint32_t property_set(const std::string& name, const std::string& value);
bool is_legal_property_name(const std::string& name);
} // namespace init
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index be754da..f3b643a 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -27,9 +27,13 @@
#include <selinux/android.h>
#include "action.h"
+#include "property_service.h"
#include "selinux.h"
#include "util.h"
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
using android::base::GetExecutablePath;
using android::base::Join;
using android::base::Socketpair;
@@ -75,6 +79,13 @@
return Success();
}
+std::vector<std::pair<std::string, std::string>> properties_to_set;
+
+uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
+ properties_to_set.emplace_back(name, value);
+ return PROP_SUCCESS;
+}
+
class SubcontextProcess {
public:
SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd)
@@ -108,6 +119,14 @@
result = RunBuiltinFunction(map_result->second, args, context_);
}
+ for (const auto& [name, value] : properties_to_set) {
+ auto property = reply->add_properties_to_set();
+ property->set_name(name);
+ property->set_value(value);
+ }
+
+ properties_to_set.clear();
+
if (result) {
reply->set_success(true);
} else {
@@ -186,6 +205,9 @@
auto init_fd = std::atoi(argv[3]);
SelabelInitialize();
+
+ property_set = SubcontextPropertySet;
+
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
subcontext_process.MainLoop();
return 0;
@@ -257,10 +279,6 @@
Restart();
return Error() << "Unable to parse message from subcontext";
}
- if (subcontext_reply.reply_case() == SubcontextReply::kFailure) {
- auto& failure = subcontext_reply.failure();
- return ResultError(failure.error_string(), failure.error_errno());
- }
return subcontext_reply;
}
@@ -275,6 +293,16 @@
return subcontext_reply.error();
}
+ for (const auto& property : subcontext_reply->properties_to_set()) {
+ ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
+ HandlePropertySet(property.name(), property.value(), context_, cr);
+ }
+
+ if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
+ auto& failure = subcontext_reply->failure();
+ return ResultError(failure.error_string(), failure.error_errno());
+ }
+
if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
return Error() << "Unexpected message type from subcontext: "
<< subcontext_reply->reply_case();
@@ -294,6 +322,11 @@
return subcontext_reply.error();
}
+ if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
+ auto& failure = subcontext_reply->failure();
+ return ResultError(failure.error_string(), failure.error_errno());
+ }
+
if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
return Error() << "Unexpected message type from subcontext: "
<< subcontext_reply->reply_case();
diff --git a/init/subcontext.proto b/init/subcontext.proto
index e68115e..c31f4fb 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,4 +38,10 @@
Failure failure = 2;
ExpandArgsReply expand_args_reply = 3;
}
+
+ message PropertyToSet {
+ optional string name = 1;
+ optional string value = 2;
+ }
+ repeated PropertyToSet properties_to_set = 4;
}
\ No newline at end of file
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index bbfbdda..a748d1b 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -50,7 +50,9 @@
auto process_memory = stack_map->process_memory();
unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
regs, stack_map->process_memory());
- unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+ if (stack_map->GetJitDebug() != nullptr) {
+ unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+ }
unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
if (num_ignore_frames >= unwinder.NumFrames()) {
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 09fc061..b87f59c 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -24,28 +24,20 @@
#include "autosuspend_ops.h"
-static struct autosuspend_ops *autosuspend_ops;
+static struct autosuspend_ops* autosuspend_ops = NULL;
static bool autosuspend_enabled;
-static bool autosuspend_inited;
static int autosuspend_init(void) {
- if (autosuspend_inited) {
+ if (autosuspend_ops != NULL) {
return 0;
}
autosuspend_ops = autosuspend_wakeup_count_init();
- if (autosuspend_ops) {
- goto out;
- }
-
- if (!autosuspend_ops) {
+ if (autosuspend_ops == NULL) {
ALOGE("failed to initialize autosuspend");
return -1;
}
-out:
- autosuspend_inited = true;
-
ALOGV("autosuspend initialized");
return 0;
}
@@ -96,6 +88,19 @@
return 0;
}
+int autosuspend_force_suspend(int timeout_ms) {
+ int ret;
+
+ ret = autosuspend_init();
+ if (ret) {
+ return ret;
+ }
+
+ ALOGV("autosuspend_force_suspend");
+
+ return autosuspend_ops->force_suspend(timeout_ms);
+}
+
void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
int ret;
diff --git a/libsuspend/autosuspend_ops.h b/libsuspend/autosuspend_ops.h
index 357b828..b0024c8 100644
--- a/libsuspend/autosuspend_ops.h
+++ b/libsuspend/autosuspend_ops.h
@@ -20,6 +20,7 @@
struct autosuspend_ops {
int (*enable)(void);
int (*disable)(void);
+ int (*force_suspend)(int timeout_ms);
void (*set_wakeup_callback)(void (*func)(bool success));
};
diff --git a/libsuspend/autosuspend_wakeup_count.cpp b/libsuspend/autosuspend_wakeup_count.cpp
index cfca765..27c8629 100644
--- a/libsuspend/autosuspend_wakeup_count.cpp
+++ b/libsuspend/autosuspend_wakeup_count.cpp
@@ -37,7 +37,7 @@
#define BASE_SLEEP_TIME 100000
#define MAX_SLEEP_TIME 60000000
-static int state_fd;
+static int state_fd = -1;
static int wakeup_count_fd;
using android::base::ReadFdToString;
@@ -46,11 +46,12 @@
static pthread_t suspend_thread;
static sem_t suspend_lockout;
-static const char* sleep_state = "mem";
+static constexpr char sleep_state[] = "mem";
static void (*wakeup_func)(bool success) = NULL;
static int sleep_time = BASE_SLEEP_TIME;
static constexpr char sys_power_state[] = "/sys/power/state";
static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count";
+static bool autosuspend_is_init = false;
static void update_sleep_time(bool success) {
if (success) {
@@ -62,10 +63,9 @@
}
static void* suspend_thread_func(void* arg __attribute__((unused))) {
- int ret;
bool success = true;
- while (1) {
+ while (true) {
update_sleep_time(success);
usleep(sleep_time);
success = false;
@@ -84,7 +84,7 @@
}
LOG(VERBOSE) << "wait";
- ret = sem_wait(&suspend_lockout);
+ int ret = sem_wait(&suspend_lockout);
if (ret < 0) {
PLOG(ERROR) << "error waiting on semaphore";
continue;
@@ -112,13 +112,72 @@
return NULL;
}
-static int autosuspend_wakeup_count_enable(void) {
- int ret;
+static int init_state_fd(void) {
+ if (state_fd >= 0) {
+ return 0;
+ }
+ int fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_CLOEXEC | O_RDWR));
+ if (fd < 0) {
+ PLOG(ERROR) << "error opening " << sys_power_state;
+ return -1;
+ }
+
+ state_fd = fd;
+ LOG(INFO) << "init_state_fd success";
+ return 0;
+}
+
+static int autosuspend_init(void) {
+ if (autosuspend_is_init) {
+ return 0;
+ }
+
+ int ret = init_state_fd();
+ if (ret < 0) {
+ return -1;
+ }
+
+ wakeup_count_fd = TEMP_FAILURE_RETRY(open(sys_power_wakeup_count, O_CLOEXEC | O_RDWR));
+ if (wakeup_count_fd < 0) {
+ PLOG(ERROR) << "error opening " << sys_power_wakeup_count;
+ goto err_open_wakeup_count;
+ }
+
+ ret = sem_init(&suspend_lockout, 0, 0);
+ if (ret < 0) {
+ PLOG(ERROR) << "error creating suspend_lockout semaphore";
+ goto err_sem_init;
+ }
+
+ ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
+ if (ret) {
+ LOG(ERROR) << "error creating thread: " << strerror(ret);
+ goto err_pthread_create;
+ }
+
+ LOG(VERBOSE) << "autosuspend_init success";
+ autosuspend_is_init = true;
+ return 0;
+
+err_pthread_create:
+ sem_destroy(&suspend_lockout);
+err_sem_init:
+ close(wakeup_count_fd);
+err_open_wakeup_count:
+ return -1;
+}
+
+static int autosuspend_wakeup_count_enable(void) {
LOG(VERBOSE) << "autosuspend_wakeup_count_enable";
- ret = sem_post(&suspend_lockout);
+ int ret = autosuspend_init();
+ if (ret < 0) {
+ LOG(ERROR) << "autosuspend_init failed";
+ return ret;
+ }
+ ret = sem_post(&suspend_lockout);
if (ret < 0) {
PLOG(ERROR) << "error changing semaphore";
}
@@ -129,11 +188,13 @@
}
static int autosuspend_wakeup_count_disable(void) {
- int ret;
-
LOG(VERBOSE) << "autosuspend_wakeup_count_disable";
- ret = sem_wait(&suspend_lockout);
+ if (!autosuspend_is_init) {
+ return 0; // always successful if no thread is running yet
+ }
+
+ int ret = sem_wait(&suspend_lockout);
if (ret < 0) {
PLOG(ERROR) << "error changing semaphore";
@@ -144,6 +205,17 @@
return ret;
}
+static int force_suspend(int timeout_ms) {
+ LOG(VERBOSE) << "force_suspend called with timeout: " << timeout_ms;
+
+ int ret = init_state_fd();
+ if (ret < 0) {
+ return ret;
+ }
+
+ return WriteStringToFd(sleep_state, state_fd) ? 0 : -1;
+}
+
static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
if (wakeup_func != NULL) {
LOG(ERROR) << "duplicate wakeup callback applied, keeping original";
@@ -155,44 +227,10 @@
struct autosuspend_ops autosuspend_wakeup_count_ops = {
.enable = autosuspend_wakeup_count_enable,
.disable = autosuspend_wakeup_count_disable,
+ .force_suspend = force_suspend,
.set_wakeup_callback = autosuspend_set_wakeup_callback,
};
struct autosuspend_ops* autosuspend_wakeup_count_init(void) {
- int ret;
-
- state_fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_RDWR));
- if (state_fd < 0) {
- PLOG(ERROR) << "error opening " << sys_power_state;
- goto err_open_state;
- }
-
- wakeup_count_fd = TEMP_FAILURE_RETRY(open(sys_power_wakeup_count, O_RDWR));
- if (wakeup_count_fd < 0) {
- PLOG(ERROR) << "error opening " << sys_power_wakeup_count;
- goto err_open_wakeup_count;
- }
-
- ret = sem_init(&suspend_lockout, 0, 0);
- if (ret < 0) {
- PLOG(ERROR) << "error creating semaphore";
- goto err_sem_init;
- }
- ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
- if (ret) {
- LOG(ERROR) << "error creating thread: " << strerror(ret);
- goto err_pthread_create;
- }
-
- LOG(INFO) << "selected wakeup count";
return &autosuspend_wakeup_count_ops;
-
-err_pthread_create:
- sem_destroy(&suspend_lockout);
-err_sem_init:
- close(wakeup_count_fd);
-err_open_wakeup_count:
- close(state_fd);
-err_open_state:
- return NULL;
}
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index e130ca3..21f4d61 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -45,6 +45,17 @@
int autosuspend_disable(void);
/*
+ * force_suspend
+ *
+ * Forces suspend to happen. timeout_ms is used to give system a chance to suspend gracefully.
+ * When timeout expires, suspend will be forced via mem --> /sys/power/state. timeout_ms of 0
+ * will force suspend immediately.
+ *
+ * Returns 0 if system suspended, -1 if suspend did not occur.
+ */
+int autosuspend_force_suspend(int timeout_ms);
+
+/*
* set_wakeup_callback
*
* Set a function to be called each time the device returns from suspend.
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index cad09c3..2a801fa 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -234,27 +234,15 @@
namespace.default.visible = true
namespace.default.search.paths = /odm/${LIB}
-namespace.default.search.paths += /odm/${LIB}/vndk
-namespace.default.search.paths += /odm/${LIB}/vndk-sp
namespace.default.search.paths += /vendor/${LIB}
-namespace.default.search.paths += /vendor/${LIB}/vndk
-namespace.default.search.paths += /vendor/${LIB}/vndk-sp
namespace.default.permitted.paths = /odm
namespace.default.permitted.paths += /vendor
namespace.default.asan.search.paths = /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
-namespace.default.asan.search.paths += /odm/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /odm/${LIB}/vndk-sp
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /vendor/${LIB}/vndk-sp
namespace.default.asan.permitted.paths = /data/asan/odm
namespace.default.asan.permitted.paths += /odm
@@ -274,10 +262,22 @@
###############################################################################
namespace.vndk.isolated = false
-namespace.vndk.search.paths = /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.search.paths = /odm/${LIB}/vndk
+namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.search.paths += /vendor/${LIB}/vndk
+namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
-namespace.vndk.asan.search.paths = /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
diff --git a/usbd/Android.bp b/usbd/Android.bp
new file mode 100644
index 0000000..4f9338f
--- /dev/null
+++ b/usbd/Android.bp
@@ -0,0 +1,16 @@
+cc_binary {
+ name: "usbd",
+ init_rc: ["usbd.rc"],
+ srcs: ["usbd.cpp"],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "android.hardware.usb.gadget@1.0",
+ "libcutils",
+ ],
+}
+
diff --git a/usbd/usbd.cpp b/usbd/usbd.cpp
new file mode 100644
index 0000000..41cd8dd
--- /dev/null
+++ b/usbd/usbd.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "usbd"
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/hardware/usb/gadget/1.0/IUsbGadget.h>
+
+#define PERSISTENT_USB_CONFIG "persist.sys.usb.config"
+
+using android::base::GetProperty;
+using android::base::SetProperty;
+using android::hardware::usb::gadget::V1_0::GadgetFunction;
+using android::hardware::usb::gadget::V1_0::IUsbGadget;
+using android::hardware::Return;
+
+int main(int /*argc*/, char** /*argv*/) {
+ android::sp<IUsbGadget> gadget = IUsbGadget::getService();
+ Return<void> ret;
+
+ if (gadget != nullptr) {
+ LOG(INFO) << "Usb HAL found.";
+ std::string function = GetProperty(PERSISTENT_USB_CONFIG, "");
+ if (function == "adb") {
+ LOG(INFO) << "peristent prop is adb";
+ SetProperty("ctl.start", "adbd");
+ ret = gadget->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::ADB),
+ nullptr, 0);
+ } else {
+ LOG(INFO) << "Signal MTP to enable default functions";
+ ret = gadget->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::MTP),
+ nullptr, 0);
+ }
+
+ if (!ret.isOk()) LOG(ERROR) << "Error while invoking usb hal";
+ } else {
+ LOG(INFO) << "Usb HAL not found";
+ }
+ exit(0);
+}
diff --git a/usbd/usbd.rc b/usbd/usbd.rc
new file mode 100644
index 0000000..c7838e8
--- /dev/null
+++ b/usbd/usbd.rc
@@ -0,0 +1,5 @@
+service usbd /system/bin/usbd
+ class late_start
+ oneshot
+ user root
+ group root usb