summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--init/builtins.cpp4
-rw-r--r--init/property_service.cpp365
-rw-r--r--init/property_service.h8
-rw-r--r--init/subcontext.cpp41
-rw-r--r--init/subcontext.proto6
-rw-r--r--libbacktrace/UnwindStack.cpp4
-rw-r--r--libsuspend/autosuspend.c27
-rw-r--r--libsuspend/autosuspend_ops.h1
-rw-r--r--libsuspend/autosuspend_wakeup_count.cpp130
-rw-r--r--libsuspend/include/suspend/autosuspend.h11
-rw-r--r--rootdir/etc/ld.config.txt.in28
-rw-r--r--usbd/Android.bp16
-rw-r--r--usbd/usbd.cpp56
-rw-r--r--usbd/usbd.rc5
14 files changed, 442 insertions, 260 deletions
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f58402166..413d11eb0 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1039,9 +1039,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
1039 {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}}, 1039 {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
1040 {"rm", {1, 1, {true, do_rm}}}, 1040 {"rm", {1, 1, {true, do_rm}}},
1041 {"rmdir", {1, 1, {true, do_rmdir}}}, 1041 {"rmdir", {1, 1, {true, do_rmdir}}},
1042 // TODO: setprop should be run in the subcontext, but property service needs to be split 1042 {"setprop", {2, 2, {true, do_setprop}}},
1043 // out from init before that is possible.
1044 {"setprop", {2, 2, {false, do_setprop}}},
1045 {"setrlimit", {3, 3, {false, do_setrlimit}}}, 1043 {"setrlimit", {3, 3, {false, do_setrlimit}}},
1046 {"start", {1, 1, {false, do_start}}}, 1044 {"start", {1, 1, {false, do_start}}},
1047 {"stop", {1, 1, {false, do_stop}}}, 1045 {"stop", {1, 1, {false, do_stop}}},
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 79f7f25b7..0cb9e63b4 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -84,6 +84,10 @@ static int property_set_fd = -1;
84 84
85static PropertyInfoAreaFile property_info_area; 85static PropertyInfoAreaFile property_info_area;
86 86
87uint32_t InitPropertySet(const std::string& name, const std::string& value);
88
89uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
90
87void CreateSerializedPropertyInfo(); 91void CreateSerializedPropertyInfo();
88 92
89void property_init() { 93void property_init() {
@@ -97,7 +101,7 @@ void property_init() {
97 } 101 }
98} 102}
99static bool CheckMacPerms(const std::string& name, const char* target_context, 103static bool CheckMacPerms(const std::string& name, const char* target_context,
100 const char* source_context, struct ucred* cr) { 104 const char* source_context, const ucred& cr) {
101 if (!target_context || !source_context) { 105 if (!target_context || !source_context) {
102 return false; 106 return false;
103 } 107 }
@@ -105,7 +109,7 @@ static bool CheckMacPerms(const std::string& name, const char* target_context,
105 property_audit_data audit_data; 109 property_audit_data audit_data;
106 110
107 audit_data.name = name.c_str(); 111 audit_data.name = name.c_str();
108 audit_data.cr = cr; 112 audit_data.cr = &cr;
109 113
110 bool has_access = (selinux_check_access(source_context, target_context, "property_service", 114 bool has_access = (selinux_check_access(source_context, target_context, "property_service",
111 "set", &audit_data) == 0); 115 "set", &audit_data) == 0);
@@ -257,7 +261,7 @@ static int RestoreconRecursiveAsync(const std::string& name, const std::string&
257 return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE); 261 return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
258} 262}
259 263
260uint32_t property_set(const std::string& name, const std::string& value) { 264uint32_t PropertySet(const std::string& name, const std::string& value) {
261 if (name == "selinux.restorecon_recursive") { 265 if (name == "selinux.restorecon_recursive") {
262 return PropertySetAsync(name, value, RestoreconRecursiveAsync); 266 return PropertySetAsync(name, value, RestoreconRecursiveAsync);
263 } 267 }
@@ -265,206 +269,208 @@ uint32_t property_set(const std::string& name, const std::string& value) {
265 return PropertySetImpl(name, value); 269 return PropertySetImpl(name, value);
266} 270}
267 271
268class SocketConnection { 272uint32_t InitPropertySet(const std::string& name, const std::string& value) {
269 public: 273 if (StartsWith(name, "ctl.")) {
270 SocketConnection(int socket, const struct ucred& cred) 274 LOG(ERROR) << "Do not set ctl. properties from init; call the Service functions directly";
271 : socket_(socket), cred_(cred) {} 275 return PROP_ERROR_INVALID_NAME;
276 }
272 277
273 ~SocketConnection() { 278 const char* type = nullptr;
274 close(socket_); 279 property_info_area->GetPropertyInfo(name.c_str(), nullptr, &type);
275 }
276 280
277 bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) { 281 if (type == nullptr || !CheckType(type, value)) {
278 return RecvFully(value, sizeof(*value), timeout_ms); 282 LOG(ERROR) << "property_set: name: '" << name << "' type check failed, type: '"
279 } 283 << (type ?: "(null)") << "' value: '" << value << "'";
284 return PROP_ERROR_INVALID_VALUE;
285 }
280 286
281 bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) { 287 return PropertySet(name, value);
282 return RecvFully(chars, size, timeout_ms); 288}
283 }
284 289
285 bool RecvString(std::string* value, uint32_t* timeout_ms) { 290class SocketConnection {
286 uint32_t len = 0; 291 public:
287 if (!RecvUint32(&len, timeout_ms)) { 292 SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
288 return false;
289 }
290 293
291 if (len == 0) { 294 ~SocketConnection() { close(socket_); }
292 *value = "";
293 return true;
294 }
295 295
296 // http://b/35166374: don't allow init to make arbitrarily large allocations. 296 bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
297 if (len > 0xffff) { 297 return RecvFully(value, sizeof(*value), timeout_ms);
298 LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
299 errno = ENOMEM;
300 return false;
301 } 298 }
302 299
303 std::vector<char> chars(len); 300 bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
304 if (!RecvChars(&chars[0], len, timeout_ms)) { 301 return RecvFully(chars, size, timeout_ms);
305 return false;
306 } 302 }
307 303
308 *value = std::string(&chars[0], len); 304 bool RecvString(std::string* value, uint32_t* timeout_ms) {
309 return true; 305 uint32_t len = 0;
310 } 306 if (!RecvUint32(&len, timeout_ms)) {
311 307 return false;
312 bool SendUint32(uint32_t value) { 308 }
313 int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0)); 309
314 return result == sizeof(value); 310 if (len == 0) {
315 } 311 *value = "";
316
317 int socket() {
318 return socket_;
319 }
320
321 const struct ucred& cred() {
322 return cred_;
323 }
324
325 private:
326 bool PollIn(uint32_t* timeout_ms) {
327 struct pollfd ufds[1];
328 ufds[0].fd = socket_;
329 ufds[0].events = POLLIN;
330 ufds[0].revents = 0;
331 while (*timeout_ms > 0) {
332 auto start_time = std::chrono::steady_clock::now();
333 int nr = poll(ufds, 1, *timeout_ms);
334 auto now = std::chrono::steady_clock::now();
335 auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
336 uint64_t millis = time_elapsed.count();
337 *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
338
339 if (nr > 0) {
340 return true; 312 return true;
341 } 313 }
342 314
343 if (nr == 0) { 315 // http://b/35166374: don't allow init to make arbitrarily large allocations.
344 // Timeout 316 if (len > 0xffff) {
345 break; 317 LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
346 } 318 errno = ENOMEM;
319 return false;
320 }
347 321
348 if (nr < 0 && errno != EINTR) { 322 std::vector<char> chars(len);
349 PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message"; 323 if (!RecvChars(&chars[0], len, timeout_ms)) {
350 return false; 324 return false;
351 } else { // errno == EINTR
352 // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
353 // to avoid slowing init down by causing EINTR with under millisecond timeout.
354 if (*timeout_ms > 0) {
355 --(*timeout_ms);
356 } 325 }
357 } 326
327 *value = std::string(&chars[0], len);
328 return true;
358 } 329 }
359 330
360 LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message."; 331 bool SendUint32(uint32_t value) {
361 return false; 332 int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
362 } 333 return result == sizeof(value);
334 }
363 335
364 bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) { 336 int socket() { return socket_; }
365 size_t bytes_left = size;
366 char* data = static_cast<char*>(data_ptr);
367 while (*timeout_ms > 0 && bytes_left > 0) {
368 if (!PollIn(timeout_ms)) {
369 return false;
370 }
371 337
372 int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT)); 338 const ucred& cred() { return cred_; }
373 if (result <= 0) { 339
374 return false; 340 std::string source_context() const {
375 } 341 char* source_context = nullptr;
342 getpeercon(socket_, &source_context);
343 std::string result = source_context;
344 freecon(source_context);
345 return result;
346 }
347
348 private:
349 bool PollIn(uint32_t* timeout_ms) {
350 struct pollfd ufds[1];
351 ufds[0].fd = socket_;
352 ufds[0].events = POLLIN;
353 ufds[0].revents = 0;
354 while (*timeout_ms > 0) {
355 auto start_time = std::chrono::steady_clock::now();
356 int nr = poll(ufds, 1, *timeout_ms);
357 auto now = std::chrono::steady_clock::now();
358 auto time_elapsed =
359 std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
360 uint64_t millis = time_elapsed.count();
361 *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
362
363 if (nr > 0) {
364 return true;
365 }
366
367 if (nr == 0) {
368 // Timeout
369 break;
370 }
371
372 if (nr < 0 && errno != EINTR) {
373 PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid
374 << " to send property message";
375 return false;
376 } else { // errno == EINTR
377 // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
378 // to avoid slowing init down by causing EINTR with under millisecond timeout.
379 if (*timeout_ms > 0) {
380 --(*timeout_ms);
381 }
382 }
383 }
376 384
377 bytes_left -= result; 385 LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid
378 data += result; 386 << " to send property message.";
387 return false;
379 } 388 }
380 389
381 return bytes_left == 0; 390 bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
382 } 391 size_t bytes_left = size;
392 char* data = static_cast<char*>(data_ptr);
393 while (*timeout_ms > 0 && bytes_left > 0) {
394 if (!PollIn(timeout_ms)) {
395 return false;
396 }
397
398 int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
399 if (result <= 0) {
400 return false;
401 }
402
403 bytes_left -= result;
404 data += result;
405 }
406
407 return bytes_left == 0;
408 }
383 409
384 int socket_; 410 int socket_;
385 struct ucred cred_; 411 ucred cred_;
386 412
387 DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection); 413 DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
388}; 414};
389 415
390static void handle_property_set(SocketConnection& socket, 416// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
391 const std::string& name, 417uint32_t HandlePropertySet(const std::string& name, const std::string& value,
392 const std::string& value, 418 const std::string& source_context, const ucred& cr) {
393 bool legacy_protocol) { 419 if (!is_legal_property_name(name)) {
394 const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2"; 420 LOG(ERROR) << "PropertySet: illegal property name \"" << name << "\"";
395 if (!is_legal_property_name(name)) { 421 return PROP_ERROR_INVALID_NAME;
396 LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\""; 422 }
397 socket.SendUint32(PROP_ERROR_INVALID_NAME);
398 return;
399 }
400
401 struct ucred cr = socket.cred();
402 char* source_ctx = nullptr;
403 getpeercon(socket.socket(), &source_ctx);
404 std::string source_context = source_ctx;
405 freecon(source_ctx);
406
407 if (StartsWith(name, "ctl.")) {
408 // ctl. properties have their name ctl.<action> and their value is the name of the service to
409 // apply that action to. Permissions for these actions are based on the service, so we must
410 // create a fake name of ctl.<service> to check permissions.
411 auto control_string = "ctl." + value;
412 const char* target_context = nullptr;
413 const char* type = nullptr;
414 property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
415 if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) {
416 LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
417 << " service ctl [" << value << "]"
418 << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
419 if (!legacy_protocol) {
420 socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
421 }
422 return;
423 }
424 423
425 handle_control_message(name.c_str() + 4, value.c_str()); 424 if (StartsWith(name, "ctl.")) {
426 if (!legacy_protocol) { 425 // ctl. properties have their name ctl.<action> and their value is the name of the service
427 socket.SendUint32(PROP_SUCCESS); 426 // to apply that action to. Permissions for these actions are based on the service, so we
428 } 427 // must create a fake name of ctl.<service> to check permissions.
429 } else { 428 auto control_string = "ctl." + value;
430 const char* target_context = nullptr; 429 const char* target_context = nullptr;
431 const char* type = nullptr; 430 const char* type = nullptr;
432 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type); 431 property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
433 if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) { 432 if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) {
434 LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid 433 LOG(ERROR) << "PropertySet: Unable to " << (name.c_str() + 4) << " service ctl ["
435 << " name:" << name; 434 << value << "]"
436 if (!legacy_protocol) { 435 << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
437 socket.SendUint32(PROP_ERROR_PERMISSION_DENIED); 436 return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
438 } 437 }
439 return;
440 }
441 if (type == nullptr || !CheckType(type, value)) {
442 LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '"
443 << (type ?: "(null)") << "' value: '" << value << "'";
444 if (!legacy_protocol) {
445 socket.SendUint32(PROP_ERROR_INVALID_VALUE);
446 }
447 return;
448 }
449 // sys.powerctl is a special property that is used to make the device reboot. We want to log
450 // any process that sets this property to be able to accurately blame the cause of a shutdown.
451 if (name == "sys.powerctl") {
452 std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
453 std::string process_cmdline;
454 std::string process_log_string;
455 if (ReadFileToString(cmdline_path, &process_cmdline)) {
456 // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
457 process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
458 }
459 LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
460 << process_log_string;
461 }
462 438
463 uint32_t result = property_set(name, value); 439 handle_control_message(name.c_str() + 4, value.c_str());
464 if (!legacy_protocol) { 440 return PROP_SUCCESS;
465 socket.SendUint32(result); 441 }
466 } 442
467 } 443 const char* target_context = nullptr;
444 const char* type = nullptr;
445 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
446
447 if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
448 LOG(ERROR) << "PropertySet: permission denied uid:" << cr.uid << " name:" << name;
449 return PROP_ERROR_PERMISSION_DENIED;
450 }
451
452 if (type == nullptr || !CheckType(type, value)) {
453 LOG(ERROR) << "PropertySet: name: '" << name << "' type check failed, type: '"
454 << (type ?: "(null)") << "' value: '" << value << "'";
455 return PROP_ERROR_INVALID_VALUE;
456 }
457
458 // sys.powerctl is a special property that is used to make the device reboot. We want to log
459 // any process that sets this property to be able to accurately blame the cause of a shutdown.
460 if (name == "sys.powerctl") {
461 std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
462 std::string process_cmdline;
463 std::string process_log_string;
464 if (ReadFileToString(cmdline_path, &process_cmdline)) {
465 // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
466 // path.
467 process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
468 }
469 LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
470 << process_log_string;
471 }
472
473 return PropertySet(name, value);
468} 474}
469 475
470static void handle_property_set_fd() { 476static void handle_property_set_fd() {
@@ -475,7 +481,7 @@ static void handle_property_set_fd() {
475 return; 481 return;
476 } 482 }
477 483
478 struct ucred cr; 484 ucred cr;
479 socklen_t cr_size = sizeof(cr); 485 socklen_t cr_size = sizeof(cr);
480 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { 486 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
481 close(s); 487 close(s);
@@ -507,7 +513,7 @@ static void handle_property_set_fd() {
507 prop_name[PROP_NAME_MAX-1] = 0; 513 prop_name[PROP_NAME_MAX-1] = 0;
508 prop_value[PROP_VALUE_MAX-1] = 0; 514 prop_value[PROP_VALUE_MAX-1] = 0;
509 515
510 handle_property_set(socket, prop_value, prop_value, true); 516 HandlePropertySet(prop_value, prop_value, socket.source_context(), socket.cred());
511 break; 517 break;
512 } 518 }
513 519
@@ -521,7 +527,8 @@ static void handle_property_set_fd() {
521 return; 527 return;
522 } 528 }
523 529
524 handle_property_set(socket, name, value, false); 530 auto result = HandlePropertySet(name, value, socket.source_context(), socket.cred());
531 socket.SendUint32(result);
525 break; 532 break;
526 } 533 }
527 534
diff --git a/init/property_service.h b/init/property_service.h
index a55e79c1d..8161b40e3 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -25,10 +25,15 @@ namespace android {
25namespace init { 25namespace init {
26 26
27struct property_audit_data { 27struct property_audit_data {
28 ucred *cr; 28 const ucred* cr;
29 const char* name; 29 const char* name;
30}; 30};
31 31
32extern uint32_t (*property_set)(const std::string& name, const std::string& value);
33
34uint32_t HandlePropertySet(const std::string& name, const std::string& value,
35 const std::string& source_context, const ucred& cr);
36
32extern bool PropertyChildReap(pid_t pid); 37extern bool PropertyChildReap(pid_t pid);
33 38
34void property_init(void); 39void property_init(void);
@@ -36,7 +41,6 @@ void property_load_boot_defaults(void);
36void load_persist_props(void); 41void load_persist_props(void);
37void load_system_props(void); 42void load_system_props(void);
38void start_property_service(void); 43void start_property_service(void);
39uint32_t property_set(const std::string& name, const std::string& value);
40bool is_legal_property_name(const std::string& name); 44bool is_legal_property_name(const std::string& name);
41 45
42} // namespace init 46} // namespace init
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index be754da73..f3b643ad7 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -27,9 +27,13 @@
27#include <selinux/android.h> 27#include <selinux/android.h>
28 28
29#include "action.h" 29#include "action.h"
30#include "property_service.h"
30#include "selinux.h" 31#include "selinux.h"
31#include "util.h" 32#include "util.h"
32 33
34#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
35#include <sys/_system_properties.h>
36
33using android::base::GetExecutablePath; 37using android::base::GetExecutablePath;
34using android::base::Join; 38using android::base::Join;
35using android::base::Socketpair; 39using android::base::Socketpair;
@@ -75,6 +79,13 @@ Result<Success> SendMessage(int socket, const T& message) {
75 return Success(); 79 return Success();
76} 80}
77 81
82std::vector<std::pair<std::string, std::string>> properties_to_set;
83
84uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
85 properties_to_set.emplace_back(name, value);
86 return PROP_SUCCESS;
87}
88
78class SubcontextProcess { 89class SubcontextProcess {
79 public: 90 public:
80 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) 91 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd)
@@ -108,6 +119,14 @@ void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& exec
108 result = RunBuiltinFunction(map_result->second, args, context_); 119 result = RunBuiltinFunction(map_result->second, args, context_);
109 } 120 }
110 121
122 for (const auto& [name, value] : properties_to_set) {
123 auto property = reply->add_properties_to_set();
124 property->set_name(name);
125 property->set_value(value);
126 }
127
128 properties_to_set.clear();
129
111 if (result) { 130 if (result) {
112 reply->set_success(true); 131 reply->set_success(true);
113 } else { 132 } else {
@@ -186,6 +205,9 @@ int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map
186 auto init_fd = std::atoi(argv[3]); 205 auto init_fd = std::atoi(argv[3]);
187 206
188 SelabelInitialize(); 207 SelabelInitialize();
208
209 property_set = SubcontextPropertySet;
210
189 auto subcontext_process = SubcontextProcess(function_map, context, init_fd); 211 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
190 subcontext_process.MainLoop(); 212 subcontext_process.MainLoop();
191 return 0; 213 return 0;
@@ -257,10 +279,6 @@ Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& sub
257 Restart(); 279 Restart();
258 return Error() << "Unable to parse message from subcontext"; 280 return Error() << "Unable to parse message from subcontext";
259 } 281 }
260 if (subcontext_reply.reply_case() == SubcontextReply::kFailure) {
261 auto& failure = subcontext_reply.failure();
262 return ResultError(failure.error_string(), failure.error_errno());
263 }
264 return subcontext_reply; 282 return subcontext_reply;
265} 283}
266 284
@@ -275,6 +293,16 @@ Result<Success> Subcontext::Execute(const std::vector<std::string>& args) {
275 return subcontext_reply.error(); 293 return subcontext_reply.error();
276 } 294 }
277 295
296 for (const auto& property : subcontext_reply->properties_to_set()) {
297 ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
298 HandlePropertySet(property.name(), property.value(), context_, cr);
299 }
300
301 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
302 auto& failure = subcontext_reply->failure();
303 return ResultError(failure.error_string(), failure.error_errno());
304 }
305
278 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) { 306 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
279 return Error() << "Unexpected message type from subcontext: " 307 return Error() << "Unexpected message type from subcontext: "
280 << subcontext_reply->reply_case(); 308 << subcontext_reply->reply_case();
@@ -294,6 +322,11 @@ Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::s
294 return subcontext_reply.error(); 322 return subcontext_reply.error();
295 } 323 }
296 324
325 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
326 auto& failure = subcontext_reply->failure();
327 return ResultError(failure.error_string(), failure.error_errno());
328 }
329
297 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) { 330 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
298 return Error() << "Unexpected message type from subcontext: " 331 return Error() << "Unexpected message type from subcontext: "
299 << subcontext_reply->reply_case(); 332 << subcontext_reply->reply_case();
diff --git a/init/subcontext.proto b/init/subcontext.proto
index e68115e0e..c31f4fb68 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,4 +38,10 @@ message SubcontextReply {
38 Failure failure = 2; 38 Failure failure = 2;
39 ExpandArgsReply expand_args_reply = 3; 39 ExpandArgsReply expand_args_reply = 3;
40 } 40 }
41
42 message PropertyToSet {
43 optional string name = 1;
44 optional string value = 2;
45 }
46 repeated PropertyToSet properties_to_set = 4;
41} \ No newline at end of file 47} \ No newline at end of file
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index bbfbddaa8..a748d1b4f 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -50,7 +50,9 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
50 auto process_memory = stack_map->process_memory(); 50 auto process_memory = stack_map->process_memory();
51 unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(), 51 unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
52 regs, stack_map->process_memory()); 52 regs, stack_map->process_memory());
53 unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch()); 53 if (stack_map->GetJitDebug() != nullptr) {
54 unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
55 }
54 unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore()); 56 unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
55 57
56 if (num_ignore_frames >= unwinder.NumFrames()) { 58 if (num_ignore_frames >= unwinder.NumFrames()) {
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 09fc0617e..b87f59cd6 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -24,28 +24,20 @@
24 24
25#include "autosuspend_ops.h" 25#include "autosuspend_ops.h"
26 26
27static struct autosuspend_ops *autosuspend_ops; 27static struct autosuspend_ops* autosuspend_ops = NULL;
28static bool autosuspend_enabled; 28static bool autosuspend_enabled;
29static bool autosuspend_inited;
30 29
31static int autosuspend_init(void) { 30static int autosuspend_init(void) {
32 if (autosuspend_inited) { 31 if (autosuspend_ops != NULL) {
33 return 0; 32 return 0;
34 } 33 }
35 34
36 autosuspend_ops = autosuspend_wakeup_count_init(); 35 autosuspend_ops = autosuspend_wakeup_count_init();
37 if (autosuspend_ops) { 36 if (autosuspend_ops == NULL) {
38 goto out;
39 }
40
41 if (!autosuspend_ops) {
42 ALOGE("failed to initialize autosuspend"); 37 ALOGE("failed to initialize autosuspend");
43 return -1; 38 return -1;
44 } 39 }
45 40
46out:
47 autosuspend_inited = true;
48
49 ALOGV("autosuspend initialized"); 41 ALOGV("autosuspend initialized");
50 return 0; 42 return 0;
51} 43}
@@ -96,6 +88,19 @@ int autosuspend_disable(void) {
96 return 0; 88 return 0;
97} 89}
98 90
91int autosuspend_force_suspend(int timeout_ms) {
92 int ret;
93
94 ret = autosuspend_init();
95 if (ret) {
96 return ret;
97 }
98
99 ALOGV("autosuspend_force_suspend");
100
101 return autosuspend_ops->force_suspend(timeout_ms);
102}
103
99void autosuspend_set_wakeup_callback(void (*func)(bool success)) { 104void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
100 int ret; 105 int ret;
101 106
diff --git a/libsuspend/autosuspend_ops.h b/libsuspend/autosuspend_ops.h
index 357b82827..b0024c8bb 100644
--- a/libsuspend/autosuspend_ops.h
+++ b/libsuspend/autosuspend_ops.h
@@ -20,6 +20,7 @@
20struct autosuspend_ops { 20struct autosuspend_ops {
21 int (*enable)(void); 21 int (*enable)(void);
22 int (*disable)(void); 22 int (*disable)(void);
23 int (*force_suspend)(int timeout_ms);
23 void (*set_wakeup_callback)(void (*func)(bool success)); 24 void (*set_wakeup_callback)(void (*func)(bool success));
24}; 25};
25 26
diff --git a/libsuspend/autosuspend_wakeup_count.cpp b/libsuspend/autosuspend_wakeup_count.cpp
index cfca76521..27c862957 100644
--- a/libsuspend/autosuspend_wakeup_count.cpp
+++ b/libsuspend/autosuspend_wakeup_count.cpp
@@ -37,7 +37,7 @@
37#define BASE_SLEEP_TIME 100000 37#define BASE_SLEEP_TIME 100000
38#define MAX_SLEEP_TIME 60000000 38#define MAX_SLEEP_TIME 60000000
39 39
40static int state_fd; 40static int state_fd = -1;
41static int wakeup_count_fd; 41static int wakeup_count_fd;
42 42
43using android::base::ReadFdToString; 43using android::base::ReadFdToString;
@@ -46,11 +46,12 @@ using android::base::WriteStringToFd;
46 46
47static pthread_t suspend_thread; 47static pthread_t suspend_thread;
48static sem_t suspend_lockout; 48static sem_t suspend_lockout;
49static const char* sleep_state = "mem"; 49static constexpr char sleep_state[] = "mem";
50static void (*wakeup_func)(bool success) = NULL; 50static void (*wakeup_func)(bool success) = NULL;
51static int sleep_time = BASE_SLEEP_TIME; 51static int sleep_time = BASE_SLEEP_TIME;
52static constexpr char sys_power_state[] = "/sys/power/state"; 52static constexpr char sys_power_state[] = "/sys/power/state";
53static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count"; 53static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count";
54static bool autosuspend_is_init = false;
54 55
55static void update_sleep_time(bool success) { 56static void update_sleep_time(bool success) {
56 if (success) { 57 if (success) {
@@ -62,10 +63,9 @@ static void update_sleep_time(bool success) {
62} 63}
63 64
64static void* suspend_thread_func(void* arg __attribute__((unused))) { 65static void* suspend_thread_func(void* arg __attribute__((unused))) {
65 int ret;
66 bool success = true; 66 bool success = true;
67 67
68 while (1) { 68 while (true) {
69 update_sleep_time(success); 69 update_sleep_time(success);
70 usleep(sleep_time); 70 usleep(sleep_time);
71 success = false; 71 success = false;
@@ -84,7 +84,7 @@ static void* suspend_thread_func(void* arg __attribute__((unused))) {
84 } 84 }
85 85
86 LOG(VERBOSE) << "wait"; 86 LOG(VERBOSE) << "wait";
87 ret = sem_wait(&suspend_lockout); 87 int ret = sem_wait(&suspend_lockout);
88 if (ret < 0) { 88 if (ret < 0) {
89 PLOG(ERROR) << "error waiting on semaphore"; 89 PLOG(ERROR) << "error waiting on semaphore";
90 continue; 90 continue;
@@ -112,13 +112,72 @@ static void* suspend_thread_func(void* arg __attribute__((unused))) {
112 return NULL; 112 return NULL;
113} 113}
114 114
115static int autosuspend_wakeup_count_enable(void) { 115static int init_state_fd(void) {
116 int ret; 116 if (state_fd >= 0) {
117 return 0;
118 }
119
120 int fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_CLOEXEC | O_RDWR));
121 if (fd < 0) {
122 PLOG(ERROR) << "error opening " << sys_power_state;
123 return -1;
124 }
125
126 state_fd = fd;
127 LOG(INFO) << "init_state_fd success";
128 return 0;
129}
130
131static int autosuspend_init(void) {
132 if (autosuspend_is_init) {
133 return 0;
134 }
135
136 int ret = init_state_fd();
137 if (ret < 0) {
138 return -1;
139 }
140
141 wakeup_count_fd = TEMP_FAILURE_RETRY(open(sys_power_wakeup_count, O_CLOEXEC | O_RDWR));
142 if (wakeup_count_fd < 0) {
143 PLOG(ERROR) << "error opening " << sys_power_wakeup_count;
144 goto err_open_wakeup_count;
145 }
146
147 ret = sem_init(&suspend_lockout, 0, 0);
148 if (ret < 0) {
149 PLOG(ERROR) << "error creating suspend_lockout semaphore";
150 goto err_sem_init;
151 }
152
153 ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
154 if (ret) {
155 LOG(ERROR) << "error creating thread: " << strerror(ret);
156 goto err_pthread_create;
157 }
158
159 LOG(VERBOSE) << "autosuspend_init success";
160 autosuspend_is_init = true;
161 return 0;
117 162
163err_pthread_create:
164 sem_destroy(&suspend_lockout);
165err_sem_init:
166 close(wakeup_count_fd);
167err_open_wakeup_count:
168 return -1;
169}
170
171static int autosuspend_wakeup_count_enable(void) {
118 LOG(VERBOSE) << "autosuspend_wakeup_count_enable"; 172 LOG(VERBOSE) << "autosuspend_wakeup_count_enable";
119 173
120 ret = sem_post(&suspend_lockout); 174 int ret = autosuspend_init();
175 if (ret < 0) {
176 LOG(ERROR) << "autosuspend_init failed";
177 return ret;
178 }
121 179
180 ret = sem_post(&suspend_lockout);
122 if (ret < 0) { 181 if (ret < 0) {
123 PLOG(ERROR) << "error changing semaphore"; 182 PLOG(ERROR) << "error changing semaphore";
124 } 183 }
@@ -129,11 +188,13 @@ static int autosuspend_wakeup_count_enable(void) {
129} 188}
130 189
131static int autosuspend_wakeup_count_disable(void) { 190static int autosuspend_wakeup_count_disable(void) {
132 int ret;
133
134 LOG(VERBOSE) << "autosuspend_wakeup_count_disable"; 191 LOG(VERBOSE) << "autosuspend_wakeup_count_disable";
135 192
136 ret = sem_wait(&suspend_lockout); 193 if (!autosuspend_is_init) {
194 return 0; // always successful if no thread is running yet
195 }
196
197 int ret = sem_wait(&suspend_lockout);
137 198
138 if (ret < 0) { 199 if (ret < 0) {
139 PLOG(ERROR) << "error changing semaphore"; 200 PLOG(ERROR) << "error changing semaphore";
@@ -144,6 +205,17 @@ static int autosuspend_wakeup_count_disable(void) {
144 return ret; 205 return ret;
145} 206}
146 207
208static int force_suspend(int timeout_ms) {
209 LOG(VERBOSE) << "force_suspend called with timeout: " << timeout_ms;
210
211 int ret = init_state_fd();
212 if (ret < 0) {
213 return ret;
214 }
215
216 return WriteStringToFd(sleep_state, state_fd) ? 0 : -1;
217}
218
147static void autosuspend_set_wakeup_callback(void (*func)(bool success)) { 219static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
148 if (wakeup_func != NULL) { 220 if (wakeup_func != NULL) {
149 LOG(ERROR) << "duplicate wakeup callback applied, keeping original"; 221 LOG(ERROR) << "duplicate wakeup callback applied, keeping original";
@@ -155,44 +227,10 @@ static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
155struct autosuspend_ops autosuspend_wakeup_count_ops = { 227struct autosuspend_ops autosuspend_wakeup_count_ops = {
156 .enable = autosuspend_wakeup_count_enable, 228 .enable = autosuspend_wakeup_count_enable,
157 .disable = autosuspend_wakeup_count_disable, 229 .disable = autosuspend_wakeup_count_disable,
230 .force_suspend = force_suspend,
158 .set_wakeup_callback = autosuspend_set_wakeup_callback, 231 .set_wakeup_callback = autosuspend_set_wakeup_callback,
159}; 232};
160 233
161struct autosuspend_ops* autosuspend_wakeup_count_init(void) { 234struct autosuspend_ops* autosuspend_wakeup_count_init(void) {
162 int ret;
163
164 state_fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_RDWR));
165 if (state_fd < 0) {
166 PLOG(ERROR) << "error opening " << sys_power_state;
167 goto err_open_state;
168 }
169
170 wakeup_count_fd = TEMP_FAILURE_RETRY(open(sys_power_wakeup_count, O_RDWR));
171 if (wakeup_count_fd < 0) {
172 PLOG(ERROR) << "error opening " << sys_power_wakeup_count;
173 goto err_open_wakeup_count;
174 }
175
176 ret = sem_init(&suspend_lockout, 0, 0);
177 if (ret < 0) {
178 PLOG(ERROR) << "error creating semaphore";
179 goto err_sem_init;
180 }
181 ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
182 if (ret) {
183 LOG(ERROR) << "error creating thread: " << strerror(ret);
184 goto err_pthread_create;
185 }
186
187 LOG(INFO) << "selected wakeup count";
188 return &autosuspend_wakeup_count_ops; 235 return &autosuspend_wakeup_count_ops;
189
190err_pthread_create:
191 sem_destroy(&suspend_lockout);
192err_sem_init:
193 close(wakeup_count_fd);
194err_open_wakeup_count:
195 close(state_fd);
196err_open_state:
197 return NULL;
198} 236}
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index e130ca3df..21f4d61bf 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -45,6 +45,17 @@ int autosuspend_enable(void);
45int autosuspend_disable(void); 45int autosuspend_disable(void);
46 46
47/* 47/*
48 * force_suspend
49 *
50 * Forces suspend to happen. timeout_ms is used to give system a chance to suspend gracefully.
51 * When timeout expires, suspend will be forced via mem --> /sys/power/state. timeout_ms of 0
52 * will force suspend immediately.
53 *
54 * Returns 0 if system suspended, -1 if suspend did not occur.
55 */
56int autosuspend_force_suspend(int timeout_ms);
57
58/*
48 * set_wakeup_callback 59 * set_wakeup_callback
49 * 60 *
50 * Set a function to be called each time the device returns from suspend. 61 * 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 cad09c3ff..2a801fad8 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -234,27 +234,15 @@ namespace.default.isolated = true
234namespace.default.visible = true 234namespace.default.visible = true
235 235
236namespace.default.search.paths = /odm/${LIB} 236namespace.default.search.paths = /odm/${LIB}
237namespace.default.search.paths += /odm/${LIB}/vndk
238namespace.default.search.paths += /odm/${LIB}/vndk-sp
239namespace.default.search.paths += /vendor/${LIB} 237namespace.default.search.paths += /vendor/${LIB}
240namespace.default.search.paths += /vendor/${LIB}/vndk
241namespace.default.search.paths += /vendor/${LIB}/vndk-sp
242 238
243namespace.default.permitted.paths = /odm 239namespace.default.permitted.paths = /odm
244namespace.default.permitted.paths += /vendor 240namespace.default.permitted.paths += /vendor
245 241
246namespace.default.asan.search.paths = /data/asan/odm/${LIB} 242namespace.default.asan.search.paths = /data/asan/odm/${LIB}
247namespace.default.asan.search.paths += /odm/${LIB} 243namespace.default.asan.search.paths += /odm/${LIB}
248namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
249namespace.default.asan.search.paths += /odm/${LIB}/vndk
250namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
251namespace.default.asan.search.paths += /odm/${LIB}/vndk-sp
252namespace.default.asan.search.paths += /data/asan/vendor/${LIB} 244namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
253namespace.default.asan.search.paths += /vendor/${LIB} 245namespace.default.asan.search.paths += /vendor/${LIB}
254namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
255namespace.default.asan.search.paths += /vendor/${LIB}/vndk
256namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
257namespace.default.asan.search.paths += /vendor/${LIB}/vndk-sp
258 246
259namespace.default.asan.permitted.paths = /data/asan/odm 247namespace.default.asan.permitted.paths = /data/asan/odm
260namespace.default.asan.permitted.paths += /odm 248namespace.default.asan.permitted.paths += /odm
@@ -274,10 +262,22 @@ namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
274############################################################################### 262###############################################################################
275namespace.vndk.isolated = false 263namespace.vndk.isolated = false
276 264
277namespace.vndk.search.paths = /system/${LIB}/vndk-sp%VNDK_VER% 265namespace.vndk.search.paths = /odm/${LIB}/vndk
266namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
267namespace.vndk.search.paths += /vendor/${LIB}/vndk
268namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
269namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
278namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER% 270namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
279 271
280namespace.vndk.asan.search.paths = /data/asan/system/${LIB}/vndk-sp%VNDK_VER% 272namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk
273namespace.vndk.asan.search.paths += /odm/${LIB}/vndk
274namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
275namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
276namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
277namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk
278namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
279namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
280namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
281namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER% 281namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
282namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER% 282namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
283namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER% 283namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
diff --git a/usbd/Android.bp b/usbd/Android.bp
new file mode 100644
index 000000000..4f9338fef
--- /dev/null
+++ b/usbd/Android.bp
@@ -0,0 +1,16 @@
1cc_binary {
2 name: "usbd",
3 init_rc: ["usbd.rc"],
4 srcs: ["usbd.cpp"],
5 shared_libs: [
6 "libbase",
7 "libhidlbase",
8 "libhidltransport",
9 "liblog",
10 "libutils",
11 "libhardware",
12 "android.hardware.usb.gadget@1.0",
13 "libcutils",
14 ],
15}
16
diff --git a/usbd/usbd.cpp b/usbd/usbd.cpp
new file mode 100644
index 000000000..41cd8dd9b
--- /dev/null
+++ b/usbd/usbd.cpp
@@ -0,0 +1,56 @@
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "usbd"
18
19#include <string>
20
21#include <android-base/logging.h>
22#include <android-base/properties.h>
23#include <android/hardware/usb/gadget/1.0/IUsbGadget.h>
24
25#define PERSISTENT_USB_CONFIG "persist.sys.usb.config"
26
27using android::base::GetProperty;
28using android::base::SetProperty;
29using android::hardware::usb::gadget::V1_0::GadgetFunction;
30using android::hardware::usb::gadget::V1_0::IUsbGadget;
31using android::hardware::Return;
32
33int main(int /*argc*/, char** /*argv*/) {
34 android::sp<IUsbGadget> gadget = IUsbGadget::getService();
35 Return<void> ret;
36
37 if (gadget != nullptr) {
38 LOG(INFO) << "Usb HAL found.";
39 std::string function = GetProperty(PERSISTENT_USB_CONFIG, "");
40 if (function == "adb") {
41 LOG(INFO) << "peristent prop is adb";
42 SetProperty("ctl.start", "adbd");
43 ret = gadget->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::ADB),
44 nullptr, 0);
45 } else {
46 LOG(INFO) << "Signal MTP to enable default functions";
47 ret = gadget->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::MTP),
48 nullptr, 0);
49 }
50
51 if (!ret.isOk()) LOG(ERROR) << "Error while invoking usb hal";
52 } else {
53 LOG(INFO) << "Usb HAL not found";
54 }
55 exit(0);
56}
diff --git a/usbd/usbd.rc b/usbd/usbd.rc
new file mode 100644
index 000000000..c7838e831
--- /dev/null
+++ b/usbd/usbd.rc
@@ -0,0 +1,5 @@
1service usbd /system/bin/usbd
2 class late_start
3 oneshot
4 user root
5 group root usb