Merge "Allow existance of partition to be checked before flashall or update"
diff --git a/adb/Android.bp b/adb/Android.bp
index 07f052f..906c5e3 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -277,26 +277,113 @@
},
}
+// libadbd_core contains the common sources to build libadbd and libadbd_services.
cc_library_static {
+ name: "libadbd_core",
+ defaults: ["adb_defaults"],
+ recovery_available: true,
+
+ // libminadbd wants both, as it's used to build native tests.
+ compile_multilib: "both",
+
+ srcs: libadb_srcs + libadb_posix_srcs + [
+ "daemon/auth.cpp",
+ "daemon/jdwp_service.cpp",
+ "daemon/usb.cpp",
+ ],
+
+ local_include_dirs: [
+ "daemon/include",
+ ],
+
+ static_libs: [
+ "libdiagnose_usb",
+ "libqemu_pipe",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "liblog",
+ ],
+}
+
+cc_library {
+ name: "libadbd_services",
+ defaults: ["adb_defaults"],
+ recovery_available: true,
+ compile_multilib: "both",
+
+ srcs: [
+ "daemon/file_sync_service.cpp",
+ "daemon/framebuffer_service.cpp",
+ "daemon/mdns.cpp",
+ "daemon/remount_service.cpp",
+ "daemon/services.cpp",
+ "daemon/set_verity_enable_state_service.cpp",
+ "daemon/shell_service.cpp",
+ "shell_service_protocol.cpp",
+ ],
+
+ cflags: [
+ "-D_GNU_SOURCE",
+ "-Wno-deprecated-declarations",
+ ],
+
+ static_libs: [
+ "libadbd_core",
+ "libavb_user",
+ "libdiagnose_usb",
+ "libqemu_pipe",
+
+ // `daemon/shell_service.cpp` uses selinux_android_setcon(), which is not exposed by
+ // libselinux.
+ "libselinux",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libbase",
+ "libbootloader_message",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "libext4_utils",
+ "libfec",
+ "libfec_rs",
+ "libfs_mgr",
+ "liblog",
+ "libmdnssd",
+ ],
+}
+
+cc_library {
name: "libadbd",
defaults: ["adb_defaults"],
recovery_available: true,
- // libminadbd wants both, for some reason.
+ // Avoid getting duplicate symbol of android::build::GetBuildNumber().
+ use_version_lib: false,
+
+ // libminadbd wants both, as it's used to build native tests.
compile_multilib: "both",
- srcs: libadb_srcs + libadb_posix_srcs + [
- "daemon/auth.cpp",
- "daemon/usb.cpp",
- "daemon/jdwp_service.cpp",
+
+ // libadbd doesn't build any additional source, but to expose libadbd_core as a shared library.
+ whole_static_libs: [
+ "libadbd_core",
],
- static_libs: [
+ shared_libs: [
+ "libadbd_services",
"libasyncio",
- "libcrypto_utils",
- "libcrypto",
- "libdiagnose_usb",
- "libqemu_pipe",
"libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "liblog",
],
export_include_dirs: [
@@ -307,19 +394,10 @@
cc_binary {
name: "adbd",
defaults: ["adb_defaults"],
-
recovery_available: true,
srcs: [
"daemon/main.cpp",
- "daemon/mdns.cpp",
- "daemon/file_sync_service.cpp",
- "daemon/framebuffer_service.cpp",
- "daemon/remount_service.cpp",
- "daemon/set_verity_enable_state_service.cpp",
- "daemon/services.cpp",
- "daemon/shell_service.cpp",
- "shell_service_protocol.cpp",
],
cflags: [
@@ -331,27 +409,16 @@
keep_symbols: true,
},
- static_libs: [
+ shared_libs: [
"libadbd",
- "libasyncio",
- "libavb_user",
- "libbootloader_message",
- "libcrypto_utils",
+ "libadbd_services",
+ "libbase",
+ "libcap",
"libcrypto",
- "libdiagnose_usb",
- "libfec",
- "libfec_rs",
- "libfs_mgr",
+ "libcutils",
"liblog",
- "libext4_utils",
- "libmdnssd",
"libminijail",
"libselinux",
- "libsquashfs_utils",
- "libqemu_pipe",
-
- "libbase",
- "libcutils",
],
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 3fb14f3..da273fd 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1925,7 +1925,8 @@
for (int i = argc - 1; i >= 0; i--) {
const char* file = argv[i];
- if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+ if (android::base::EndsWithIgnoreCase(file, ".apk") ||
+ android::base::EndsWithIgnoreCase(file, ".dm")) {
struct stat sb;
if (stat(file, &sb) != -1) total_size += sb.st_size;
first_apk = i;
@@ -1986,9 +1987,8 @@
}
std::string cmd = android::base::StringPrintf(
- "%s install-write -S %" PRIu64 " %d %d_%s -",
- install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i,
- android::base::Basename(file).c_str());
+ "%s install-write -S %" PRIu64 " %d %s -", install_cmd.c_str(),
+ static_cast<uint64_t>(sb.st_size), session_id, android::base::Basename(file).c_str());
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 1f59d64..dfcc52d 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -94,7 +94,7 @@
WriteFdExactly(fd.get(), "restarting in USB mode\n");
}
-bool reboot_service_impl(unique_fd fd, const std::string& arg) {
+void reboot_service(unique_fd fd, const std::string& arg) {
std::string reboot_arg = arg;
bool auto_reboot = false;
@@ -108,7 +108,7 @@
if (reboot_arg == "sideload") {
if (getuid() != 0) {
WriteFdExactly(fd.get(), "'adb root' is required for 'adb reboot sideload'.\n");
- return false;
+ return;
}
const std::vector<std::string> options = {auto_reboot ? "--sideload_auto_reboot"
@@ -116,7 +116,7 @@
std::string err;
if (!write_bootloader_message(options, &err)) {
D("Failed to set bootloader message: %s", err.c_str());
- return false;
+ return;
}
reboot_arg = "recovery";
@@ -128,16 +128,9 @@
std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
- return false;
- }
-
- return true;
-}
-
-void reboot_service(unique_fd fd, const std::string& arg) {
- if (!reboot_service_impl(std::move(fd), arg)) {
return;
}
+
// Don't return early. Give the reboot command time to take effect
// to avoid messing up scripts which do "adb reboot && adb wait-for-device"
while (true) {
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 9222008..3c74c75 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1190,17 +1190,11 @@
}
#endif // ADB_HOST
-int register_socket_transport(unique_fd s, const char* serial, int port, int local,
+int register_socket_transport(unique_fd s, std::string serial, int port, int local,
atransport::ReconnectCallback reconnect) {
atransport* t = new atransport(std::move(reconnect), kCsOffline);
- if (!serial) {
- char buf[32];
- snprintf(buf, sizeof(buf), "T-%p", t);
- serial = buf;
- }
-
- D("transport: %s init'ing for socket %d, on port %d", serial, s.get(), port);
+ D("transport: %s init'ing for socket %d, on port %d", serial.c_str(), s.get(), port);
if (init_socket_transport(t, std::move(s), port, local) < 0) {
delete t;
return -1;
@@ -1208,7 +1202,7 @@
std::unique_lock<std::recursive_mutex> lock(transport_lock);
for (const auto& transport : pending_list) {
- if (strcmp(serial, transport->serial.c_str()) == 0) {
+ if (serial == transport->serial) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in pending_list and fails to register";
delete t;
@@ -1217,7 +1211,7 @@
}
for (const auto& transport : transport_list) {
- if (strcmp(serial, transport->serial.c_str()) == 0) {
+ if (serial == transport->serial) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in transport_list and fails to register";
delete t;
@@ -1225,8 +1219,8 @@
}
}
+ t->serial = std::move(serial);
pending_list.push_front(t);
- t->serial = serial;
lock.unlock();
diff --git a/adb/transport.h b/adb/transport.h
index 1844ae8..4bfc2ce 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -364,7 +364,7 @@
void connect_device(const std::string& address, std::string* response);
/* cause new transports to be init'd and added to the list */
-int register_socket_transport(unique_fd s, const char* serial, int port, int local,
+int register_socket_transport(unique_fd s, std::string serial, int port, int local,
atransport::ReconnectCallback reconnect);
// This should only be used for transports with connection_state == kCsNoPerm.
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 9398ceb..b20dee9 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -125,8 +125,7 @@
return init_socket_transport(t, std::move(fd), port, 0) >= 0;
};
- int ret =
- register_socket_transport(std::move(fd), serial.c_str(), port, 0, std::move(reconnect));
+ int ret = register_socket_transport(std::move(fd), serial, port, 0, std::move(reconnect));
if (ret < 0) {
if (ret == -EALREADY) {
*response = android::base::StringPrintf("already connected to %s", serial.c_str());
@@ -162,7 +161,7 @@
close_on_exec(fd.get());
disable_tcp_nagle(fd.get());
std::string serial = getEmulatorSerialString(console_port);
- if (register_socket_transport(std::move(fd), serial.c_str(), adb_port, 1,
+ if (register_socket_transport(std::move(fd), std::move(serial), adb_port, 1,
[](atransport*) { return false; }) == 0) {
return 0;
}
@@ -265,7 +264,7 @@
close_on_exec(fd.get());
disable_tcp_nagle(fd.get());
std::string serial = android::base::StringPrintf("host-%d", fd.get());
- register_socket_transport(std::move(fd), serial.c_str(), port, 1,
+ register_socket_transport(std::move(fd), std::move(serial), port, 1,
[](atransport*) { return false; });
}
}
@@ -362,7 +361,7 @@
* exchange. */
std::string serial = android::base::StringPrintf("host-%d", fd.get());
WriteFdExactly(fd.get(), _start_req, strlen(_start_req));
- register_socket_transport(std::move(fd), serial.c_str(), port, 1,
+ register_socket_transport(std::move(fd), std::move(serial), port, 1,
[](atransport*) { return false; });
}
@@ -454,10 +453,6 @@
return it->second;
}
-std::string getEmulatorSerialString(int console_port) {
- return android::base::StringPrintf("emulator-%d", console_port);
-}
-
atransport* find_emulator_transport_by_adb_port(int adb_port) {
std::lock_guard<std::mutex> lock(local_transports_lock);
return find_emulator_transport_by_adb_port_locked(adb_port);
@@ -468,6 +463,10 @@
}
#endif
+std::string getEmulatorSerialString(int console_port) {
+ return android::base::StringPrintf("emulator-%d", console_port);
+}
+
int init_socket_transport(atransport* t, unique_fd fd, int adb_port, int local) {
int fail = 0;
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 2b4a954..51cc62a 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -1,3 +1,17 @@
+// 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.
+
cc_library_host_static {
name: "libfastboot2",
@@ -54,3 +68,54 @@
export_include_dirs: ["."],
}
+
+cc_defaults {
+ name: "fastboot_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wvla",
+ ],
+ rtti: true,
+
+ clang_cflags: [
+ "-Wthread-safety",
+ ],
+}
+
+cc_binary {
+ name: "fastbootd",
+ defaults: ["fastboot_defaults"],
+
+ recovery: true,
+
+ srcs: [
+ "device/commands.cpp",
+ "device/fastboot_device.cpp",
+ "device/main.cpp",
+ "device/usb_client.cpp",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libext4_utils",
+ "libsparse",
+ "liblog",
+ "libbootloader_message",
+ "libhidltransport",
+ "libhidlbase",
+ "libhwbinder",
+ "libbase",
+ "libutils",
+ "libcutils",
+ "libfs_mgr",
+ ],
+
+ static_libs: [
+ "libadbd",
+ ],
+
+ cpp_std: "c++17",
+}
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 5e7e955..7caca3d 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -27,6 +27,8 @@
#define FB_CMD_REBOOT "reboot"
#define FB_CMD_SHUTDOWN "shutdown"
#define FB_CMD_REBOOT_BOOTLOADER "reboot-bootloader"
+#define FB_CMD_REBOOT_RECOVERY "reboot-recovery"
+#define FB_CMD_REBOOT_FASTBOOT "reboot-fastboot"
#define FB_CMD_POWERDOWN "powerdown"
#define RESPONSE_OKAY "OKAY"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
new file mode 100644
index 0000000..a3cbf96
--- /dev/null
+++ b/fastboot/device/commands.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#include "commands.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/android_reboot.h>
+
+#include "fastboot_device.h"
+
+bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
+ }
+ // arg[0] is the command name, arg[1] contains size of data to be downloaded
+ unsigned int size;
+ if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) {
+ return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
+ }
+ device->get_download_data().resize(size);
+ if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
+ return false;
+ }
+
+ if (device->HandleData(true, &device->get_download_data())) {
+ return device->WriteStatus(FastbootResult::OKAY, "");
+ }
+
+ PLOG(ERROR) << "Couldn't download data";
+ return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
+}
+
+bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteStatus(FastbootResult::OKAY, "");
+}
+
+bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+static bool EnterRecovery() {
+ const char msg_switch_to_recovery = 'r';
+
+ android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
+ if (sock < 0) {
+ PLOG(ERROR) << "Couldn't create sock";
+ return false;
+ }
+
+ struct sockaddr_un addr = {.sun_family = AF_UNIX};
+ strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
+ if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ PLOG(ERROR) << "Couldn't connect to recovery";
+ return false;
+ }
+ // Switch to recovery will not update the boot reason since it does not
+ // require a reboot.
+ auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
+ if (ret != sizeof(msg_switch_to_recovery)) {
+ PLOG(ERROR) << "Couldn't write message to switch to recovery";
+ return false;
+ }
+
+ return true;
+}
+
+bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto status = true;
+ if (EnterRecovery()) {
+ status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
+ } else {
+ status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
+ }
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return status;
+}
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
new file mode 100644
index 0000000..cd984c8
--- /dev/null
+++ b/fastboot/device/commands.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <functional>
+#include <string>
+#include <vector>
+
+class FastbootDevice;
+
+enum class FastbootResult {
+ OKAY,
+ FAIL,
+ INFO,
+ DATA,
+};
+
+// Execute a command with the given arguments (possibly empty).
+using CommandHandler = std::function<bool(FastbootDevice*, const std::vector<std::string>&)>;
+
+bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
new file mode 100644
index 0000000..4c3d23f
--- /dev/null
+++ b/fastboot/device/fastboot_device.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#include "fastboot_device.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include <algorithm>
+
+#include "constants.h"
+#include "usb_client.h"
+
+FastbootDevice::FastbootDevice()
+ : kCommandMap({
+ {FB_CMD_SET_ACTIVE, SetActiveHandler},
+ {FB_CMD_DOWNLOAD, DownloadHandler},
+ {FB_CMD_SHUTDOWN, ShutDownHandler},
+ {FB_CMD_REBOOT, RebootHandler},
+ {FB_CMD_REBOOT_BOOTLOADER, RebootBootloaderHandler},
+ {FB_CMD_REBOOT_FASTBOOT, RebootFastbootHandler},
+ {FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler},
+ }),
+ transport_(std::make_unique<ClientUsbTransport>()) {}
+
+FastbootDevice::~FastbootDevice() {
+ CloseDevice();
+}
+
+void FastbootDevice::CloseDevice() {
+ transport_->Close();
+}
+
+bool FastbootDevice::WriteStatus(FastbootResult result, const std::string& message) {
+ constexpr size_t kResponseReasonSize = 4;
+ constexpr size_t kNumResponseTypes = 4; // "FAIL", "OKAY", "INFO", "DATA"
+ char buf[FB_RESPONSE_SZ];
+ constexpr size_t kMaxMessageSize = sizeof(buf) - kResponseReasonSize;
+ size_t msg_len = std::min(kMaxMessageSize, message.size());
+
+ constexpr const char* kResultStrings[kNumResponseTypes] = {RESPONSE_OKAY, RESPONSE_FAIL,
+ RESPONSE_INFO, RESPONSE_DATA};
+
+ if (static_cast<size_t>(result) >= kNumResponseTypes) {
+ return false;
+ }
+
+ memcpy(buf, kResultStrings[static_cast<size_t>(result)], kResponseReasonSize);
+ memcpy(buf + kResponseReasonSize, message.c_str(), msg_len);
+
+ size_t response_len = kResponseReasonSize + msg_len;
+ auto write_ret = this->get_transport()->Write(buf, response_len);
+ if (write_ret != static_cast<ssize_t>(response_len)) {
+ PLOG(ERROR) << "Failed to write " << message;
+ return false;
+ }
+
+ return true;
+}
+
+bool FastbootDevice::HandleData(bool read, std::vector<char>* data) {
+ auto read_write_data_size = read ? this->get_transport()->Read(data->data(), data->size())
+ : this->get_transport()->Write(data->data(), data->size());
+ if (read_write_data_size == -1 || static_cast<size_t>(read_write_data_size) != data->size()) {
+ return false;
+ }
+ return true;
+}
+
+void FastbootDevice::ExecuteCommands() {
+ char command[FB_RESPONSE_SZ + 1];
+ for (;;) {
+ auto bytes_read = transport_->Read(command, FB_RESPONSE_SZ);
+ if (bytes_read == -1) {
+ PLOG(ERROR) << "Couldn't read command";
+ return;
+ }
+ command[bytes_read] = '\0';
+
+ LOG(INFO) << "Fastboot command: " << command;
+ auto args = android::base::Split(command, ":");
+ auto found_command = kCommandMap.find(args[0]);
+ if (found_command == kCommandMap.end()) {
+ WriteStatus(FastbootResult::FAIL, "Unrecognized command");
+ continue;
+ }
+ if (!found_command->second(this, args)) {
+ return;
+ }
+ }
+}
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
new file mode 100644
index 0000000..fec42a7
--- /dev/null
+++ b/fastboot/device/fastboot_device.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "commands.h"
+#include "transport.h"
+
+class FastbootDevice;
+
+class FastbootDevice {
+ public:
+ FastbootDevice();
+ ~FastbootDevice();
+
+ void CloseDevice();
+ void ExecuteCommands();
+ bool WriteStatus(FastbootResult result, const std::string& message);
+ bool HandleData(bool read, std::vector<char>* data);
+
+ std::vector<char>& get_download_data() { return download_data_; }
+ void set_upload_data(const std::vector<char>& data) { upload_data_ = data; }
+ void set_upload_data(std::vector<char>&& data) { upload_data_ = std::move(data); }
+ Transport* get_transport() { return transport_.get(); }
+
+ private:
+ const std::unordered_map<std::string, CommandHandler> kCommandMap;
+
+ std::unique_ptr<Transport> transport_;
+
+ std::vector<char> download_data_;
+ std::vector<char> upload_data_;
+};
diff --git a/init/watchdogd.h b/fastboot/device/main.cpp
similarity index 63%
rename from init/watchdogd.h
rename to fastboot/device/main.cpp
index 73f77d5..df9c900 100644
--- a/init/watchdogd.h
+++ b/fastboot/device/main.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+#include <android-base/logging.h>
-namespace android {
-namespace init {
+#include "fastboot_device.h"
-int watchdogd_main(int argc, char **argv);
+int main(int /*argc*/, char* argv[]) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
-} // namespace init
-} // namespace android
-
-#endif
+ while (true) {
+ FastbootDevice device;
+ device.ExecuteCommands();
+ }
+}
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
new file mode 100644
index 0000000..215f99a
--- /dev/null
+++ b/fastboot/device/usb_client.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+#include "usb_client.h"
+
+#include <endian.h>
+#include <fcntl.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+constexpr int kMaxPacketSizeFs = 64;
+constexpr int kMaxPacketSizeHs = 512;
+constexpr int kMaxPacketsizeSs = 1024;
+
+constexpr size_t kFbFfsNumBufs = 16;
+constexpr size_t kFbFfsBufSize = 32768;
+
+constexpr const char* kUsbFfsFastbootEp0 = "/dev/usb-ffs/fastboot/ep0";
+constexpr const char* kUsbFfsFastbootOut = "/dev/usb-ffs/fastboot/ep1";
+constexpr const char* kUsbFfsFastbootIn = "/dev/usb-ffs/fastboot/ep2";
+
+struct FuncDesc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_endpoint_descriptor_no_audio sink;
+} __attribute__((packed));
+
+struct SsFuncDesc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+} __attribute__((packed));
+
+struct DescV2 {
+ struct usb_functionfs_descs_head_v2 header;
+ // The rest of the structure depends on the flags in the header.
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
+ struct FuncDesc fs_descs, hs_descs;
+ struct SsFuncDesc ss_descs;
+} __attribute__((packed));
+
+struct usb_interface_descriptor fastboot_interface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 66,
+ .bInterfaceProtocol = 3,
+ .iInterface = 1, /* first string from the provided table */
+};
+
+static struct FuncDesc fs_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(fs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeFs,
+ },
+ .sink =
+ {
+ .bLength = sizeof(fs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeFs,
+ },
+};
+
+static struct FuncDesc hs_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(hs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeHs,
+ },
+ .sink =
+ {
+ .bLength = sizeof(hs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeHs,
+ },
+};
+
+static struct SsFuncDesc ss_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(ss_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketsizeSs,
+ },
+ .source_comp =
+ {
+ .bLength = sizeof(ss_descriptors.source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 15,
+ },
+ .sink =
+ {
+ .bLength = sizeof(ss_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketsizeSs,
+ },
+ .sink_comp =
+ {
+ .bLength = sizeof(ss_descriptors.sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 15,
+ },
+};
+
+#define STR_INTERFACE_ "fastboot"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE_)];
+ } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+ .header =
+ {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 =
+ {
+ htole16(0x0409), /* en-us */
+ STR_INTERFACE_,
+ },
+};
+
+static struct DescV2 v2_descriptor = {
+ .header =
+ {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(v2_descriptor)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC,
+ },
+ .fs_count = 3,
+ .hs_count = 3,
+ .ss_count = 5,
+ .fs_descs = fs_descriptors,
+ .hs_descs = hs_descriptors,
+ .ss_descs = ss_descriptors,
+};
+
+// Reimplementing since usb_ffs_close() does not close the control FD.
+static void CloseFunctionFs(usb_handle* h) {
+ if (h->bulk_in > 0) {
+ close(h->bulk_in);
+ h->bulk_in = -1;
+ }
+ if (h->bulk_out > 0) {
+ close(h->bulk_out);
+ h->bulk_out = -1;
+ }
+ if (h->control > 0) {
+ close(h->control);
+ h->control = -1;
+ }
+}
+
+static bool InitFunctionFs(usb_handle* h) {
+ LOG(INFO) << "initializing functionfs";
+
+ if (h->control < 0) { // might have already done this before
+ LOG(INFO) << "opening control endpoint " << kUsbFfsFastbootEp0;
+ h->control = open(kUsbFfsFastbootEp0, O_RDWR);
+ if (h->control < 0) {
+ PLOG(ERROR) << "cannot open control endpoint " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+
+ auto ret = write(h->control, &v2_descriptor, sizeof(v2_descriptor));
+ if (ret < 0) {
+ PLOG(ERROR) << "cannot write descriptors " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+
+ ret = write(h->control, &strings, sizeof(strings));
+ if (ret < 0) {
+ PLOG(ERROR) << "cannot write strings " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+ // Signal only when writing the descriptors to ffs
+ android::base::SetProperty("sys.usb.ffs.ready", "1");
+ }
+
+ h->bulk_out = open(kUsbFfsFastbootOut, O_RDONLY);
+ if (h->bulk_out < 0) {
+ PLOG(ERROR) << "cannot open bulk-out endpoint " << kUsbFfsFastbootOut;
+ goto err;
+ }
+
+ h->bulk_in = open(kUsbFfsFastbootIn, O_WRONLY);
+ if (h->bulk_in < 0) {
+ PLOG(ERROR) << "cannot open bulk-in endpoint " << kUsbFfsFastbootIn;
+ goto err;
+ }
+
+ h->read_aiob.fd = h->bulk_out;
+ h->write_aiob.fd = h->bulk_in;
+ h->reads_zero_packets = false;
+ return true;
+
+err:
+ CloseFunctionFs(h);
+ return false;
+}
+
+ClientUsbTransport::ClientUsbTransport()
+ : handle_(std::unique_ptr<usb_handle>(create_usb_handle(kFbFfsNumBufs, kFbFfsBufSize))) {
+ if (!InitFunctionFs(handle_.get())) {
+ handle_.reset(nullptr);
+ }
+}
+
+ssize_t ClientUsbTransport::Read(void* data, size_t len) {
+ if (handle_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+ char* char_data = static_cast<char*>(data);
+ size_t bytes_read_total = 0;
+ while (bytes_read_total < len) {
+ auto bytes_to_read = std::min(len - bytes_read_total, kFbFfsNumBufs * kFbFfsBufSize);
+ auto bytes_read_now = handle_->read(handle_.get(), char_data, bytes_to_read);
+ if (bytes_read_now < 0) {
+ return bytes_read_total;
+ }
+ bytes_read_total += bytes_read_now;
+ char_data += bytes_read_now;
+ if (static_cast<size_t>(bytes_read_now) < bytes_to_read) {
+ break;
+ }
+ }
+ return bytes_read_total;
+}
+
+ssize_t ClientUsbTransport::Write(const void* data, size_t len) {
+ if (handle_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+ const char* char_data = reinterpret_cast<const char*>(data);
+ size_t bytes_written_total = 0;
+ while (bytes_written_total < len) {
+ auto bytes_to_write = std::min(len - bytes_written_total, kFbFfsNumBufs * kFbFfsBufSize);
+ auto bytes_written_now = handle_->write(handle_.get(), data, bytes_to_write);
+ if (bytes_written_now < 0) {
+ return bytes_written_total;
+ }
+ bytes_written_total += bytes_written_now;
+ char_data += bytes_written_now;
+ if (static_cast<size_t>(bytes_written_now) < bytes_to_write) {
+ break;
+ }
+ }
+ return bytes_written_total;
+}
+
+int ClientUsbTransport::Close() {
+ if (handle_ == nullptr) {
+ return -1;
+ }
+ CloseFunctionFs(handle_.get());
+ return 0;
+}
diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h
new file mode 100644
index 0000000..3694f9a
--- /dev/null
+++ b/fastboot/device/usb_client.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include <adbd/usb.h>
+
+#include "transport.h"
+
+class ClientUsbTransport : public Transport {
+ public:
+ ClientUsbTransport();
+ ~ClientUsbTransport() override = default;
+
+ ssize_t Read(void* data, size_t len) override;
+ ssize_t Write(const void* data, size_t len) override;
+ int Close() override;
+
+ private:
+ std::unique_ptr<usb_handle> handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientUsbTransport);
+};
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 620be3b..d787d09 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1363,6 +1363,8 @@
bool wants_wipe = false;
bool wants_reboot = false;
bool wants_reboot_bootloader = false;
+ bool wants_reboot_recovery = false;
+ bool wants_reboot_fastboot = false;
bool skip_reboot = false;
bool wants_set_active = false;
bool skip_secondary = false;
@@ -1585,6 +1587,12 @@
if (what == "bootloader") {
wants_reboot = false;
wants_reboot_bootloader = true;
+ } else if (what == "recovery") {
+ wants_reboot = false;
+ wants_reboot_recovery = true;
+ } else if (what == "fastboot") {
+ wants_reboot = false;
+ wants_reboot_fastboot = true;
} else {
syntax_error("unknown reboot target %s", what.c_str());
}
@@ -1593,6 +1601,10 @@
if (!args.empty()) syntax_error("junk after reboot command");
} else if (command == "reboot-bootloader") {
wants_reboot_bootloader = true;
+ } else if (command == "reboot-recovery") {
+ wants_reboot_recovery = true;
+ } else if (command == "reboot-fastboot") {
+ wants_reboot_fastboot = true;
} else if (command == "continue") {
fb_queue_command("continue", "resuming boot");
} else if (command == "boot") {
@@ -1710,6 +1722,12 @@
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
fb_queue_wait_for_disconnect();
+ } else if (wants_reboot_recovery) {
+ fb_queue_command("reboot-recovery", "rebooting into recovery");
+ fb_queue_wait_for_disconnect();
+ } else if (wants_reboot_fastboot) {
+ fb_queue_command("reboot-fastboot", "rebooting into fastboot");
+ fb_queue_wait_for_disconnect();
}
int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index aabc620..55ca65d 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -134,7 +134,7 @@
return ret;
}
- std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:d:]]+)");
+ std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
std::smatch sm;
for (auto& s : all) {
@@ -264,11 +264,16 @@
std::vector<std::string>* info) {
RetCode ret;
int dsize;
- if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize)) || dsize == 0) {
- error_ = "Upload request failed";
+ if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize))) {
+ error_ = "Upload request failed: " + error_;
return ret;
}
+ if (!dsize) {
+ error_ = "Upload request failed, device reports 0 bytes available";
+ return BAD_DEV_RESP;
+ }
+
std::vector<char> data;
data.resize(dsize);
@@ -462,10 +467,10 @@
}
RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
+ // ioctl on 0-length buffer causes freezing
if (!size) {
- return SUCCESS;
+ return BAD_ARG;
}
-
// Write the buffer
ssize_t tmp = transport->Write(buf, size);
@@ -521,7 +526,7 @@
// Now we need to send a multiple of chunk size
size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
- if (SendBuffer(data + total, nbytes)) {
+ if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
error_ = ErrnoStr("Send failed in SparseWriteCallback()");
return -1;
}
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 9fdd317..e8711cb 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -103,7 +103,7 @@
/* HELPERS */
void SetInfoCallback(std::function<void(std::string&)> info);
- const std::string RCString(RetCode rc);
+ static const std::string RCString(RetCode rc);
std::string Error();
RetCode WaitForDisconnect();
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 05e03e1..aa68ceb 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -133,7 +133,11 @@
bool DestroyLogicalPartition(const std::string& name) {
DeviceMapper& dm = DeviceMapper::Instance();
- return dm.DeleteDevice(name);
+ if (!dm.DeleteDevice(name)) {
+ return false;
+ }
+ LINFO << "Unmapped logical partition " << name;
+ return true;
}
} // namespace fs_mgr
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index eb429b9..2015e4d 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -84,6 +84,19 @@
void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
size_ += extent->num_sectors() * LP_SECTOR_SIZE;
+
+ if (LinearExtent* new_extent = extent->AsLinearExtent()) {
+ if (!extents_.empty() && extents_.back()->AsLinearExtent() &&
+ extents_.back()->AsLinearExtent()->end_sector() == new_extent->physical_sector()) {
+ // If the previous extent can be merged into this new one, do so
+ // to avoid creating unnecessary extents.
+ LinearExtent* prev_extent = extents_.back()->AsLinearExtent();
+ extent = std::make_unique<LinearExtent>(
+ prev_extent->num_sectors() + new_extent->num_sectors(),
+ prev_extent->physical_sector());
+ extents_.pop_back();
+ }
+ }
extents_.push_back(std::move(extent));
}
@@ -498,13 +511,18 @@
bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
// Align the space needed up to the nearest sector.
uint64_t aligned_size = AlignTo(requested_size, device_info_.logical_block_size);
+ uint64_t old_size = partition->size();
- if (aligned_size > partition->size()) {
- return GrowPartition(partition, aligned_size);
- }
- if (aligned_size < partition->size()) {
+ if (aligned_size > old_size) {
+ if (!GrowPartition(partition, aligned_size)) {
+ return false;
+ }
+ } else if (aligned_size < partition->size()) {
ShrinkPartition(partition, aligned_size);
}
+
+ LINFO << "Partition " << partition->name() << " will resize from " << old_size << " bytes to "
+ << aligned_size << " bytes";
return true;
}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index f1a91c4..da9c8f3 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -69,6 +69,11 @@
EXPECT_EQ(system->size(), 131072);
EXPECT_EQ(system->extents().size(), 1);
EXPECT_EQ(system->extents()[0]->num_sectors(), 131072 / LP_SECTOR_SIZE);
+ // Test resizing again, that the extents are merged together.
+ builder->ResizePartition(system, 1024 * 256);
+ EXPECT_EQ(system->size(), 1024 * 256);
+ EXPECT_EQ(system->extents().size(), 1);
+ EXPECT_EQ(system->extents()[0]->num_sectors(), (1024 * 256) / LP_SECTOR_SIZE);
// Test shrinking within the same extent.
builder->ResizePartition(system, 32768);
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index e83b922..a35cf8e 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -81,6 +81,7 @@
LinearExtent* AsLinearExtent() override { return this; }
uint64_t physical_sector() const { return physical_sector_; }
+ uint64_t end_sector() const { return physical_sector_ + num_sectors_; }
private:
uint64_t physical_sector_;
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 4522275..6ef5124 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -26,6 +26,8 @@
#include "liblp/metadata_format.h"
#define LP_TAG "[liblp]"
+#define LWARN LOG(WARNING) << LP_TAG
+#define LINFO LOG(INFO) << LP_TAG
#define LERROR LOG(ERROR) << LP_TAG
#define PERROR PLOG(ERROR) << LP_TAG
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 156319b..fc9d83f 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -304,7 +304,11 @@
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return false;
}
- return FlashPartitionTable(fd, metadata, slot_number);
+ if (!FlashPartitionTable(fd, metadata, slot_number)) {
+ return false;
+ }
+ LWARN << "Flashed new logical partition geometry to " << block_device;
+ return true;
}
bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
@@ -314,7 +318,12 @@
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return false;
}
- return UpdatePartitionTable(fd, metadata, slot_number);
+ if (!UpdatePartitionTable(fd, metadata, slot_number)) {
+ return false;
+ }
+ LINFO << "Updated logical partition table at slot " << slot_number << " on device "
+ << block_device;
+ return true;
}
bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
diff --git a/init/Android.bp b/init/Android.bp
index 660d586..d42ab8a 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -107,6 +107,7 @@
"first_stage_mount.cpp",
"import_parser.cpp",
"init.cpp",
+ "init_first_stage.cpp",
"keychords.cpp",
"modalias_handler.cpp",
"parser.cpp",
@@ -115,6 +116,7 @@
"property_service.cpp",
"property_type.cpp",
"reboot.cpp",
+ "reboot_utils.cpp",
"security.cpp",
"selinux.cpp",
"service.cpp",
@@ -127,7 +129,6 @@
"ueventd.cpp",
"ueventd_parser.cpp",
"util.cpp",
- "watchdogd.cpp",
],
whole_static_libs: ["libcap"],
header_libs: ["bootimg_headers"],
@@ -157,7 +158,6 @@
srcs: ["main.cpp"],
symlinks: [
"sbin/ueventd",
- "sbin/watchdogd",
],
}
*/
diff --git a/init/Android.mk b/init/Android.mk
index d0cb820..9d9d368 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -98,7 +98,6 @@
# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
- ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_EXECUTABLE)
diff --git a/init/devices.cpp b/init/devices.cpp
index ba08180..58c8b2e 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -34,7 +34,7 @@
#include "util.h"
#ifdef _INIT_INIT_H
-#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
+#error "Do not include init.h in files used by ueventd; it will expose init's globals"
#endif
using android::base::Basename;
diff --git a/init/host_init_stubs.cpp b/init/host_init_stubs.cpp
index 2352fc7..8866bdc 100644
--- a/init/host_init_stubs.cpp
+++ b/init/host_init_stubs.cpp
@@ -41,10 +41,9 @@
}
// selinux.h
-bool SelinuxHasVendorInit() {
- return true;
+int SelinuxGetVendorAndroidVersion() {
+ return 10000;
}
-
void SelabelInitialize() {}
bool SelabelLookupFileContext(const std::string& key, int type, std::string* result) {
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index f0e1f07..0af11f6 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -23,6 +23,9 @@
#include <string>
+// android/api-level.h
+#define __ANDROID_API_P__ 28
+
// sys/system_properties.h
#define PROP_VALUE_MAX 92
@@ -41,7 +44,7 @@
const std::string& source_context, const ucred& cr, std::string* error);
// selinux.h
-bool SelinuxHasVendorInit();
+int SelinuxGetVendorAndroidVersion();
void SelabelInitialize();
bool SelabelLookupFileContext(const std::string& key, int type, std::string* result);
diff --git a/init/init.cpp b/init/init.cpp
index 7ad9ec3..ad80c98 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,15 +18,12 @@
#include <dirent.h>
#include <fcntl.h>
-#include <paths.h>
#include <pthread.h>
-#include <seccomp_policy.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
-#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
@@ -43,8 +40,6 @@
#include <cutils/android_reboot.h>
#include <keyutils.h>
#include <libavb/libavb.h>
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
#include "action_parser.h"
#include "epoll.h"
@@ -53,12 +48,12 @@
#include "keychords.h"
#include "property_service.h"
#include "reboot.h"
+#include "reboot_utils.h"
#include "security.h"
#include "selinux.h"
#include "sigchld_handler.h"
#include "ueventd.h"
#include "util.h"
-#include "watchdogd.h"
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -418,14 +413,6 @@
return Success();
}
-static void global_seccomp() {
- import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
- LOG(FATAL) << "Failed to globally enable seccomp!";
- }
- });
-}
-
// Set the UDC controller for the ConfigFS USB Gadgets.
// Read the UDC controller in use from "/sys/class/udc".
// In case of multiple UDC controllers select the first one.
@@ -442,40 +429,6 @@
}
}
-static void InstallRebootSignalHandlers() {
- // Instead of panic'ing the kernel as is the default behavior when init crashes,
- // we prefer to reboot to bootloader on development builds, as this will prevent
- // boot looping bad configurations and allow both developers and test farms to easily
- // recover.
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- sigfillset(&action.sa_mask);
- action.sa_handler = [](int signal) {
- // These signal handlers are also caught for processes forked from init, however we do not
- // want them to trigger reboot, so we directly call _exit() for children processes here.
- if (getpid() != 1) {
- _exit(signal);
- }
-
- // Calling DoReboot() or LOG(FATAL) is not a good option as this is a signal handler.
- // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
- // and probably good enough given this is already an error case and only enabled for
- // development builds.
- RebootSystem(ANDROID_RB_RESTART2, "bootloader");
- };
- action.sa_flags = SA_RESTART;
- sigaction(SIGABRT, &action, nullptr);
- sigaction(SIGBUS, &action, nullptr);
- sigaction(SIGFPE, &action, nullptr);
- sigaction(SIGILL, &action, nullptr);
- sigaction(SIGSEGV, &action, nullptr);
-#if defined(SIGSTKFLT)
- sigaction(SIGSTKFLT, &action, nullptr);
-#endif
- sigaction(SIGSYS, &action, nullptr);
- sigaction(SIGTRAP, &action, nullptr);
-}
-
static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
if (siginfo.ssi_pid != 0) {
// Drop any userspace SIGTERM requests.
@@ -612,129 +565,27 @@
android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
}
+int first_stage_main(int argc, char** argv);
+
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
- if (!strcmp(basename(argv[0]), "watchdogd")) {
- return watchdogd_main(argc, argv);
- }
-
if (argc > 1 && !strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
+ if (getenv("INIT_SECOND_STAGE") == nullptr) {
+ return first_stage_main(argc, argv);
+ }
+
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
- bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
-
- if (is_first_stage) {
- boot_clock::time_point start_time = boot_clock::now();
-
- std::vector<std::pair<std::string, int>> errors;
-#define CHECKCALL(x) \
- if (x != 0) errors.emplace_back(#x " failed", errno);
-
- // Clear the umask.
- umask(0);
-
- CHECKCALL(clearenv());
- CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
- // Get the basic filesystem setup we need put together in the initramdisk
- // on / and then we'll let the rc file figure out the rest.
- CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
- CHECKCALL(mkdir("/dev/pts", 0755));
- CHECKCALL(mkdir("/dev/socket", 0755));
- CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
-#define MAKE_STR(x) __STRING(x)
- CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
-#undef MAKE_STR
- // Don't expose the raw commandline to unprivileged processes.
- CHECKCALL(chmod("/proc/cmdline", 0440));
- gid_t groups[] = { AID_READPROC };
- CHECKCALL(setgroups(arraysize(groups), groups));
- CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
- CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
-
- CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
-
- if constexpr (WORLD_WRITABLE_KMSG) {
- CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
- }
-
- CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
- CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
-
- // This is needed for log wrapper, which gets called before ueventd runs.
- CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
- CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
-
- // Mount staging areas for devices managed by vold
- // See storage config details at http://source.android.com/devices/storage/
- CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
- "mode=0755,uid=0,gid=1000"));
- // /mnt/vendor is used to mount vendor-specific partitions that can not be
- // part of the vendor partition, e.g. because they are mounted read-write.
- CHECKCALL(mkdir("/mnt/vendor", 0755));
- // /mnt/product is used to mount product-specific partitions that can not be
- // part of the product partition, e.g. because they are mounted read-write.
- CHECKCALL(mkdir("/mnt/product", 0755));
-
-#undef CHECKCALL
-
- // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
- // talk to the outside world...
- InitKernelLogging(argv);
-
- if (!errors.empty()) {
- for (const auto& [error_string, error_errno] : errors) {
- LOG(ERROR) << error_string << " " << strerror(error_errno);
- }
- LOG(FATAL) << "Init encountered errors starting first stage, aborting";
- }
-
- LOG(INFO) << "init first stage started!";
-
- if (!DoFirstStageMount()) {
- LOG(FATAL) << "Failed to mount required partitions early ...";
- }
-
- SetInitAvbVersionInRecovery();
-
- // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
- global_seccomp();
-
- // Set up SELinux, loading the SELinux policy.
- SelinuxSetupKernelLogging();
- SelinuxInitialize();
-
- // We're in the kernel domain, so re-exec init to transition to the init domain now
- // that the SELinux policy has been loaded.
- if (selinux_android_restorecon("/init", 0) == -1) {
- PLOG(FATAL) << "restorecon failed of /init failed";
- }
-
- setenv("INIT_SECOND_STAGE", "true", 1);
-
- static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
- uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
- setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
-
- char* path = argv[0];
- char* args[] = { path, nullptr };
- execv(path, args);
-
- // execv() only returns if an error happened, in which case we
- // panic and never fall through this conditional.
- PLOG(FATAL) << "execv(\"" << path << "\") failed";
- }
-
- // At this point we're in the second stage of init.
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
diff --git a/init/init.h b/init/init.h
index 6c82fa1..f244ad7 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,8 +31,8 @@
namespace android {
namespace init {
-// Note: These globals are *only* valid in init, so they should not be used in ueventd,
-// watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
+// Note: These globals are *only* valid in init, so they should not be used in ueventd
+// or any files that may be included in ueventd, such as devices.cpp and util.cpp.
// TODO: Have an Init class and remove all globals.
extern std::string default_console;
extern std::vector<std::string> late_import_paths;
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
new file mode 100644
index 0000000..ef9ce81
--- /dev/null
+++ b/init/init_first_stage.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include <paths.h>
+#include <seccomp_policy.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <cutils/android_reboot.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
+#include "first_stage_mount.h"
+#include "reboot_utils.h"
+#include "selinux.h"
+#include "util.h"
+
+using android::base::boot_clock;
+
+namespace android {
+namespace init {
+
+static void GlobalSeccomp() {
+ import_kernel_cmdline(false, [](const std::string& key, const std::string& value,
+ bool in_qemu) {
+ if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
+ LOG(FATAL) << "Failed to globally enable seccomp!";
+ }
+ });
+}
+
+int first_stage_main(int argc, char** argv) {
+ if (REBOOT_BOOTLOADER_ON_PANIC) {
+ InstallRebootSignalHandlers();
+ }
+
+ boot_clock::time_point start_time = boot_clock::now();
+
+ std::vector<std::pair<std::string, int>> errors;
+#define CHECKCALL(x) \
+ if (x != 0) errors.emplace_back(#x " failed", errno);
+
+ // Clear the umask.
+ umask(0);
+
+ CHECKCALL(clearenv());
+ CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
+ // Get the basic filesystem setup we need put together in the initramdisk
+ // on / and then we'll let the rc file figure out the rest.
+ CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
+ CHECKCALL(mkdir("/dev/pts", 0755));
+ CHECKCALL(mkdir("/dev/socket", 0755));
+ CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
+#define MAKE_STR(x) __STRING(x)
+ CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
+#undef MAKE_STR
+ // Don't expose the raw commandline to unprivileged processes.
+ CHECKCALL(chmod("/proc/cmdline", 0440));
+ gid_t groups[] = {AID_READPROC};
+ CHECKCALL(setgroups(arraysize(groups), groups));
+ CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
+ CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
+
+ CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
+
+ if constexpr (WORLD_WRITABLE_KMSG) {
+ CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
+ }
+
+ CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
+ CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
+
+ // This is needed for log wrapper, which gets called before ueventd runs.
+ CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
+ CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
+
+ // Mount staging areas for devices managed by vold
+ // See storage config details at http://source.android.com/devices/storage/
+ CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+ "mode=0755,uid=0,gid=1000"));
+ // /mnt/vendor is used to mount vendor-specific partitions that can not be
+ // part of the vendor partition, e.g. because they are mounted read-write.
+ CHECKCALL(mkdir("/mnt/vendor", 0755));
+ // /mnt/product is used to mount product-specific partitions that can not be
+ // part of the product partition, e.g. because they are mounted read-write.
+ CHECKCALL(mkdir("/mnt/product", 0755));
+
+#undef CHECKCALL
+
+ // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
+ // talk to the outside world...
+ android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
+ RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+ });
+
+ if (!errors.empty()) {
+ for (const auto& [error_string, error_errno] : errors) {
+ LOG(ERROR) << error_string << " " << strerror(error_errno);
+ }
+ LOG(FATAL) << "Init encountered errors starting first stage, aborting";
+ }
+
+ LOG(INFO) << "init first stage started!";
+
+ if (!DoFirstStageMount()) {
+ LOG(FATAL) << "Failed to mount required partitions early ...";
+ }
+
+ SetInitAvbVersionInRecovery();
+
+ // Does this need to be done in first stage init or can it be done later?
+ // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
+ GlobalSeccomp();
+
+ // Set up SELinux, loading the SELinux policy.
+ SelinuxSetupKernelLogging();
+ SelinuxInitialize();
+
+ // Unneeded? It's an ext4 file system so shouldn't it have the right domain already?
+ // We're in the kernel domain, so re-exec init to transition to the init domain now
+ // that the SELinux policy has been loaded.
+ if (selinux_android_restorecon("/init", 0) == -1) {
+ PLOG(FATAL) << "restorecon failed of /init failed";
+ }
+
+ setenv("INIT_SECOND_STAGE", "true", 1);
+
+ static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
+ uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
+ setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
+
+ const char* path = argv[0];
+ const char* args[] = {path, nullptr};
+ execv(path, const_cast<char**>(args));
+
+ // execv() only returns if an error happened, in which case we
+ // panic and never fall through this conditional.
+ PLOG(FATAL) << "execv(\"" << path << "\") failed";
+
+ return 1;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c0d811f..cd2f630 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -16,6 +16,7 @@
#include "property_service.h"
+#include <android/api-level.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -576,7 +577,7 @@
size_t flen = 0;
const char* context = kInitContext.c_str();
- if (SelinuxHasVendorInit()) {
+ if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
if (StartsWith(filename, path_prefix)) {
context = secontext;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 11507f4..7401857 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -20,11 +20,9 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <mntent.h>
-#include <sys/capability.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
-#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
@@ -51,9 +49,9 @@
#include <selinux/selinux.h>
#include "action_manager.h"
-#include "capabilities.h"
#include "init.h"
#include "property_service.h"
+#include "reboot_utils.h"
#include "service.h"
#include "sigchld_handler.h"
@@ -159,54 +157,6 @@
<< stat;
}
-bool IsRebootCapable() {
- if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
- PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
- return true;
- }
-
- ScopedCaps caps(cap_get_proc());
- if (!caps) {
- PLOG(WARNING) << "cap_get_proc() failed";
- return true;
- }
-
- cap_flag_value_t value = CAP_SET;
- if (cap_get_flag(caps.get(), CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) {
- PLOG(WARNING) << "cap_get_flag(CAP_SYS_BOOT, EFFECTIVE) failed";
- return true;
- }
- return value == CAP_SET;
-}
-
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
- LOG(INFO) << "Reboot ending, jumping to kernel";
-
- if (!IsRebootCapable()) {
- // On systems where init does not have the capability of rebooting the
- // device, just exit cleanly.
- exit(0);
- }
-
- switch (cmd) {
- case ANDROID_RB_POWEROFF:
- reboot(RB_POWER_OFF);
- break;
-
- case ANDROID_RB_RESTART2:
- syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
- break;
-
- case ANDROID_RB_THERMOFF:
- reboot(RB_POWER_OFF);
- break;
- }
- // In normal case, reboot should not return.
- PLOG(ERROR) << "reboot call returned";
- abort();
-}
-
/* Find all read+write block devices and emulated devices in /proc/mounts
* and add them to correpsponding list.
*/
@@ -329,8 +279,15 @@
return stat;
}
-void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
- bool runFsck) {
+//* Reboot / shutdown the system.
+// cmd ANDROID_RB_* as defined in android_reboot.h
+// reason Reason string like "reboot", "shutdown,userrequested"
+// rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
+// empty string.
+// runFsck Whether to run fsck after umount is done.
+//
+static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
+ bool runFsck) {
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
diff --git a/init/reboot.h b/init/reboot.h
index 1c58bd1..07dcb6e 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -22,26 +22,9 @@
namespace android {
namespace init {
-// This is a wrapper around the actual reboot calls. DoReboot() should be preferred in most cases.
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget);
-
-/* Reboot / shutdown the system.
- * cmd ANDROID_RB_* as defined in android_reboot.h
- * reason Reason string like "reboot", "shutdown,userrequested"
- * rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
- * empty string.
- * runFsck Whether to run fsck after umount is done.
- */
-void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
- bool runFsck) __attribute__((__noreturn__));
-
// Parses and handles a setprop sys.powerctl message.
bool HandlePowerctlMessage(const std::string& command);
-// Determines whether the system is capable of rebooting. This is conservative,
-// so if any of the attempts to determine this fail, it will still return true.
-bool IsRebootCapable();
-
} // namespace init
} // namespace android
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
new file mode 100644
index 0000000..9610304
--- /dev/null
+++ b/init/reboot_utils.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include <sys/capability.h>
+#include <sys/reboot.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <cutils/android_reboot.h>
+
+#include "capabilities.h"
+
+namespace android {
+namespace init {
+
+bool IsRebootCapable() {
+ if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
+ PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
+ return true;
+ }
+
+ ScopedCaps caps(cap_get_proc());
+ if (!caps) {
+ PLOG(WARNING) << "cap_get_proc() failed";
+ return true;
+ }
+
+ cap_flag_value_t value = CAP_SET;
+ if (cap_get_flag(caps.get(), CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) {
+ PLOG(WARNING) << "cap_get_flag(CAP_SYS_BOOT, EFFECTIVE) failed";
+ return true;
+ }
+ return value == CAP_SET;
+}
+
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+ LOG(INFO) << "Reboot ending, jumping to kernel";
+
+ if (!IsRebootCapable()) {
+ // On systems where init does not have the capability of rebooting the
+ // device, just exit cleanly.
+ exit(0);
+ }
+
+ switch (cmd) {
+ case ANDROID_RB_POWEROFF:
+ reboot(RB_POWER_OFF);
+ break;
+
+ case ANDROID_RB_RESTART2:
+ syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
+ break;
+
+ case ANDROID_RB_THERMOFF:
+ reboot(RB_POWER_OFF);
+ break;
+ }
+ // In normal case, reboot should not return.
+ PLOG(ERROR) << "reboot call returned";
+ abort();
+}
+
+void InstallRebootSignalHandlers() {
+ // Instead of panic'ing the kernel as is the default behavior when init crashes,
+ // we prefer to reboot to bootloader on development builds, as this will prevent
+ // boot looping bad configurations and allow both developers and test farms to easily
+ // recover.
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigfillset(&action.sa_mask);
+ action.sa_handler = [](int signal) {
+ // These signal handlers are also caught for processes forked from init, however we do not
+ // want them to trigger reboot, so we directly call _exit() for children processes here.
+ if (getpid() != 1) {
+ _exit(signal);
+ }
+
+ // Calling DoReboot() or LOG(FATAL) is not a good option as this is a signal handler.
+ // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
+ // and probably good enough given this is already an error case and only enabled for
+ // development builds.
+ RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+ };
+ action.sa_flags = SA_RESTART;
+ sigaction(SIGABRT, &action, nullptr);
+ sigaction(SIGBUS, &action, nullptr);
+ sigaction(SIGFPE, &action, nullptr);
+ sigaction(SIGILL, &action, nullptr);
+ sigaction(SIGSEGV, &action, nullptr);
+#if defined(SIGSTKFLT)
+ sigaction(SIGSTKFLT, &action, nullptr);
+#endif
+ sigaction(SIGSYS, &action, nullptr);
+ sigaction(SIGTRAP, &action, nullptr);
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
new file mode 100644
index 0000000..073a16a
--- /dev/null
+++ b/init/reboot_utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace init {
+
+// Determines whether the system is capable of rebooting. This is conservative,
+// so if any of the attempts to determine this fail, it will still return true.
+bool IsRebootCapable();
+// This is a wrapper around the actual reboot calls.
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target);
+void InstallRebootSignalHandlers();
+
+} // namespace init
+} // namespace android
diff --git a/init/selinux.cpp b/init/selinux.cpp
index b788be9..fd7e86f 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -47,6 +47,7 @@
#include "selinux.h"
+#include <android/api-level.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
@@ -472,29 +473,27 @@
selinux_set_callback(SELINUX_CB_LOG, cb);
}
-// This function checks whether the sepolicy supports vendor init.
-bool SelinuxHasVendorInit() {
+// This function returns the Android version with which the vendor SEPolicy was compiled.
+// It is used for version checks such as whether or not vendor_init should be used
+int SelinuxGetVendorAndroidVersion() {
if (!IsSplitPolicyDevice()) {
- // If this device does not split sepolicy files, vendor_init will be available in the latest
- // monolithic sepolicy file.
- return true;
+ // If this device does not split sepolicy files, it's not a Treble device and therefore,
+ // we assume it's always on the latest platform.
+ return __ANDROID_API_FUTURE__;
}
std::string version;
if (!GetVendorMappingVersion(&version)) {
- // Return true as the default if we failed to load the vendor sepolicy version.
- return true;
+ LOG(FATAL) << "Could not read vendor SELinux version";
}
int major_version;
std::string major_version_str(version, 0, version.find('.'));
if (!ParseInt(major_version_str, &major_version)) {
- PLOG(ERROR) << "Failed to parse the vendor sepolicy major version " << major_version_str;
- // Return true as the default if we failed to parse the major version.
- return true;
+ PLOG(FATAL) << "Failed to parse the vendor sepolicy major version " << major_version_str;
}
- return major_version >= 28;
+ return major_version;
}
// selinux_android_file_context_handle() takes on the order of 10+ms to run, so we want to cache
diff --git a/init/selinux.h b/init/selinux.h
index 30069b5..c41d7f0 100644
--- a/init/selinux.h
+++ b/init/selinux.h
@@ -27,7 +27,7 @@
void SelinuxRestoreContext();
void SelinuxSetupKernelLogging();
-bool SelinuxHasVendorInit();
+int SelinuxGetVendorAndroidVersion();
void SelabelInitialize();
bool SelabelLookupFileContext(const std::string& key, int type, std::string* result);
diff --git a/init/service.cpp b/init/service.cpp
index 4c2747e..d20e90a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -46,10 +46,12 @@
#include "util.h"
#if defined(__ANDROID__)
+#include <android/api-level.h>
#include <sys/system_properties.h>
#include "init.h"
#include "property_service.h"
+#include "selinux.h"
#else
#include "host_init_stubs.h"
#endif
@@ -1211,6 +1213,13 @@
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
+
+ if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
+ if (str_args[0] == "/sbin/watchdogd") {
+ str_args[0] = "/system/bin/watchdogd";
+ }
+ }
+
service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
return Success();
}
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index ee72513..c2a21d4 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,6 +30,7 @@
#include "util.h"
#if defined(__ANDROID__)
+#include <android/api-level.h>
#include "property_service.h"
#include "selinux.h"
#else
@@ -355,7 +356,7 @@
static bool shutting_down;
std::vector<Subcontext>* InitializeSubcontexts() {
- if (SelinuxHasVendorInit()) {
+ if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
subcontexts.emplace_back(path_prefix, secontext);
}
diff --git a/init/util.cpp b/init/util.cpp
index 7735717..105ac87 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -47,7 +47,7 @@
#endif
#ifdef _INIT_INIT_H
-#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
+#error "Do not include init.h in files used by ueventd; it will expose init's globals"
#endif
using android::base::boot_clock;
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index a9cfce4..c564271 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -31,6 +31,7 @@
#include <deque>
#include <iterator>
+#include <memory>
#include <string>
#include <vector>
diff --git a/libpixelflinger/fixed.cpp b/libpixelflinger/fixed.cpp
index 5094537..de6b479 100644
--- a/libpixelflinger/fixed.cpp
+++ b/libpixelflinger/fixed.cpp
@@ -70,17 +70,6 @@
// ------------------------------------------------------------------------
-GGLfixed gglFastDivx(GGLfixed n, GGLfixed d)
-{
- if ((d>>24) && ((d>>24)+1)) {
- n >>= 8;
- d >>= 8;
- }
- return gglMulx(n, gglRecip(d));
-}
-
-// ------------------------------------------------------------------------
-
static const GGLfixed ggl_sqrt_reciproc_approx_tab[8] = {
// 1/sqrt(x) with x = 1-N/16, N=[8...1]
0x16A09, 0x15555, 0x143D1, 0x134BF, 0x1279A, 0x11C01, 0x111AC, 0x10865
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
index 51e9e26..7f39e9b 100644
--- a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
+++ b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
@@ -86,7 +86,6 @@
GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST;
GGLfixed gglSqrtx(GGLfixed a) CONST;
GGLfixed gglSqrtRecipx(GGLfixed x) CONST;
-GGLfixed gglFastDivx(GGLfixed n, GGLfixed d) CONST;
int32_t gglMulDivi(int32_t a, int32_t b, int32_t c);
int32_t gglRecipQNormalized(int32_t x, int* exponent);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index df5da65..be2145d 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -190,6 +190,7 @@
"tests/MemoryRangeTest.cpp",
"tests/MemoryRemoteTest.cpp",
"tests/MemoryTest.cpp",
+ "tests/RegsInfoTest.cpp",
"tests/RegsIterateTest.cpp",
"tests/RegsStepIfSignalHandlerTest.cpp",
"tests/RegsTest.cpp",
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 2c00456..f59a472 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -167,15 +167,10 @@
return false;
}
- if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
- return false;
- }
-
- // We could still potentially unwind without the section header
- // information, so ignore any errors.
- if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) {
- log(0, "Malformed section header found, ignoring...");
- }
+ // If we have enough information that this is an elf file, then allow
+ // malformed program and section headers.
+ ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias);
+ ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
return true;
}
@@ -200,14 +195,12 @@
}
template <typename EhdrType, typename PhdrType>
-bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
+void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
uint64_t offset = ehdr.e_phoff;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset;
- return false;
+ return;
}
switch (phdr.p_type) {
@@ -242,11 +235,10 @@
break;
}
}
- return true;
}
template <typename EhdrType, typename ShdrType>
-bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
+void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
uint64_t offset = ehdr.e_shoff;
uint64_t sec_offset = 0;
uint64_t sec_size = 0;
@@ -267,9 +259,7 @@
offset += ehdr.e_shentsize;
for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset;
- return false;
+ return;
}
if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
@@ -277,18 +267,14 @@
// the string terminated names.
ShdrType str_shdr;
if (shdr.sh_link >= ehdr.e_shnum) {
- last_error_.code = ERROR_UNWIND_INFO;
- return false;
+ continue;
}
uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
if (!memory_->Read(str_offset, &str_shdr, sizeof(str_shdr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = str_offset;
- return false;
+ continue;
}
if (str_shdr.sh_type != SHT_STRTAB) {
- last_error_.code = ERROR_UNWIND_INFO;
- return false;
+ continue;
}
symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
str_shdr.sh_offset, str_shdr.sh_size));
@@ -324,7 +310,6 @@
static_cast<uint64_t>(shdr.sh_offset)));
}
}
- return true;
}
template <typename DynType>
@@ -499,11 +484,13 @@
template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
-template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
-template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&,
+ uint64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&,
+ uint64_t*);
-template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
-template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
+template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
+template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
diff --git a/libunwindstack/RegsInfo.h b/libunwindstack/RegsInfo.h
index 47825f5..e6dd33c 100644
--- a/libunwindstack/RegsInfo.h
+++ b/libunwindstack/RegsInfo.h
@@ -25,11 +25,13 @@
template <typename AddressType>
struct RegsInfo {
+ static constexpr size_t MAX_REGISTERS = 64;
+
RegsInfo(RegsImpl<AddressType>* regs) : regs(regs) {}
RegsImpl<AddressType>* regs = nullptr;
uint64_t saved_reg_map = 0;
- AddressType saved_regs[64];
+ AddressType saved_regs[MAX_REGISTERS];
inline AddressType Get(uint32_t reg) {
if (IsSaved(reg)) {
@@ -39,23 +41,23 @@
}
inline AddressType* Save(uint32_t reg) {
- if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
- // This should never happen as since all currently supported
- // architectures have the total number of registers < 64.
+ if (reg > MAX_REGISTERS) {
+ // This should never happen since all currently supported
+ // architectures have < 64 total registers.
abort();
}
- saved_reg_map |= 1 << reg;
+ saved_reg_map |= 1ULL << reg;
saved_regs[reg] = (*regs)[reg];
return &(*regs)[reg];
}
inline bool IsSaved(uint32_t reg) {
- if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
- // This should never happen as since all currently supported
- // architectures have the total number of registers < 64.
+ if (reg > MAX_REGISTERS) {
+ // This should never happen since all currently supported
+ // architectures have < 64 total registers.
abort();
}
- return saved_reg_map & (1 << reg);
+ return saved_reg_map & (1ULL << reg);
}
inline uint16_t Total() { return regs->total_regs(); }
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 5c1210d..a45eba8 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -104,10 +104,10 @@
bool ReadAllHeaders(uint64_t* load_bias);
template <typename EhdrType, typename PhdrType>
- bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
+ void ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
template <typename EhdrType, typename ShdrType>
- bool ReadSectionHeaders(const EhdrType& ehdr);
+ void ReadSectionHeaders(const EhdrType& ehdr);
template <typename DynType>
bool GetSonameWithTemplate(std::string* soname);
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index aa6df84..9326bff 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -97,9 +97,15 @@
template <typename ElfType>
void InitHeadersDebugFrameFail();
+ template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+ void InitProgramHeadersMalformed();
+
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void InitSectionHeadersMalformed();
+ template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+ void InitSectionHeadersMalformedSymData();
+
template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
void InitSectionHeaders(uint64_t entry_size);
@@ -677,6 +683,29 @@
InitHeadersDebugFrame<ElfInterface64Fake>();
}
+template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitProgramHeadersMalformed() {
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+ Ehdr ehdr = {};
+ ehdr.e_phoff = 0x100;
+ ehdr.e_phnum = 3;
+ ehdr.e_phentsize = sizeof(Phdr);
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+}
+
+TEST_F(ElfInterfaceTest, init_program_headers_malformed32) {
+ InitProgramHeadersMalformed<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, init_program_headers_malformed64) {
+ InitProgramHeadersMalformed<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeadersMalformed() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -700,6 +729,80 @@
InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}
+template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitSectionHeadersMalformedSymData() {
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+ uint64_t offset = 0x1000;
+
+ Ehdr ehdr = {};
+ ehdr.e_shoff = offset;
+ ehdr.e_shnum = 5;
+ ehdr.e_shentsize = sizeof(Shdr);
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ offset += ehdr.e_shentsize;
+
+ Shdr shdr = {};
+ shdr.sh_type = SHT_SYMTAB;
+ shdr.sh_link = 4;
+ shdr.sh_addr = 0x5000;
+ shdr.sh_offset = 0x5000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = shdr.sh_entsize * 10;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_DYNSYM;
+ shdr.sh_link = 10;
+ shdr.sh_addr = 0x6000;
+ shdr.sh_offset = 0x6000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = shdr.sh_entsize * 10;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_DYNSYM;
+ shdr.sh_link = 2;
+ shdr.sh_addr = 0x6000;
+ shdr.sh_offset = 0x6000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = shdr.sh_entsize * 10;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ // The string data for the entries.
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x20000;
+ shdr.sh_offset = 0xf000;
+ shdr.sh_size = 0x1000;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0U, elf->debug_frame_offset());
+ EXPECT_EQ(0U, elf->debug_frame_size());
+ EXPECT_EQ(0U, elf->gnu_debugdata_offset());
+ EXPECT_EQ(0U, elf->gnu_debugdata_size());
+
+ std::string name;
+ uint64_t name_offset;
+ ASSERT_FALSE(elf->GetFunctionName(0x90010, &name, &name_offset));
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata32) {
+ InitSectionHeadersMalformedSymData<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata64) {
+ InitSectionHeadersMalformedSymData<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -708,7 +811,7 @@
Ehdr ehdr = {};
ehdr.e_shoff = offset;
- ehdr.e_shnum = 10;
+ ehdr.e_shnum = 5;
ehdr.e_shentsize = entry_size;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
@@ -795,7 +898,7 @@
Ehdr ehdr = {};
ehdr.e_shoff = offset;
- ehdr.e_shnum = 10;
+ ehdr.e_shnum = 6;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index f599503..861b82f 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -319,7 +319,7 @@
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
+ ehdr.e_shnum = 0;
memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_, false);
@@ -341,7 +341,7 @@
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
+ ehdr.e_shnum = 0;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_, false);
@@ -368,7 +368,7 @@
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
+ ehdr.e_shnum = 0;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
Elf* elf_in_threads[kNumConcurrentThreads];
diff --git a/libunwindstack/tests/RegsInfoTest.cpp b/libunwindstack/tests/RegsInfoTest.cpp
new file mode 100644
index 0000000..052b5bf
--- /dev/null
+++ b/libunwindstack/tests/RegsInfoTest.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Regs.h>
+
+#include "RegsFake.h"
+#include "RegsInfo.h"
+
+namespace unwindstack {
+
+TEST(RegsInfoTest, single_uint32_t) {
+ RegsImplFake<uint32_t> regs(10);
+ RegsInfo<uint32_t> info(®s);
+
+ regs[1] = 0x100;
+ ASSERT_FALSE(info.IsSaved(1));
+ ASSERT_EQ(0x100U, info.Get(1));
+ ASSERT_EQ(10, info.Total());
+
+ uint32_t* value = info.Save(1);
+ ASSERT_EQ(value, ®s[1]);
+ regs[1] = 0x200;
+ ASSERT_TRUE(info.IsSaved(1));
+ ASSERT_EQ(0x100U, info.Get(1));
+ ASSERT_EQ(0x200U, regs[1]);
+}
+
+TEST(RegsInfoTest, single_uint64_t) {
+ RegsImplFake<uint64_t> regs(20);
+ RegsInfo<uint64_t> info(®s);
+
+ regs[3] = 0x300;
+ ASSERT_FALSE(info.IsSaved(3));
+ ASSERT_EQ(0x300U, info.Get(3));
+ ASSERT_EQ(20, info.Total());
+
+ uint64_t* value = info.Save(3);
+ ASSERT_EQ(value, ®s[3]);
+ regs[3] = 0x400;
+ ASSERT_TRUE(info.IsSaved(3));
+ ASSERT_EQ(0x300U, info.Get(3));
+ ASSERT_EQ(0x400U, regs[3]);
+}
+
+TEST(RegsInfoTest, all) {
+ RegsImplFake<uint64_t> regs(64);
+ RegsInfo<uint64_t> info(®s);
+
+ for (uint32_t i = 0; i < 64; i++) {
+ regs[i] = i * 0x100;
+ ASSERT_EQ(i * 0x100, info.Get(i)) << "Reg " + std::to_string(i) + " failed.";
+ }
+
+ for (uint32_t i = 0; i < 64; i++) {
+ ASSERT_FALSE(info.IsSaved(i)) << "Reg " + std::to_string(i) + " failed.";
+ uint64_t* reg = info.Save(i);
+ ASSERT_EQ(reg, ®s[i]) << "Reg " + std::to_string(i) + " failed.";
+ *reg = i * 0x1000 + 0x100;
+ ASSERT_EQ(i * 0x1000 + 0x100, regs[i]) << "Reg " + std::to_string(i) + " failed.";
+ }
+
+ for (uint32_t i = 0; i < 64; i++) {
+ ASSERT_TRUE(info.IsSaved(i)) << "Reg " + std::to_string(i) + " failed.";
+ ASSERT_EQ(i * 0x100, info.Get(i)) << "Reg " + std::to_string(i) + " failed.";
+ }
+}
+
+} // namespace unwindstack
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index bd6015e..2a83bd9 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -16,16 +16,15 @@
#define LOG_TAG "CallStack"
-#include <utils/CallStack.h>
-
-#include <memory>
-
#include <utils/Printer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <backtrace/Backtrace.h>
+#define CALLSTACK_WEAK // Don't generate weak definitions.
+#include <utils/CallStack.h>
+
namespace android {
CallStack::CallStack() {
@@ -76,4 +75,26 @@
}
}
+// The following four functions may be used via weak symbol references from libutils.
+// Clients assume that if any of these symbols are available, then deleteStack() is.
+
+CallStack::CallStackUPtr CallStack::getCurrentInternal(int ignoreDepth) {
+ CallStack::CallStackUPtr stack(new CallStack());
+ stack->update(ignoreDepth + 1);
+ return stack;
+}
+
+void CallStack::logStackInternal(const char* logtag, const CallStack* stack,
+ android_LogPriority priority) {
+ stack->log(logtag, priority);
+}
+
+String8 CallStack::stackToStringInternal(const char* prefix, const CallStack* stack) {
+ return stack->toString(prefix);
+}
+
+void CallStack::deleteStack(CallStack* stack) {
+ delete stack;
+}
+
}; // namespace android
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 9074850..3f1e79a 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,30 +17,41 @@
#define LOG_TAG "RefBase"
// #define LOG_NDEBUG 0
+#include <memory>
+
#include <utils/RefBase.h>
#include <utils/CallStack.h>
+#include <utils/Mutex.h>
+
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
-// compile with refcounting debugging enabled
-#define DEBUG_REFS 0
+// Compile with refcounting debugging enabled.
+#define DEBUG_REFS 0
+
+// The following three are ignored unless DEBUG_REFS is set.
// whether ref-tracking is enabled by default, if not, trackMe(true, false)
// needs to be called explicitly
-#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
+#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
// whether callstack are collected (significantly slows things down)
-#define DEBUG_REFS_CALLSTACK_ENABLED 1
+#define DEBUG_REFS_CALLSTACK_ENABLED 1
// folder where stack traces are saved when DEBUG_REFS is enabled
// this folder needs to exist and be writable
-#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
// log all reference counting operations
-#define PRINT_REFS 0
+#define PRINT_REFS 0
+
+// Continue after logging a stack trace if ~RefBase discovers that reference
+// count has never been incremented. Normally we conspicuously crash in that
+// case.
+#define DEBUG_REFBASE_DESTRUCTION 1
// ---------------------------------------------------------------------------
@@ -184,7 +195,7 @@
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.log(LOG_TAG);
+ CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
}
@@ -198,14 +209,14 @@
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.log(LOG_TAG);
+ CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
}
}
if (dumpStack) {
ALOGE("above errors at:");
- CallStack stack(LOG_TAG);
+ CallStack::logStack(LOG_TAG);
}
}
@@ -279,7 +290,7 @@
this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
- write(rc, text.string(), text.length());
+ (void)write(rc, text.string(), text.length());
close(rc);
ALOGD("STACK TRACE for %p saved in %s", this, name);
}
@@ -294,7 +305,7 @@
ref_entry* next;
const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
- CallStack stack;
+ CallStack::CallStackUPtr stack;
#endif
int32_t ref;
};
@@ -311,7 +322,7 @@
ref->ref = mRef;
ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
- ref->stack.update(2);
+ ref->stack = CallStack::getCurrent(2);
#endif
ref->next = *refs;
*refs = ref;
@@ -346,7 +357,7 @@
ref = ref->next;
}
- CallStack stack(LOG_TAG);
+ CallStack::logStack(LOG_TAG);
}
}
@@ -373,7 +384,7 @@
inc, refs->id, refs->ref);
out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
- out->append(refs->stack.toString("\t\t"));
+ out->append(CallStack::stackToString("\t\t", refs->stack.get()));
#else
out->append("\t\t(call stacks disabled)");
#endif
@@ -700,16 +711,16 @@
if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
delete mRefs;
}
- } else if (mRefs->mStrong.load(std::memory_order_relaxed)
- == INITIAL_STRONG_VALUE) {
+ } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
// We never acquired a strong reference on this object.
- LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
- "RefBase: Explicit destruction with non-zero weak "
- "reference count");
- // TODO: Always report if we get here. Currently MediaMetadataRetriever
- // C++ objects are inconsistently managed and sometimes get here.
- // There may be other cases, but we believe they should all be fixed.
- delete mRefs;
+#if DEBUG_REFBASE_DESTRUCTION
+ // Treating this as fatal is prone to causing boot loops. For debugging, it's
+ // better to treat as non-fatal.
+ ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
+ CallStack::logStack(LOG_TAG);
+#else
+ LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
+#endif
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
const_cast<weakref_impl*&>(mRefs) = nullptr;
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 0c1b875..a7b1d10 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_CALLSTACK_H
#define ANDROID_CALLSTACK_H
+#include <memory>
+
#include <android/log.h>
#include <backtrace/backtrace_constants.h>
#include <utils/String8.h>
@@ -25,6 +27,11 @@
#include <stdint.h>
#include <sys/types.h>
+#ifndef CALLSTACK_WEAK
+#define CALLSTACK_WEAK __attribute__((weak))
+#endif
+#define ALWAYS_INLINE __attribute__((always_inline))
+
namespace android {
class Printer;
@@ -36,7 +43,7 @@
CallStack();
// Create a callstack with the current thread's stack trace.
// Immediately dump it to logcat using the given logtag.
- CallStack(const char* logtag, int32_t ignoreDepth=1);
+ CallStack(const char* logtag, int32_t ignoreDepth = 1);
~CallStack();
// Reset the stack frames (same as creating an empty call stack).
@@ -44,7 +51,7 @@
// Immediately collect the stack traces for the specified thread.
// The default is to dump the stack of the current call.
- void update(int32_t ignoreDepth=1, pid_t tid=BACKTRACE_CURRENT_THREAD);
+ void update(int32_t ignoreDepth = 1, pid_t tid = BACKTRACE_CURRENT_THREAD);
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
@@ -63,7 +70,58 @@
// Get the count of stack frames that are in this call stack.
size_t size() const { return mFrameLines.size(); }
-private:
+ // DO NOT USE ANYTHING BELOW HERE. The following public members are expected
+ // to disappear again shortly, once a better replacement facility exists.
+ // The replacement facility will be incompatible!
+
+ // Debugging accesses to some basic functionality. These use weak symbols to
+ // avoid introducing a dependency on libutilscallstack. Such a dependency from
+ // libutils results in a cyclic build dependency. These routines can be called
+ // from within libutils. But if the actual library is unavailable, they do
+ // nothing.
+ //
+ // DO NOT USE THESE. They will disappear.
+ struct StackDeleter {
+ void operator()(CallStack* stack) { deleteStack(stack); }
+ };
+
+ typedef std::unique_ptr<CallStack, StackDeleter> CallStackUPtr;
+
+ // Return current call stack if possible, nullptr otherwise.
+ static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t ignoreDepth = 1) {
+ if (reinterpret_cast<uintptr_t>(getCurrentInternal) == 0) {
+ ALOGW("CallStack::getCurrentInternal not linked, returning null");
+ return CallStackUPtr(nullptr);
+ } else {
+ return getCurrentInternal(ignoreDepth);
+ }
+ }
+ static void ALWAYS_INLINE logStack(const char* logtag, CallStack* stack = getCurrent().get(),
+ android_LogPriority priority = ANDROID_LOG_DEBUG) {
+ if (reinterpret_cast<uintptr_t>(logStackInternal) != 0 && stack != nullptr) {
+ logStackInternal(logtag, stack, priority);
+ } else {
+ ALOGW("CallStack::logStackInternal not linked");
+ }
+ }
+ static String8 ALWAYS_INLINE stackToString(const char* prefix = nullptr,
+ const CallStack* stack = getCurrent().get()) {
+ if (reinterpret_cast<uintptr_t>(stackToStringInternal) != 0 && stack != nullptr) {
+ return stackToStringInternal(prefix, stack);
+ } else {
+ return String8("<CallStack package not linked>");
+ }
+ }
+
+ private:
+ static CallStackUPtr CALLSTACK_WEAK getCurrentInternal(int32_t ignoreDepth);
+ static void CALLSTACK_WEAK logStackInternal(const char* logtag, const CallStack* stack,
+ android_LogPriority priority);
+ static String8 CALLSTACK_WEAK stackToStringInternal(const char* prefix, const CallStack* stack);
+ // The deleter is only invoked on non-null pointers. Hence it will never be
+ // invoked if CallStack is not linked.
+ static void CALLSTACK_WEAK deleteStack(CallStack* stack);
+
Vector<String8> mFrameLines;
};
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 2efda86..9ac082f 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -7,17 +7,8 @@
"liblog",
],
local_include_dirs: ["include"],
- cflags: ["-Werror"],
-
+ cflags: ["-Werror", "-DLMKD_TRACE_KILLS"],
init_rc: ["lmkd.rc"],
-
- product_variables: {
- debuggable: {
- cflags: [
- "-DLMKD_TRACE_KILLS"
- ],
- },
- },
}
cc_library_static {
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index c2487d6..1a14be3 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -52,8 +52,8 @@
#else /* LMKD_TRACE_KILLS */
-#define TRACE_KILL_START(pid)
-#define TRACE_KILL_END()
+#define TRACE_KILL_START(pid) ((void)(pid))
+#define TRACE_KILL_END() ((void)0)
#endif /* LMKD_TRACE_KILLS */
@@ -111,6 +111,7 @@
static bool kill_heaviest_task;
static unsigned long kill_timeout_ms;
static bool use_minfree_levels;
+static bool per_app_memcg;
/* data required to handle events */
struct event_handler_info {
@@ -472,7 +473,7 @@
return;
}
- if (low_ram_device) {
+ if (per_app_memcg) {
if (params.oomadj >= 900) {
soft_limit_mult = 0;
} else if (params.oomadj >= 800) {
@@ -1481,6 +1482,8 @@
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
use_minfree_levels =
property_get_bool("ro.lmk.use_minfree_levels", false);
+ per_app_memcg =
+ property_get_bool("ro.config.per_app_memcg", low_ram_device);
if (!init()) {
if (!use_inkernel_interface) {
diff --git a/watchdogd/Android.bp b/watchdogd/Android.bp
new file mode 100644
index 0000000..0fbc33c
--- /dev/null
+++ b/watchdogd/Android.bp
@@ -0,0 +1,14 @@
+cc_binary {
+ name: "watchdogd",
+ recovery_available: true,
+ srcs: ["watchdogd.cpp"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ shared_libs: ["libbase"],
+ sanitize: {
+ misc_undefined: ["signed-integer-overflow"],
+ },
+}
diff --git a/init/watchdogd.cpp b/watchdogd/watchdogd.cpp
similarity index 79%
rename from init/watchdogd.cpp
rename to watchdogd/watchdogd.cpp
index e03a2c3..5dc41e6 100644
--- a/init/watchdogd.cpp
+++ b/watchdogd/watchdogd.cpp
@@ -23,16 +23,9 @@
#include <android-base/logging.h>
-#ifdef _INIT_INIT_H
-#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
-#endif
-
#define DEV_NAME "/dev/watchdog"
-namespace android {
-namespace init {
-
-int watchdogd_main(int argc, char **argv) {
+int main(int argc, char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
int interval = 10;
@@ -43,7 +36,7 @@
LOG(INFO) << "watchdogd started (interval " << interval << ", margin " << margin << ")!";
- int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
+ int fd = open(DEV_NAME, O_RDWR | O_CLOEXEC);
if (fd == -1) {
PLOG(ERROR) << "Failed to open " << DEV_NAME;
return 1;
@@ -63,9 +56,8 @@
interval = 1;
}
LOG(WARNING) << "Adjusted interval to timeout returned by driver: "
- << "timeout " << timeout
- << ", interval " << interval
- << ", margin " << margin;
+ << "timeout " << timeout << ", interval " << interval << ", margin "
+ << margin;
}
}
@@ -74,6 +66,3 @@
sleep(interval);
}
}
-
-} // namespace init
-} // namespace android