diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md index ffda3a5d6..1926a4f5b 100644 --- a/shell_and_utilities/README.md +++ b/shell_and_utilities/README.md @@ -211,3 +211,32 @@ tac tail tar taskset tee time timeout top touch tr traceroute traceroute6 true truncate tty tunctl ulimit umount uname uniq unix2dos unlink unshare uptime usleep uudecode uuencode uuidgen vconfig vmstat watch wc which whoami xargs xxd yes zcat + +## Android R + +BSD: grep fsck\_msdos newfs\_msdos + +bzip2: bzcat bzip2 bunzip2 + +one-true-awk: awk + +toolbox: getevent getprop setprop start stop + +toybox: acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp +chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df +diff dirname dmesg dos2unix du echo egrep env expand expr fallocate +false fgrep file find flock fmt free freeramdisk fsfreeze getconf +getenforce getfattr grep groups gunzip gzip head help hostname hwclock +i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd insmod +install ionice iorenice iotop kill killall ln load\_policy log logname +losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom +mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint +mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe +paste patch pgrep pidof ping ping6 pivot\_root pkill pmap printenv +printf prlimit ps pwd pwdx readlink realpath renice restorecon rev +rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr +setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split +stat strings stty swapoff swapon sync sysctl tac tail tar taskset tee +time timeout top touch tr traceroute traceroute6 true truncate tty tunctl +ulimit umount uname uniq unix2dos unlink unshare uptime usleep uudecode +uuencode uuidgen vconfig vmstat watch wc which whoami xargs xxd yes zcat diff --git a/toolbox/Android.bp b/toolbox/Android.bp index 5289976c6..9ca56073d 100644 --- a/toolbox/Android.bp +++ b/toolbox/Android.bp @@ -28,6 +28,8 @@ cc_defaults { "toolbox.c", "getevent.c", "getprop.cpp", + "setprop.cpp", + "start.cpp", ], generated_headers: [ "toolbox_input_labels", @@ -40,6 +42,9 @@ cc_defaults { symlinks: [ "getevent", "getprop", + "setprop", + "start", + "stop", ], } diff --git a/toolbox/setprop.cpp b/toolbox/setprop.cpp new file mode 100644 index 000000000..acf8c3e61 --- /dev/null +++ b/toolbox/setprop.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 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 +#include +#include + +#include + +#include +#include + +using android::base::SetProperty; +using android::base::StartsWith; + +extern "C" int setprop_main(int argc, char** argv) { + if (argc != 3) { + std::cout << "usage: setprop NAME VALUE\n" + "\n" + "Sets an Android system property." + << std::endl; + return EXIT_FAILURE; + } + + auto name = std::string{argv[1]}; + auto value = std::string{argv[2]}; + + // SetProperty() doesn't tell us why it failed, and actually can't recognize most failures, so + // we duplicate some of init's checks here to help the user. + + if (name.front() == '.' || name.back() == '.') { + std::cerr << "Property names must not start or end with a '.'" << std::endl; + return EXIT_FAILURE; + } + + if (name.find("..") != std::string::npos) { + std::cerr << "'..' is not allowed in a property name" << std::endl; + return EXIT_FAILURE; + } + + for (const auto& c : name) { + if (!isalnum(c) && !strchr(":@_.-", c)) { + std::cerr << "Invalid character '" << c << "' in name '" << name << "'" << std::endl; + return EXIT_FAILURE; + } + } + + if (value.size() >= PROP_VALUE_MAX && !StartsWith(value, "ro.")) { + std::cerr << "Value '" << value << "' is too long, " << value.size() + << " bytes vs a max of " << PROP_VALUE_MAX << std::endl; + return EXIT_FAILURE; + } + + if (mbstowcs(nullptr, value.data(), 0) == static_cast(-1)) { + std::cerr << "Value '" << value << "' is not a UTF8 encoded string" << std::endl; + return EXIT_FAILURE; + } + + if (!SetProperty(name, value)) { + std::cerr << "Failed to set property '" << name << "' to '" << value + << "'.\nSee dmesg for error reason." << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/toolbox/start.cpp b/toolbox/start.cpp new file mode 100644 index 000000000..b87ed15a9 --- /dev/null +++ b/toolbox/start.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 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 +#include + +#include +#include +#include + +#include + +using android::base::GetProperty; +using android::base::SetProperty; +using namespace std::literals; + +static void ControlService(bool start, const std::string& service) { + if (!android::base::SetProperty(start ? "ctl.start" : "ctl.stop", service)) { + std::cerr << "Unable to " << (start ? "start" : "stop") << " service '" << service + << "'\nSee dmesg for error reason." << std::endl; + exit(EXIT_FAILURE); + } +} + +static void ControlDefaultServices(bool start) { + std::vector services = {"netd", "surfaceflinger", "zygote"}; + + // Only start zygote_secondary if not single arch. + std::string zygote_configuration = GetProperty("ro.zygote", ""); + if (zygote_configuration != "zygote32" && zygote_configuration != "zygote64") { + services.emplace_back("zygote_secondary"); + } + + if (start) { + for (const auto& service : services) { + ControlService(true, service); + } + } else { + for (auto it = services.crbegin(); it != services.crend(); ++it) { + ControlService(false, *it); + } + } +} + +static int StartStop(int argc, char** argv, bool start) { + if (getuid()) { + std::cerr << "Must be root" << std::endl; + return EXIT_FAILURE; + } + + if (argc == 1) { + ControlDefaultServices(start); + } + + if (argc == 2 && argv[1] == "--help"s) { + std::cout << "usage: " << (start ? "start" : "stop") + << " [SERVICE...]\n" + "\n" + << (start ? "Starts" : "Stops") + << " the given system service, or netd/surfaceflinger/zygotes." << std::endl; + return EXIT_SUCCESS; + } + + for (int i = 1; i < argc; ++i) { + ControlService(start, argv[i]); + } + return EXIT_SUCCESS; +} + +extern "C" int start_main(int argc, char** argv) { + return StartStop(argc, argv, true); +} + +extern "C" int stop_main(int argc, char** argv) { + return StartStop(argc, argv, false); +} \ No newline at end of file diff --git a/toolbox/tools.h b/toolbox/tools.h index abeb3ef24..9a7ebd228 100644 --- a/toolbox/tools.h +++ b/toolbox/tools.h @@ -1,3 +1,6 @@ TOOL(getevent) TOOL(getprop) +TOOL(setprop) +TOOL(start) +TOOL(stop) TOOL(toolbox)