Snap for 5476769 from cd780b456f to qt-release
Change-Id: Ibb4868f38d9c1c6957717a8a3c10373cd1051ffe
This commit is contained in:
+2
-6
@@ -69,6 +69,7 @@ cc_defaults {
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libinstall",
|
||||
"librecovery_fastboot",
|
||||
"libminui",
|
||||
"libotautil",
|
||||
@@ -93,7 +94,6 @@ cc_library_static {
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libinstall",
|
||||
"librecovery_ui",
|
||||
],
|
||||
}
|
||||
@@ -108,13 +108,10 @@ cc_binary {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"logging.cpp",
|
||||
"recovery_main.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libinstall",
|
||||
"libminadbd_services",
|
||||
"librecovery_ui",
|
||||
],
|
||||
|
||||
@@ -126,6 +123,7 @@ cc_binary {
|
||||
required: [
|
||||
"e2fsdroid.recovery",
|
||||
"librecovery_ui_ext",
|
||||
"minadbd",
|
||||
"mke2fs.conf.recovery",
|
||||
"mke2fs.recovery",
|
||||
"recovery_deps",
|
||||
@@ -141,7 +139,6 @@ cc_binary {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"logging.cpp",
|
||||
"recovery-persist.cpp",
|
||||
],
|
||||
|
||||
@@ -170,7 +167,6 @@ cc_binary {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"logging.cpp",
|
||||
"recovery-refresh.cpp",
|
||||
],
|
||||
|
||||
|
||||
+7
-3
@@ -44,9 +44,13 @@
|
||||
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
|
||||
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
|
||||
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/recovery_intermediates)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libminui_intermediates/import_includes)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/sbin)
|
||||
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinstall.recovery_intermediates)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/system/lib64/libinstall.so)
|
||||
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
||||
+6
-1
@@ -19,6 +19,10 @@ cc_defaults {
|
||||
"recovery_defaults",
|
||||
],
|
||||
|
||||
header_libs: [
|
||||
"libminadbd_headers",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbootloader_message",
|
||||
@@ -47,7 +51,7 @@ cc_defaults {
|
||||
],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
cc_library_static {
|
||||
name: "libinstall",
|
||||
recovery_available: true,
|
||||
|
||||
@@ -62,6 +66,7 @@ cc_library {
|
||||
"install.cpp",
|
||||
"package.cpp",
|
||||
"verifier.cpp",
|
||||
"wipe_data.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
|
||||
+249
-61
@@ -21,24 +21,266 @@
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/memory.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include "fuse_sideload.h"
|
||||
#include "install/install.h"
|
||||
#include "minadbd_types.h"
|
||||
#include "recovery_ui/ui.h"
|
||||
|
||||
using CommandFunction = std::function<bool()>;
|
||||
|
||||
static bool SetUsbConfig(const std::string& state) {
|
||||
android::base::SetProperty("sys.usb.config", state);
|
||||
return android::base::WaitForProperty("sys.usb.state", state);
|
||||
}
|
||||
|
||||
int apply_from_adb(bool* wipe_cache, RecoveryUI* ui) {
|
||||
// Parses the minadbd command in |message|; returns MinadbdCommands::kError upon errors.
|
||||
static MinadbdCommands ParseMinadbdCommands(const std::string& message) {
|
||||
if (!android::base::StartsWith(message, kMinadbdCommandPrefix)) {
|
||||
LOG(ERROR) << "Failed to parse command in message " << message;
|
||||
return MinadbdCommands::kError;
|
||||
}
|
||||
|
||||
auto cmd_code_string = message.substr(strlen(kMinadbdCommandPrefix));
|
||||
auto cmd_code = android::base::get_unaligned<uint32_t>(cmd_code_string.c_str());
|
||||
if (cmd_code >= static_cast<uint32_t>(MinadbdCommands::kError)) {
|
||||
LOG(ERROR) << "Unsupported command code: " << cmd_code;
|
||||
return MinadbdCommands::kError;
|
||||
}
|
||||
|
||||
return static_cast<MinadbdCommands>(cmd_code);
|
||||
}
|
||||
|
||||
static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) {
|
||||
char message[kMinadbdMessageSize];
|
||||
memcpy(message, kMinadbdStatusPrefix, strlen(kMinadbdStatusPrefix));
|
||||
android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), status);
|
||||
|
||||
if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) {
|
||||
PLOG(ERROR) << "Failed to write message " << message;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Installs the package from FUSE. Returns true if the installation succeeds, and false otherwise.
|
||||
static bool AdbInstallPackageHandler(RecoveryUI* ui, int* result) {
|
||||
// How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
|
||||
// because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME
|
||||
// will start to exist once the host connects and starts serving a package. Poll for its
|
||||
// appearance. (Note that inotify doesn't work with FUSE.)
|
||||
constexpr int ADB_INSTALL_TIMEOUT = 15;
|
||||
*result = INSTALL_ERROR;
|
||||
for (int i = 0; i < ADB_INSTALL_TIMEOUT; ++i) {
|
||||
struct stat st;
|
||||
if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
|
||||
if (errno == ENOENT && i < ADB_INSTALL_TIMEOUT - 1) {
|
||||
sleep(1);
|
||||
continue;
|
||||
} else {
|
||||
ui->Print("\nTimed out waiting for fuse to be ready.\n\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
*result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, ui);
|
||||
break;
|
||||
}
|
||||
|
||||
// Calling stat() on this magic filename signals the FUSE to exit.
|
||||
struct stat st;
|
||||
stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
|
||||
return *result == INSTALL_SUCCESS;
|
||||
}
|
||||
|
||||
// Parses and executes the command from minadbd. Returns false if we enter an invalid state so that
|
||||
// the caller can kill the minadbd service properly.
|
||||
static bool HandleMessageFromMinadbd(
|
||||
int socket_fd, const std::map<MinadbdCommands, CommandFunction>& command_map) {
|
||||
char buffer[kMinadbdMessageSize];
|
||||
if (!android::base::ReadFully(socket_fd, buffer, kMinadbdMessageSize)) {
|
||||
PLOG(ERROR) << "Failed to read message from minadbd";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string message(buffer, buffer + kMinadbdMessageSize);
|
||||
auto command_type = ParseMinadbdCommands(message);
|
||||
if (command_type == MinadbdCommands::kError) {
|
||||
return false;
|
||||
}
|
||||
if (command_map.find(command_type) == command_map.end()) {
|
||||
LOG(ERROR) << "Unsupported command: "
|
||||
<< android::base::get_unaligned<unsigned int>(
|
||||
message.substr(strlen(kMinadbdCommandPrefix)).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have received a valid command, execute the corresponding function.
|
||||
const auto& command_func = command_map.at(command_type);
|
||||
if (!command_func()) {
|
||||
LOG(ERROR) << "Failed to execute command " << static_cast<unsigned int>(command_type);
|
||||
return WriteStatusToFd(MinadbdCommandStatus::kFailure, socket_fd);
|
||||
}
|
||||
return WriteStatusToFd(MinadbdCommandStatus::kSuccess, socket_fd);
|
||||
}
|
||||
|
||||
// TODO(xunchang) add a wrapper function and kill the minadbd service there.
|
||||
static void ListenAndExecuteMinadbdCommands(
|
||||
pid_t minadbd_pid, android::base::unique_fd&& socket_fd,
|
||||
const std::map<MinadbdCommands, CommandFunction>& command_map) {
|
||||
android::base::unique_fd epoll_fd(epoll_create1(O_CLOEXEC));
|
||||
if (epoll_fd == -1) {
|
||||
PLOG(ERROR) << "Failed to create epoll";
|
||||
kill(minadbd_pid, SIGKILL);
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr int EPOLL_MAX_EVENTS = 10;
|
||||
struct epoll_event ev = {};
|
||||
ev.events = EPOLLIN | EPOLLHUP;
|
||||
ev.data.fd = socket_fd.get();
|
||||
struct epoll_event events[EPOLL_MAX_EVENTS];
|
||||
if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, socket_fd.get(), &ev) == -1) {
|
||||
PLOG(ERROR) << "Failed to add socket fd to epoll";
|
||||
kill(minadbd_pid, SIGKILL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the timeout to be 300s when waiting for minadbd commands.
|
||||
constexpr int TIMEOUT_MILLIS = 300 * 1000;
|
||||
while (true) {
|
||||
// Poll for the status change of the socket_fd, and handle the message if the fd is ready to
|
||||
// read.
|
||||
int event_count =
|
||||
TEMP_FAILURE_RETRY(epoll_wait(epoll_fd.get(), events, EPOLL_MAX_EVENTS, TIMEOUT_MILLIS));
|
||||
if (event_count == -1) {
|
||||
PLOG(ERROR) << "Failed to wait for epoll events";
|
||||
kill(minadbd_pid, SIGKILL);
|
||||
return;
|
||||
}
|
||||
if (event_count == 0) {
|
||||
LOG(ERROR) << "Timeout waiting for messages from minadbd";
|
||||
kill(minadbd_pid, SIGKILL);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int n = 0; n < event_count; n++) {
|
||||
if (events[n].events & EPOLLHUP) {
|
||||
LOG(INFO) << "Socket has been closed";
|
||||
kill(minadbd_pid, SIGKILL);
|
||||
return;
|
||||
}
|
||||
if (!HandleMessageFromMinadbd(socket_fd.get(), command_map)) {
|
||||
kill(minadbd_pid, SIGKILL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recovery starts minadbd service as a child process, and spawns another thread to listen for the
|
||||
// message from minadbd through a socket pair. Here is an example to execute one command from adb
|
||||
// host.
|
||||
// a. recovery b. listener thread c. minadbd service
|
||||
//
|
||||
// a1. create socket pair
|
||||
// a2. fork minadbd service
|
||||
// c3. wait for the adb commands
|
||||
// from host
|
||||
// c4. after receiving host commands:
|
||||
// 1) set up pre-condition (i.e.
|
||||
// start fuse for adb sideload)
|
||||
// 2) issue command through
|
||||
// socket.
|
||||
// 3) wait for result
|
||||
// a5. start listener thread
|
||||
// b6. listen for message from
|
||||
// minadbd in a loop.
|
||||
// b7. After receiving a minadbd
|
||||
// command from socket
|
||||
// 1) execute the command function
|
||||
// 2) send the result back to
|
||||
// minadbd
|
||||
// ......
|
||||
// c8. exit upon receiving the
|
||||
// result
|
||||
// a9. wait for listener thread
|
||||
// to exit.
|
||||
//
|
||||
// a10. wait for minadbd to
|
||||
// exit
|
||||
// b11. exit the listening loop
|
||||
//
|
||||
static void CreateMinadbdServiceAndExecuteCommands(
|
||||
const std::map<MinadbdCommands, CommandFunction>& command_map) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
android::base::unique_fd recovery_socket;
|
||||
android::base::unique_fd minadbd_socket;
|
||||
if (!android::base::Socketpair(AF_UNIX, SOCK_STREAM, 0, &recovery_socket, &minadbd_socket)) {
|
||||
PLOG(ERROR) << "Failed to create socket";
|
||||
return;
|
||||
}
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
PLOG(ERROR) << "Failed to fork child process";
|
||||
return;
|
||||
}
|
||||
if (child == 0) {
|
||||
recovery_socket.reset();
|
||||
execl("/system/bin/minadbd", "minadbd", "--socket_fd",
|
||||
std::to_string(minadbd_socket.release()).c_str(), nullptr);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
minadbd_socket.reset();
|
||||
|
||||
// We need to call SetUsbConfig() after forking minadbd service. Because the function waits for
|
||||
// the usb state to be updated, which depends on sys.usb.ffs.ready=1 set in the adb daemon.
|
||||
if (!SetUsbConfig("sideload")) {
|
||||
LOG(ERROR) << "Failed to set usb config to sideload";
|
||||
return;
|
||||
}
|
||||
|
||||
std::thread listener_thread(ListenAndExecuteMinadbdCommands, child, std::move(recovery_socket),
|
||||
std::ref(command_map));
|
||||
|
||||
if (listener_thread.joinable()) {
|
||||
listener_thread.join();
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(child, &status, 0);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
if (WEXITSTATUS(status) == MinadbdErrorCode::kMinadbdAdbVersionError) {
|
||||
LOG(ERROR) << "\nYou need adb 1.0.32 or newer to sideload\nto this device.\n";
|
||||
} else if (!WIFSIGNALED(status)) {
|
||||
LOG(ERROR) << "\n(adbd status " << WEXITSTATUS(status) << ")";
|
||||
}
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
}
|
||||
|
||||
int apply_from_adb(RecoveryUI* ui) {
|
||||
// Save the usb state to restore after the sideload operation.
|
||||
std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
|
||||
// Clean up state and stop adbd.
|
||||
@@ -51,66 +293,12 @@ int apply_from_adb(bool* wipe_cache, RecoveryUI* ui) {
|
||||
"\n\nNow send the package you want to apply\n"
|
||||
"to the device with \"adb sideload <filename>\"...\n");
|
||||
|
||||
pid_t child;
|
||||
if ((child = fork()) == 0) {
|
||||
execl("/system/bin/recovery", "recovery", "--adbd", nullptr);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
int install_result = INSTALL_ERROR;
|
||||
std::map<MinadbdCommands, CommandFunction> command_map{
|
||||
{ MinadbdCommands::kInstall, std::bind(&AdbInstallPackageHandler, ui, &install_result) },
|
||||
};
|
||||
|
||||
if (!SetUsbConfig("sideload")) {
|
||||
LOG(ERROR) << "Failed to set usb config to sideload";
|
||||
return INSTALL_ERROR;
|
||||
}
|
||||
|
||||
// How long (in seconds) we wait for the host to start sending us a package, before timing out.
|
||||
static constexpr int ADB_INSTALL_TIMEOUT = 300;
|
||||
|
||||
// FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the host connects and starts serving a
|
||||
// package. Poll for its appearance. (Note that inotify doesn't work with FUSE.)
|
||||
int result = INSTALL_ERROR;
|
||||
int status;
|
||||
bool waited = false;
|
||||
for (int i = 0; i < ADB_INSTALL_TIMEOUT; ++i) {
|
||||
if (waitpid(child, &status, WNOHANG) != 0) {
|
||||
result = INSTALL_ERROR;
|
||||
waited = true;
|
||||
break;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
|
||||
if (errno == ENOENT && i < ADB_INSTALL_TIMEOUT - 1) {
|
||||
sleep(1);
|
||||
continue;
|
||||
} else {
|
||||
ui->Print("\nTimed out waiting for package.\n\n");
|
||||
result = INSTALL_ERROR;
|
||||
kill(child, SIGKILL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, false, 0, ui);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!waited) {
|
||||
// Calling stat() on this magic filename signals the minadbd subprocess to shut down.
|
||||
struct stat st;
|
||||
stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
|
||||
|
||||
// TODO: there should be a way to cancel waiting for a package (by pushing some button combo on
|
||||
// the device). For now you just have to 'adb sideload' a file that's not a valid package, like
|
||||
// "/dev/null".
|
||||
waitpid(child, &status, 0);
|
||||
}
|
||||
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
if (WEXITSTATUS(status) == 3) {
|
||||
ui->Print("\nYou need adb 1.0.32 or newer to sideload\nto this device.\n\n");
|
||||
} else if (!WIFSIGNALED(status)) {
|
||||
ui->Print("\n(adbd status %d)\n", WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
CreateMinadbdServiceAndExecuteCommands(command_map);
|
||||
|
||||
// Clean up before switching to the older state, for example setting the state
|
||||
// to none sets sys/class/android_usb/android0/enable to 0.
|
||||
@@ -124,5 +312,5 @@ int apply_from_adb(bool* wipe_cache, RecoveryUI* ui) {
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return install_result;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ static bool StartSdcardFuse(const std::string& path) {
|
||||
return run_fuse_sideload(std::move(file_data_reader)) == 0;
|
||||
}
|
||||
|
||||
int ApplyFromSdcard(Device* device, bool* wipe_cache, RecoveryUI* ui) {
|
||||
int ApplyFromSdcard(Device* device, RecoveryUI* ui) {
|
||||
if (ensure_path_mounted(SDCARD_ROOT) != 0) {
|
||||
LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
|
||||
return INSTALL_ERROR;
|
||||
@@ -184,7 +184,7 @@ int ApplyFromSdcard(Device* device, bool* wipe_cache, RecoveryUI* ui) {
|
||||
}
|
||||
}
|
||||
|
||||
result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, false, 0 /*retry_count*/, ui);
|
||||
result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/, ui);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
|
||||
#include <recovery_ui/ui.h>
|
||||
|
||||
int apply_from_adb(bool* wipe_cache, RecoveryUI* ui);
|
||||
int apply_from_adb(RecoveryUI* ui);
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
#include "recovery_ui/device.h"
|
||||
#include "recovery_ui/ui.h"
|
||||
|
||||
int ApplyFromSdcard(Device* device, bool* wipe_cache, RecoveryUI* ui);
|
||||
int ApplyFromSdcard(Device* device, RecoveryUI* ui);
|
||||
|
||||
@@ -43,10 +43,11 @@ enum class OtaType {
|
||||
BRICK,
|
||||
};
|
||||
|
||||
// Installs the given update package. If INSTALL_SUCCESS is returned and *wipe_cache is true on
|
||||
// exit, caller should wipe the cache partition.
|
||||
int install_package(const std::string& package, bool* wipe_cache, bool needs_mount, int retry_count,
|
||||
RecoveryUI* ui);
|
||||
// Installs the given update package. This function should also wipe the cache partition after a
|
||||
// successful installation if |should_wipe_cache| is true or an updater command asks to wipe the
|
||||
// cache.
|
||||
int install_package(const std::string& package, bool should_wipe_cache, bool needs_mount,
|
||||
int retry_count, RecoveryUI* ui);
|
||||
|
||||
// Verifies the package by ota keys. Returns true if the package is verified successfully,
|
||||
// otherwise returns false.
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "recovery_ui/device.h"
|
||||
#include "recovery_ui/ui.h"
|
||||
|
||||
struct selabel_handle;
|
||||
|
||||
// Returns true on success.
|
||||
bool WipeCache(RecoveryUI* ui, const std::function<bool()>& confirm);
|
||||
|
||||
// Returns true on success.
|
||||
bool WipeData(Device* device, bool convert_fbe);
|
||||
+13
-5
@@ -48,6 +48,7 @@
|
||||
|
||||
#include "install/package.h"
|
||||
#include "install/verifier.h"
|
||||
#include "install/wipe_data.h"
|
||||
#include "otautil/error_code.h"
|
||||
#include "otautil/paths.h"
|
||||
#include "otautil/roots.h"
|
||||
@@ -631,10 +632,9 @@ static int really_install_package(const std::string& path, bool* wipe_cache, boo
|
||||
return result;
|
||||
}
|
||||
|
||||
int install_package(const std::string& path, bool* wipe_cache, bool needs_mount, int retry_count,
|
||||
RecoveryUI* ui) {
|
||||
int install_package(const std::string& path, bool should_wipe_cache, bool needs_mount,
|
||||
int retry_count, RecoveryUI* ui) {
|
||||
CHECK(!path.empty());
|
||||
CHECK(wipe_cache != nullptr);
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
@@ -647,8 +647,10 @@ int install_package(const std::string& path, bool* wipe_cache, bool needs_mount,
|
||||
LOG(ERROR) << "failed to set up expected mounts for install; aborting";
|
||||
result = INSTALL_ERROR;
|
||||
} else {
|
||||
result = really_install_package(path, wipe_cache, needs_mount, &log_buffer, retry_count,
|
||||
&max_temperature, ui);
|
||||
bool updater_wipe_cache = false;
|
||||
result = really_install_package(path, &updater_wipe_cache, needs_mount, &log_buffer,
|
||||
retry_count, &max_temperature, ui);
|
||||
should_wipe_cache = should_wipe_cache || updater_wipe_cache;
|
||||
}
|
||||
|
||||
// Measure the time spent to apply OTA update in seconds.
|
||||
@@ -703,6 +705,12 @@ int install_package(const std::string& path, bool* wipe_cache, bool needs_mount,
|
||||
// Write a copy into last_log.
|
||||
LOG(INFO) << log_content;
|
||||
|
||||
if (result == INSTALL_SUCCESS && should_wipe_cache) {
|
||||
if (!WipeCache(ui, nullptr)) {
|
||||
result = INSTALL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "install/wipe_data.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include "otautil/dirutil.h"
|
||||
#include "otautil/logging.h"
|
||||
#include "otautil/roots.h"
|
||||
#include "recovery_ui/ui.h"
|
||||
|
||||
constexpr const char* CACHE_ROOT = "/cache";
|
||||
constexpr const char* DATA_ROOT = "/data";
|
||||
constexpr const char* METADATA_ROOT = "/metadata";
|
||||
|
||||
static bool EraseVolume(const char* volume, RecoveryUI* ui, bool convert_fbe) {
|
||||
bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
|
||||
bool is_data = (strcmp(volume, DATA_ROOT) == 0);
|
||||
|
||||
ui->SetBackground(RecoveryUI::ERASING);
|
||||
ui->SetProgressType(RecoveryUI::INDETERMINATE);
|
||||
|
||||
std::vector<saved_log_file> log_files;
|
||||
if (is_cache) {
|
||||
// If we're reformatting /cache, we load any past logs (i.e. "/cache/recovery/last_*") and the
|
||||
// current log ("/cache/recovery/log") into memory, so we can restore them after the reformat.
|
||||
log_files = ReadLogFilesToMemory();
|
||||
}
|
||||
|
||||
ui->Print("Formatting %s...\n", volume);
|
||||
|
||||
ensure_path_unmounted(volume);
|
||||
|
||||
int result;
|
||||
if (is_data && convert_fbe) {
|
||||
constexpr const char* CONVERT_FBE_DIR = "/tmp/convert_fbe";
|
||||
constexpr const char* CONVERT_FBE_FILE = "/tmp/convert_fbe/convert_fbe";
|
||||
// Create convert_fbe breadcrumb file to signal init to convert to file based encryption, not
|
||||
// full disk encryption.
|
||||
if (mkdir(CONVERT_FBE_DIR, 0700) != 0) {
|
||||
PLOG(ERROR) << "Failed to mkdir " << CONVERT_FBE_DIR;
|
||||
return false;
|
||||
}
|
||||
FILE* f = fopen(CONVERT_FBE_FILE, "wbe");
|
||||
if (!f) {
|
||||
PLOG(ERROR) << "Failed to convert to file encryption";
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
result = format_volume(volume, CONVERT_FBE_DIR);
|
||||
remove(CONVERT_FBE_FILE);
|
||||
rmdir(CONVERT_FBE_DIR);
|
||||
} else {
|
||||
result = format_volume(volume);
|
||||
}
|
||||
|
||||
if (is_cache) {
|
||||
RestoreLogFilesAfterFormat(log_files);
|
||||
}
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
bool WipeCache(RecoveryUI* ui, const std::function<bool()>& confirm_func) {
|
||||
bool has_cache = volume_for_mount_point("/cache") != nullptr;
|
||||
if (!has_cache) {
|
||||
ui->Print("No /cache partition found.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (confirm_func && !confirm_func()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ui->Print("\n-- Wiping cache...\n");
|
||||
bool success = EraseVolume("/cache", ui, false);
|
||||
ui->Print("Cache wipe %s.\n", success ? "complete" : "failed");
|
||||
return success;
|
||||
}
|
||||
|
||||
bool WipeData(Device* device, bool convert_fbe) {
|
||||
RecoveryUI* ui = device->GetUI();
|
||||
ui->Print("\n-- Wiping data...\n");
|
||||
bool success = device->PreWipeData();
|
||||
if (success) {
|
||||
success &= EraseVolume(DATA_ROOT, ui, convert_fbe);
|
||||
bool has_cache = volume_for_mount_point("/cache") != nullptr;
|
||||
if (has_cache) {
|
||||
success &= EraseVolume(CACHE_ROOT, ui, false);
|
||||
}
|
||||
if (volume_for_mount_point(METADATA_ROOT) != nullptr) {
|
||||
success &= EraseVolume(METADATA_ROOT, ui, false);
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
success &= device->PostWipeData();
|
||||
}
|
||||
ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
|
||||
return success;
|
||||
}
|
||||
+30
-1
@@ -40,7 +40,6 @@ cc_library {
|
||||
|
||||
srcs: [
|
||||
"fuse_adb_provider.cpp",
|
||||
"minadbd.cpp",
|
||||
"minadbd_services.cpp",
|
||||
],
|
||||
|
||||
@@ -52,6 +51,36 @@ cc_library {
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libminadbd_headers",
|
||||
recovery_available: true,
|
||||
// TODO create a include dir
|
||||
export_include_dirs: [
|
||||
".",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "minadbd",
|
||||
recovery: true,
|
||||
|
||||
defaults: [
|
||||
"minadbd_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"minadbd.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libadbd",
|
||||
"libbase",
|
||||
"libcrypto",
|
||||
"libfusesideload",
|
||||
"libminadbd_services",
|
||||
],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "minadbd_test",
|
||||
isolated: true,
|
||||
|
||||
+36
-12
@@ -14,30 +14,54 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "minadbd.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/parseint.h>
|
||||
|
||||
#include "adb.h"
|
||||
#include "adb_auth.h"
|
||||
#include "transport.h"
|
||||
|
||||
int minadbd_main() {
|
||||
adb_device_banner = "sideload";
|
||||
#include "minadbd_services.h"
|
||||
#include "minadbd_types.h"
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
int main(int argc, char** argv) {
|
||||
android::base::InitLogging(argv, &android::base::StderrLogger);
|
||||
// TODO(xunchang) implement a command parser
|
||||
if (argc != 3 || strcmp("--socket_fd", argv[1]) != 0) {
|
||||
LOG(ERROR) << "minadbd has invalid arguments, argc: " << argc;
|
||||
exit(kMinadbdArgumentsParsingError);
|
||||
}
|
||||
|
||||
// We can't require authentication for sideloading. http://b/22025550.
|
||||
auth_required = false;
|
||||
int socket_fd;
|
||||
if (!android::base::ParseInt(argv[2], &socket_fd)) {
|
||||
LOG(ERROR) << "Failed to parse int in " << argv[2];
|
||||
exit(kMinadbdArgumentsParsingError);
|
||||
}
|
||||
if (fcntl(socket_fd, F_GETFD, 0) == -1) {
|
||||
PLOG(ERROR) << "Failed to get minadbd socket";
|
||||
exit(kMinadbdSocketIOError);
|
||||
}
|
||||
SetMinadbdSocketFd(socket_fd);
|
||||
|
||||
init_transport_registration();
|
||||
usb_init();
|
||||
adb_device_banner = "sideload";
|
||||
|
||||
VLOG(ADB) << "Event loop starting";
|
||||
fdevent_loop();
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
return 0;
|
||||
// We can't require authentication for sideloading. http://b/22025550.
|
||||
auth_required = false;
|
||||
|
||||
init_transport_registration();
|
||||
usb_init();
|
||||
|
||||
VLOG(ADB) << "Event loop starting";
|
||||
fdevent_loop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "minadbd_services.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
@@ -27,38 +29,95 @@
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/memory.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "adb.h"
|
||||
#include "adb_unique_fd.h"
|
||||
#include "fdevent.h"
|
||||
#include "fuse_adb_provider.h"
|
||||
#include "fuse_sideload.h"
|
||||
#include "minadbd_types.h"
|
||||
#include "services.h"
|
||||
#include "sysdeps.h"
|
||||
|
||||
static int minadbd_socket = -1;
|
||||
void SetMinadbdSocketFd(int socket_fd) {
|
||||
minadbd_socket = socket_fd;
|
||||
}
|
||||
|
||||
static bool WriteCommandToFd(MinadbdCommands cmd, int fd) {
|
||||
char message[kMinadbdMessageSize];
|
||||
memcpy(message, kMinadbdCommandPrefix, strlen(kMinadbdStatusPrefix));
|
||||
android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), cmd);
|
||||
|
||||
if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) {
|
||||
PLOG(ERROR) << "Failed to write message " << message;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Blocks and reads the command status from |fd|. Returns false if the received message has a
|
||||
// format error.
|
||||
static bool WaitForCommandStatus(int fd, MinadbdCommandStatus* status) {
|
||||
char buffer[kMinadbdMessageSize];
|
||||
if (!android::base::ReadFully(fd, buffer, kMinadbdMessageSize)) {
|
||||
PLOG(ERROR) << "Failed to response status from socket";
|
||||
exit(kMinadbdSocketIOError);
|
||||
}
|
||||
|
||||
std::string message(buffer, buffer + kMinadbdMessageSize);
|
||||
if (!android::base::StartsWith(message, kMinadbdStatusPrefix)) {
|
||||
LOG(ERROR) << "Failed to parse status in " << message;
|
||||
return false;
|
||||
}
|
||||
|
||||
*status = android::base::get_unaligned<MinadbdCommandStatus>(
|
||||
message.substr(strlen(kMinadbdStatusPrefix)).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sideload_host_service(unique_fd sfd, const std::string& args) {
|
||||
int64_t file_size;
|
||||
int block_size;
|
||||
if ((sscanf(args.c_str(), "%" SCNd64 ":%d", &file_size, &block_size) != 2) || file_size <= 0 ||
|
||||
block_size <= 0) {
|
||||
printf("bad sideload-host arguments: %s\n", args.c_str());
|
||||
exit(1);
|
||||
LOG(ERROR) << "bad sideload-host arguments: " << args;
|
||||
exit(kMinadbdPackageSizeError);
|
||||
}
|
||||
|
||||
printf("sideload-host file size %" PRId64 " block size %d\n", file_size, block_size);
|
||||
LOG(INFO) << "sideload-host file size " << file_size << ", block size " << block_size;
|
||||
|
||||
if (!WriteCommandToFd(MinadbdCommands::kInstall, minadbd_socket)) {
|
||||
exit(kMinadbdSocketIOError);
|
||||
}
|
||||
|
||||
auto adb_data_reader =
|
||||
std::make_unique<FuseAdbDataProvider>(std::move(sfd), file_size, block_size);
|
||||
int result = run_fuse_sideload(std::move(adb_data_reader));
|
||||
if (int result = run_fuse_sideload(std::move(adb_data_reader)); result != 0) {
|
||||
LOG(ERROR) << "Failed to start fuse";
|
||||
exit(kMinadbdFuseStartError);
|
||||
}
|
||||
|
||||
printf("sideload_host finished\n");
|
||||
exit(result == 0 ? 0 : 1);
|
||||
MinadbdCommandStatus status;
|
||||
if (!WaitForCommandStatus(minadbd_socket, &status)) {
|
||||
exit(kMinadbdMessageFormatError);
|
||||
}
|
||||
LOG(INFO) << "Got command status: " << static_cast<unsigned int>(status);
|
||||
|
||||
LOG(INFO) << "sideload_host finished";
|
||||
exit(kMinadbdSuccess);
|
||||
}
|
||||
|
||||
unique_fd daemon_service_to_fd(std::string_view name, atransport* /* transport */) {
|
||||
if (name.starts_with("sideload:")) {
|
||||
// This exit status causes recovery to print a special error message saying to use a newer adb
|
||||
// (that supports sideload-host).
|
||||
exit(3);
|
||||
exit(kMinadbdAdbVersionError);
|
||||
} else if (name.starts_with("sideload-host:")) {
|
||||
std::string arg(name.substr(strlen("sideload-host:")));
|
||||
return create_service_thread("sideload-host",
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MINADBD_H__
|
||||
#define MINADBD_H__
|
||||
#pragma once
|
||||
|
||||
int minadbd_main();
|
||||
|
||||
#endif
|
||||
void SetMinadbdSocketFd(int socket_fd);
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// The message between recovery and minadbd is 8 bytes in size unless the length is explicitly
|
||||
// specified. Both the command and status has the format |prefix(4 bytes) + encoded enum(4 bytes)|.
|
||||
constexpr size_t kMinadbdMessageSize = 8;
|
||||
constexpr char const kMinadbdCommandPrefix[] = "COMD";
|
||||
constexpr char const kMinadbdStatusPrefix[] = "STAT";
|
||||
|
||||
enum MinadbdErrorCode : int {
|
||||
kMinadbdSuccess = 0,
|
||||
kMinadbdArgumentsParsingError = 1,
|
||||
kMinadbdSocketIOError = 2,
|
||||
kMinadbdMessageFormatError = 3,
|
||||
kMinadbdAdbVersionError = 4,
|
||||
kMinadbdPackageSizeError = 5,
|
||||
kMinadbdFuseStartError = 6,
|
||||
kMinadbdUnsupportedCommandError = 7,
|
||||
kMinadbdCommandExecutionError = 8,
|
||||
kMinadbdErrorUnknown = 9,
|
||||
};
|
||||
|
||||
enum class MinadbdCommandStatus : uint32_t {
|
||||
kSuccess = 0,
|
||||
kFailure = 1,
|
||||
};
|
||||
|
||||
enum class MinadbdCommands : uint32_t {
|
||||
kInstall = 0,
|
||||
kUiPrint = 1,
|
||||
kError = 2,
|
||||
};
|
||||
|
||||
static_assert(kMinadbdMessageSize == sizeof(kMinadbdCommandPrefix) - 1 + sizeof(MinadbdCommands));
|
||||
static_assert(kMinadbdMessageSize ==
|
||||
sizeof(kMinadbdStatusPrefix) - 1 + sizeof(MinadbdCommandStatus));
|
||||
@@ -40,6 +40,7 @@ cc_library_static {
|
||||
android: {
|
||||
srcs: [
|
||||
"dirutil.cpp",
|
||||
"logging.cpp",
|
||||
"mounts.cpp",
|
||||
"parse_install_logs.cpp",
|
||||
"roots.cpp",
|
||||
|
||||
@@ -18,14 +18,26 @@
|
||||
#define _LOGGING_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <log/log_id.h>
|
||||
|
||||
static constexpr int KEEP_LOG_COUNT = 10;
|
||||
|
||||
struct selabel_handle;
|
||||
|
||||
struct saved_log_file {
|
||||
std::string name;
|
||||
struct stat sb;
|
||||
std::string data;
|
||||
};
|
||||
|
||||
void SetLoggingSehandle(selabel_handle* handle);
|
||||
|
||||
ssize_t logbasename(log_id_t id, char prio, const char* filename, const char* buf, size_t len,
|
||||
void* arg);
|
||||
|
||||
@@ -41,10 +53,13 @@ void rotate_logs(const char* last_log_file, const char* last_kmsg_file);
|
||||
void check_and_fclose(FILE* fp, const std::string& name);
|
||||
|
||||
void copy_log_file_to_pmsg(const std::string& source, const std::string& destination);
|
||||
void copy_log_file(const std::string& source, const std::string& destination, bool append);
|
||||
void copy_logs(bool modified_flash, bool has_cache);
|
||||
void copy_logs(bool save_current_log, bool has_cache, const selabel_handle* sehandle);
|
||||
void reset_tmplog_offset();
|
||||
|
||||
void save_kernel_log(const char* destination);
|
||||
|
||||
std::vector<saved_log_file> ReadLogFilesToMemory();
|
||||
|
||||
bool RestoreLogFilesAfterFormat(const std::vector<saved_log_file>& log_files);
|
||||
|
||||
#endif //_LOGGING_H
|
||||
@@ -14,38 +14,51 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "logging.h"
|
||||
#include "otautil/logging.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/klog.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <private/android_filesystem_config.h> /* for AID_SYSTEM */
|
||||
#include <private/android_logger.h> /* private pmsg functions */
|
||||
#include <selinux/label.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "otautil/dirutil.h"
|
||||
#include "otautil/paths.h"
|
||||
#include "otautil/roots.h"
|
||||
|
||||
static constexpr const char* LOG_FILE = "/cache/recovery/log";
|
||||
static constexpr const char* LAST_INSTALL_FILE = "/cache/recovery/last_install";
|
||||
static constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
|
||||
static constexpr const char* LAST_LOG_FILE = "/cache/recovery/last_log";
|
||||
constexpr const char* LOG_FILE = "/cache/recovery/log";
|
||||
constexpr const char* LAST_INSTALL_FILE = "/cache/recovery/last_install";
|
||||
constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
|
||||
constexpr const char* LAST_LOG_FILE = "/cache/recovery/last_log";
|
||||
|
||||
static const std::string LAST_KMSG_FILTER = "recovery/last_kmsg";
|
||||
static const std::string LAST_LOG_FILTER = "recovery/last_log";
|
||||
constexpr const char* LAST_KMSG_FILTER = "recovery/last_kmsg";
|
||||
constexpr const char* LAST_LOG_FILTER = "recovery/last_log";
|
||||
|
||||
constexpr const char* CACHE_LOG_DIR = "/cache/recovery";
|
||||
|
||||
static struct selabel_handle* logging_sehandle;
|
||||
|
||||
void SetLoggingSehandle(selabel_handle* handle) {
|
||||
logging_sehandle = handle;
|
||||
}
|
||||
|
||||
// fopen(3)'s the given file, by mounting volumes and making parent dirs as necessary. Returns the
|
||||
// file pointer, or nullptr on error.
|
||||
static FILE* fopen_path(const std::string& path, const char* mode) {
|
||||
static FILE* fopen_path(const std::string& path, const char* mode, const selabel_handle* sehandle) {
|
||||
if (ensure_path_mounted(path) != 0) {
|
||||
LOG(ERROR) << "Can't mount " << path;
|
||||
return nullptr;
|
||||
@@ -74,8 +87,8 @@ void check_and_fclose(FILE* fp, const std::string& name) {
|
||||
ssize_t logbasename(log_id_t /* id */, char /* prio */, const char* filename, const char* /* buf */,
|
||||
size_t len, void* arg) {
|
||||
bool* do_rotate = static_cast<bool*>(arg);
|
||||
if (LAST_KMSG_FILTER.find(filename) != std::string::npos ||
|
||||
LAST_LOG_FILTER.find(filename) != std::string::npos) {
|
||||
if (std::string(LAST_KMSG_FILTER).find(filename) != std::string::npos ||
|
||||
std::string(LAST_LOG_FILTER).find(filename) != std::string::npos) {
|
||||
*do_rotate = true;
|
||||
}
|
||||
return len;
|
||||
@@ -92,8 +105,8 @@ ssize_t logrotate(log_id_t id, char prio, const char* filename, const char* buf,
|
||||
size_t dot = name.find_last_of('.');
|
||||
std::string sub = name.substr(0, dot);
|
||||
|
||||
if (LAST_KMSG_FILTER.find(sub) == std::string::npos &&
|
||||
LAST_LOG_FILTER.find(sub) == std::string::npos) {
|
||||
if (std::string(LAST_KMSG_FILTER).find(sub) == std::string::npos &&
|
||||
std::string(LAST_LOG_FILTER).find(sub) == std::string::npos) {
|
||||
return __android_log_pmsg_file_write(id, prio, filename, buf, len);
|
||||
}
|
||||
|
||||
@@ -165,8 +178,9 @@ void reset_tmplog_offset() {
|
||||
tmplog_offset = 0;
|
||||
}
|
||||
|
||||
void copy_log_file(const std::string& source, const std::string& destination, bool append) {
|
||||
FILE* dest_fp = fopen_path(destination, append ? "ae" : "we");
|
||||
static void copy_log_file(const std::string& source, const std::string& destination, bool append,
|
||||
const selabel_handle* sehandle) {
|
||||
FILE* dest_fp = fopen_path(destination, append ? "ae" : "we", sehandle);
|
||||
if (dest_fp == nullptr) {
|
||||
PLOG(ERROR) << "Can't open " << destination;
|
||||
} else {
|
||||
@@ -189,11 +203,11 @@ void copy_log_file(const std::string& source, const std::string& destination, bo
|
||||
}
|
||||
}
|
||||
|
||||
void copy_logs(bool modified_flash, bool has_cache) {
|
||||
// We only rotate and record the log of the current session if there are actual attempts to modify
|
||||
// the flash, such as wipes, installs from BCB or menu selections. This is to avoid unnecessary
|
||||
void copy_logs(bool save_current_log, bool has_cache, const selabel_handle* sehandle) {
|
||||
// We only rotate and record the log of the current session if explicitly requested. This usually
|
||||
// happens after wipes, installation from BCB or menu selections. This is to avoid unnecessary
|
||||
// rotation (and possible deletion) of log files, if it does not do anything loggable.
|
||||
if (!modified_flash) {
|
||||
if (!save_current_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -211,9 +225,9 @@ void copy_logs(bool modified_flash, bool has_cache) {
|
||||
rotate_logs(LAST_LOG_FILE, LAST_KMSG_FILE);
|
||||
|
||||
// Copy logs to cache so the system can find out what happened.
|
||||
copy_log_file(Paths::Get().temporary_log_file(), LOG_FILE, true);
|
||||
copy_log_file(Paths::Get().temporary_log_file(), LAST_LOG_FILE, false);
|
||||
copy_log_file(Paths::Get().temporary_install_file(), LAST_INSTALL_FILE, false);
|
||||
copy_log_file(Paths::Get().temporary_log_file(), LOG_FILE, true, sehandle);
|
||||
copy_log_file(Paths::Get().temporary_log_file(), LAST_LOG_FILE, false, sehandle);
|
||||
copy_log_file(Paths::Get().temporary_install_file(), LAST_INSTALL_FILE, false, sehandle);
|
||||
save_kernel_log(LAST_KMSG_FILE);
|
||||
chmod(LOG_FILE, 0600);
|
||||
chown(LOG_FILE, AID_SYSTEM, AID_SYSTEM);
|
||||
@@ -242,3 +256,70 @@ void save_kernel_log(const char* destination) {
|
||||
buffer.resize(n);
|
||||
android::base::WriteStringToFile(buffer, destination);
|
||||
}
|
||||
|
||||
std::vector<saved_log_file> ReadLogFilesToMemory() {
|
||||
ensure_path_mounted("/cache");
|
||||
|
||||
struct dirent* de;
|
||||
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(CACHE_LOG_DIR), closedir);
|
||||
if (!d) {
|
||||
if (errno != ENOENT) {
|
||||
PLOG(ERROR) << "Failed to opendir " << CACHE_LOG_DIR;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<saved_log_file> log_files;
|
||||
while ((de = readdir(d.get())) != nullptr) {
|
||||
if (strncmp(de->d_name, "last_", 5) == 0 || strcmp(de->d_name, "log") == 0) {
|
||||
std::string path = android::base::StringPrintf("%s/%s", CACHE_LOG_DIR, de->d_name);
|
||||
|
||||
struct stat sb;
|
||||
if (stat(path.c_str(), &sb) != 0) {
|
||||
PLOG(ERROR) << "Failed to stat " << path;
|
||||
continue;
|
||||
}
|
||||
// Truncate files to 512kb
|
||||
size_t read_size = std::min<size_t>(sb.st_size, 1 << 19);
|
||||
std::string data(read_size, '\0');
|
||||
|
||||
android::base::unique_fd log_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY)));
|
||||
if (log_fd == -1 || !android::base::ReadFully(log_fd, data.data(), read_size)) {
|
||||
PLOG(ERROR) << "Failed to read log file " << path;
|
||||
continue;
|
||||
}
|
||||
|
||||
log_files.emplace_back(saved_log_file{ path, sb, data });
|
||||
}
|
||||
}
|
||||
|
||||
return log_files;
|
||||
}
|
||||
|
||||
bool RestoreLogFilesAfterFormat(const std::vector<saved_log_file>& log_files) {
|
||||
// Re-create the log dir and write back the log entries.
|
||||
if (ensure_path_mounted(CACHE_LOG_DIR) != 0) {
|
||||
PLOG(ERROR) << "Failed to mount " << CACHE_LOG_DIR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mkdir_recursively(CACHE_LOG_DIR, 0777, false, logging_sehandle) != 0) {
|
||||
PLOG(ERROR) << "Failed to create " << CACHE_LOG_DIR;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& log : log_files) {
|
||||
if (!android::base::WriteStringToFile(log.data, log.name, log.sb.st_mode, log.sb.st_uid,
|
||||
log.sb.st_gid)) {
|
||||
PLOG(ERROR) << "Failed to write to " << log.name;
|
||||
}
|
||||
}
|
||||
|
||||
// Any part of the log we'd copied to cache is now gone.
|
||||
// Reset the pointer so we copy from the beginning of the temp
|
||||
// log.
|
||||
reset_tmplog_offset();
|
||||
copy_logs(true /* save_current_log */, true /* has_cache */, logging_sehandle);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
#include <metricslogger/metrics_logger.h>
|
||||
#include <private/android_logger.h> /* private pmsg functions */
|
||||
|
||||
#include "logging.h"
|
||||
#include "otautil/logging.h"
|
||||
#include "otautil/parse_install_logs.h"
|
||||
|
||||
constexpr const char* LAST_LOG_FILE = "/data/misc/recovery/last_log";
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
#include <private/android_logger.h> /* private pmsg functions */
|
||||
|
||||
#include "logging.h"
|
||||
#include "otautil/logging.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
static const char filter[] = "recovery/";
|
||||
|
||||
+31
-186
@@ -27,7 +27,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -55,30 +54,27 @@
|
||||
#include "install/fuse_sdcard_install.h"
|
||||
#include "install/install.h"
|
||||
#include "install/package.h"
|
||||
#include "logging.h"
|
||||
#include "otautil/dirutil.h"
|
||||
#include "install/wipe_data.h"
|
||||
#include "otautil/error_code.h"
|
||||
#include "otautil/logging.h"
|
||||
#include "otautil/paths.h"
|
||||
#include "otautil/roots.h"
|
||||
#include "otautil/sysutil.h"
|
||||
#include "recovery_ui/screen_ui.h"
|
||||
#include "recovery_ui/ui.h"
|
||||
|
||||
static constexpr const char* CACHE_LOG_DIR = "/cache/recovery";
|
||||
static constexpr const char* COMMAND_FILE = "/cache/recovery/command";
|
||||
static constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
|
||||
static constexpr const char* LAST_LOG_FILE = "/cache/recovery/last_log";
|
||||
static constexpr const char* LOCALE_FILE = "/cache/recovery/last_locale";
|
||||
|
||||
static constexpr const char* CACHE_ROOT = "/cache";
|
||||
static constexpr const char* DATA_ROOT = "/data";
|
||||
static constexpr const char* METADATA_ROOT = "/metadata";
|
||||
|
||||
// We define RECOVERY_API_VERSION in Android.mk, which will be picked up by build system and packed
|
||||
// into target_files.zip. Assert the version defined in code and in Android.mk are consistent.
|
||||
static_assert(kRecoveryApiVersion == RECOVERY_API_VERSION, "Mismatching recovery API versions.");
|
||||
|
||||
static bool modified_flash = false;
|
||||
static bool save_current_log = false;
|
||||
std::string stage;
|
||||
const char* reason = nullptr;
|
||||
|
||||
@@ -148,7 +144,7 @@ static void finish_recovery() {
|
||||
}
|
||||
}
|
||||
|
||||
copy_logs(modified_flash, has_cache);
|
||||
copy_logs(save_current_log, has_cache, sehandle);
|
||||
|
||||
// Reset to normal system boot so recovery won't cycle indefinitely.
|
||||
std::string err;
|
||||
@@ -167,110 +163,6 @@ static void finish_recovery() {
|
||||
sync(); // For good measure.
|
||||
}
|
||||
|
||||
struct saved_log_file {
|
||||
std::string name;
|
||||
struct stat sb;
|
||||
std::string data;
|
||||
};
|
||||
|
||||
static bool erase_volume(const char* volume) {
|
||||
bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
|
||||
bool is_data = (strcmp(volume, DATA_ROOT) == 0);
|
||||
|
||||
ui->SetBackground(RecoveryUI::ERASING);
|
||||
ui->SetProgressType(RecoveryUI::INDETERMINATE);
|
||||
|
||||
std::vector<saved_log_file> log_files;
|
||||
|
||||
if (is_cache) {
|
||||
// If we're reformatting /cache, we load any past logs
|
||||
// (i.e. "/cache/recovery/last_*") and the current log
|
||||
// ("/cache/recovery/log") into memory, so we can restore them after
|
||||
// the reformat.
|
||||
|
||||
ensure_path_mounted(volume);
|
||||
|
||||
struct dirent* de;
|
||||
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(CACHE_LOG_DIR), closedir);
|
||||
if (d) {
|
||||
while ((de = readdir(d.get())) != nullptr) {
|
||||
if (strncmp(de->d_name, "last_", 5) == 0 || strcmp(de->d_name, "log") == 0) {
|
||||
std::string path = android::base::StringPrintf("%s/%s", CACHE_LOG_DIR, de->d_name);
|
||||
|
||||
struct stat sb;
|
||||
if (stat(path.c_str(), &sb) == 0) {
|
||||
// truncate files to 512kb
|
||||
if (sb.st_size > (1 << 19)) {
|
||||
sb.st_size = 1 << 19;
|
||||
}
|
||||
|
||||
std::string data(sb.st_size, '\0');
|
||||
FILE* f = fopen(path.c_str(), "rbe");
|
||||
fread(&data[0], 1, data.size(), f);
|
||||
fclose(f);
|
||||
|
||||
log_files.emplace_back(saved_log_file{ path, sb, data });
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (errno != ENOENT) {
|
||||
PLOG(ERROR) << "Failed to opendir " << CACHE_LOG_DIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->Print("Formatting %s...\n", volume);
|
||||
|
||||
ensure_path_unmounted(volume);
|
||||
|
||||
int result;
|
||||
if (is_data && reason && strcmp(reason, "convert_fbe") == 0) {
|
||||
static constexpr const char* CONVERT_FBE_DIR = "/tmp/convert_fbe";
|
||||
static constexpr const char* CONVERT_FBE_FILE = "/tmp/convert_fbe/convert_fbe";
|
||||
// Create convert_fbe breadcrumb file to signal init to convert to file based encryption, not
|
||||
// full disk encryption.
|
||||
if (mkdir(CONVERT_FBE_DIR, 0700) != 0) {
|
||||
PLOG(ERROR) << "Failed to mkdir " << CONVERT_FBE_DIR;
|
||||
return false;
|
||||
}
|
||||
FILE* f = fopen(CONVERT_FBE_FILE, "wbe");
|
||||
if (!f) {
|
||||
PLOG(ERROR) << "Failed to convert to file encryption";
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
result = format_volume(volume, CONVERT_FBE_DIR);
|
||||
remove(CONVERT_FBE_FILE);
|
||||
rmdir(CONVERT_FBE_DIR);
|
||||
} else {
|
||||
result = format_volume(volume);
|
||||
}
|
||||
|
||||
if (is_cache) {
|
||||
// Re-create the log dir and write back the log entries.
|
||||
if (ensure_path_mounted(CACHE_LOG_DIR) == 0 &&
|
||||
mkdir_recursively(CACHE_LOG_DIR, 0777, false, sehandle) == 0) {
|
||||
for (const auto& log : log_files) {
|
||||
if (!android::base::WriteStringToFile(log.data, log.name, log.sb.st_mode, log.sb.st_uid,
|
||||
log.sb.st_gid)) {
|
||||
PLOG(ERROR) << "Failed to write to " << log.name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PLOG(ERROR) << "Failed to mount / create " << CACHE_LOG_DIR;
|
||||
}
|
||||
|
||||
// Any part of the log we'd copied to cache is now gone.
|
||||
// Reset the pointer so we copy from the beginning of the temp
|
||||
// log.
|
||||
reset_tmplog_offset();
|
||||
copy_logs(modified_flash, has_cache);
|
||||
}
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
static bool yes_no(Device* device, const char* question1, const char* question2) {
|
||||
std::vector<std::string> headers{ question1, question2 };
|
||||
std::vector<std::string> items{ " No", " Yes" };
|
||||
@@ -292,28 +184,6 @@ static bool ask_to_wipe_data(Device* device) {
|
||||
return (chosen_item == 1);
|
||||
}
|
||||
|
||||
// Return true on success.
|
||||
static bool wipe_data(Device* device) {
|
||||
modified_flash = true;
|
||||
|
||||
ui->Print("\n-- Wiping data...\n");
|
||||
bool success = device->PreWipeData();
|
||||
if (success) {
|
||||
success &= erase_volume(DATA_ROOT);
|
||||
if (has_cache) {
|
||||
success &= erase_volume(CACHE_ROOT);
|
||||
}
|
||||
if (volume_for_mount_point(METADATA_ROOT) != nullptr) {
|
||||
success &= erase_volume(METADATA_ROOT);
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
success &= device->PostWipeData();
|
||||
}
|
||||
ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
|
||||
return success;
|
||||
}
|
||||
|
||||
static InstallResult prompt_and_wipe_data(Device* device) {
|
||||
// Use a single string and let ScreenRecoveryUI handles the wrapping.
|
||||
std::vector<std::string> wipe_data_menu_headers{
|
||||
@@ -341,7 +211,8 @@ static InstallResult prompt_and_wipe_data(Device* device) {
|
||||
}
|
||||
|
||||
if (ask_to_wipe_data(device)) {
|
||||
if (wipe_data(device)) {
|
||||
bool convert_fbe = reason && strcmp(reason, "convert_fbe") == 0;
|
||||
if (WipeData(device, convert_fbe)) {
|
||||
return INSTALL_SUCCESS;
|
||||
} else {
|
||||
return INSTALL_ERROR;
|
||||
@@ -350,25 +221,6 @@ static InstallResult prompt_and_wipe_data(Device* device) {
|
||||
}
|
||||
}
|
||||
|
||||
// Return true on success.
|
||||
static bool wipe_cache(bool should_confirm, Device* device) {
|
||||
if (!has_cache) {
|
||||
ui->Print("No /cache partition found.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (should_confirm && !yes_no(device, "Wipe cache?", " THIS CAN NOT BE UNDONE!")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
modified_flash = true;
|
||||
|
||||
ui->Print("\n-- Wiping cache...\n");
|
||||
bool success = erase_volume("/cache");
|
||||
ui->Print("Cache wipe %s.\n", success ? "complete" : "failed");
|
||||
return success;
|
||||
}
|
||||
|
||||
// Secure-wipe a given partition. It uses BLKSECDISCARD, if supported. Otherwise, it goes with
|
||||
// BLKDISCARD (if device supports BLKDISCARDZEROES) or BLKZEROOUT.
|
||||
static bool secure_wipe_partition(const std::string& partition) {
|
||||
@@ -653,7 +505,6 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
|
||||
? Device::REBOOT
|
||||
: device->InvokeMenuItem(chosen_item);
|
||||
|
||||
bool should_wipe_cache = false;
|
||||
switch (chosen_action) {
|
||||
case Device::NO_ACTION:
|
||||
break;
|
||||
@@ -666,41 +517,40 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
|
||||
return chosen_action;
|
||||
|
||||
case Device::WIPE_DATA:
|
||||
save_current_log = true;
|
||||
if (ui->IsTextVisible()) {
|
||||
if (ask_to_wipe_data(device)) {
|
||||
wipe_data(device);
|
||||
WipeData(device, false);
|
||||
}
|
||||
} else {
|
||||
wipe_data(device);
|
||||
WipeData(device, false);
|
||||
return Device::NO_ACTION;
|
||||
}
|
||||
break;
|
||||
|
||||
case Device::WIPE_CACHE:
|
||||
wipe_cache(ui->IsTextVisible(), device);
|
||||
case Device::WIPE_CACHE: {
|
||||
save_current_log = true;
|
||||
std::function<bool()> confirm_func = [&device]() {
|
||||
return yes_no(device, "Wipe cache?", " THIS CAN NOT BE UNDONE!");
|
||||
};
|
||||
WipeCache(ui, ui->IsTextVisible() ? confirm_func : nullptr);
|
||||
if (!ui->IsTextVisible()) return Device::NO_ACTION;
|
||||
break;
|
||||
|
||||
}
|
||||
case Device::APPLY_ADB_SIDELOAD:
|
||||
case Device::APPLY_SDCARD: {
|
||||
modified_flash = true;
|
||||
save_current_log = true;
|
||||
bool adb = (chosen_action == Device::APPLY_ADB_SIDELOAD);
|
||||
if (adb) {
|
||||
status = apply_from_adb(&should_wipe_cache, ui);
|
||||
status = apply_from_adb(ui);
|
||||
} else {
|
||||
status = ApplyFromSdcard(device, &should_wipe_cache, ui);
|
||||
}
|
||||
|
||||
if (status == INSTALL_SUCCESS && should_wipe_cache) {
|
||||
if (!wipe_cache(false, device)) {
|
||||
status = INSTALL_ERROR;
|
||||
}
|
||||
status = ApplyFromSdcard(device, ui);
|
||||
}
|
||||
|
||||
if (status != INSTALL_SUCCESS) {
|
||||
ui->SetBackground(RecoveryUI::ERROR);
|
||||
ui->Print("Installation aborted.\n");
|
||||
copy_logs(modified_flash, has_cache);
|
||||
copy_logs(save_current_log, has_cache, sehandle);
|
||||
} else if (!ui->IsTextVisible()) {
|
||||
return Device::NO_ACTION; // reboot if logs aren't visible
|
||||
} else {
|
||||
@@ -987,7 +837,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||
if (update_package != nullptr) {
|
||||
// It's not entirely true that we will modify the flash. But we want
|
||||
// to log the update attempt since update_package is non-NULL.
|
||||
modified_flash = true;
|
||||
save_current_log = true;
|
||||
|
||||
int required_battery_level;
|
||||
if (retry_count == 0 && !is_battery_ok(&required_battery_level)) {
|
||||
@@ -1009,11 +859,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||
set_retry_bootloader_message(retry_count + 1, args);
|
||||
}
|
||||
|
||||
modified_flash = true;
|
||||
status = install_package(update_package, &should_wipe_cache, true, retry_count, ui);
|
||||
if (status == INSTALL_SUCCESS && should_wipe_cache) {
|
||||
wipe_cache(false, device);
|
||||
}
|
||||
status = install_package(update_package, should_wipe_cache, true, retry_count, ui);
|
||||
if (status != INSTALL_SUCCESS) {
|
||||
ui->Print("Installation aborted.\n");
|
||||
|
||||
@@ -1021,7 +867,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||
// RETRY_LIMIT times before we abandon this OTA update.
|
||||
static constexpr int RETRY_LIMIT = 4;
|
||||
if (status == INSTALL_RETRY && retry_count < RETRY_LIMIT) {
|
||||
copy_logs(modified_flash, has_cache);
|
||||
copy_logs(save_current_log, has_cache, sehandle);
|
||||
retry_count += 1;
|
||||
set_retry_bootloader_message(retry_count, args);
|
||||
// Print retry count on screen.
|
||||
@@ -1045,12 +891,14 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||
}
|
||||
}
|
||||
} else if (should_wipe_data) {
|
||||
if (!wipe_data(device)) {
|
||||
save_current_log = true;
|
||||
bool convert_fbe = reason && strcmp(reason, "convert_fbe") == 0;
|
||||
if (!WipeData(device, convert_fbe)) {
|
||||
status = INSTALL_ERROR;
|
||||
}
|
||||
} else if (should_prompt_and_wipe_data) {
|
||||
// Trigger the logging to capture the cause, even if user chooses to not wipe data.
|
||||
modified_flash = true;
|
||||
save_current_log = true;
|
||||
|
||||
ui->ShowText(true);
|
||||
ui->SetBackground(RecoveryUI::ERROR);
|
||||
@@ -1059,7 +907,8 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||
ui->ShowText(false);
|
||||
}
|
||||
} else if (should_wipe_cache) {
|
||||
if (!wipe_cache(false, device)) {
|
||||
save_current_log = true;
|
||||
if (!WipeCache(ui, nullptr)) {
|
||||
status = INSTALL_ERROR;
|
||||
}
|
||||
} else if (should_wipe_ab) {
|
||||
@@ -1073,15 +922,11 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||
// sideload finishes even if there are errors. Unless one turns on the
|
||||
// text display during the installation. This is to enable automated
|
||||
// testing.
|
||||
save_current_log = true;
|
||||
if (!sideload_auto_reboot) {
|
||||
ui->ShowText(true);
|
||||
}
|
||||
status = apply_from_adb(&should_wipe_cache, ui);
|
||||
if (status == INSTALL_SUCCESS && should_wipe_cache) {
|
||||
if (!wipe_cache(false, device)) {
|
||||
status = INSTALL_ERROR;
|
||||
}
|
||||
}
|
||||
status = apply_from_adb(ui);
|
||||
ui->Print("\nInstall from ADB complete (status: %d).\n", status);
|
||||
if (sideload_auto_reboot) {
|
||||
ui->Print("Rebooting automatically.\n");
|
||||
|
||||
+4
-12
@@ -50,8 +50,8 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "fastboot/fastboot.h"
|
||||
#include "logging.h"
|
||||
#include "minadbd/minadbd.h"
|
||||
#include "install/wipe_data.h"
|
||||
#include "otautil/logging.h"
|
||||
#include "otautil/paths.h"
|
||||
#include "otautil/roots.h"
|
||||
#include "otautil/sysutil.h"
|
||||
@@ -322,16 +322,6 @@ int main(int argc, char** argv) {
|
||||
// Take action to refresh pmsg contents
|
||||
__android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &do_rotate);
|
||||
|
||||
// If this binary is started with the single argument "--adbd", instead of being the normal
|
||||
// recovery binary, it turns into kind of a stripped-down version of adbd that only supports the
|
||||
// 'sideload' command. Note this must be a real argument, not anything in the command file or
|
||||
// bootloader control block; the only way recovery should be run with this argument is when it
|
||||
// starts a copy of itself from the apply_from_adb() function.
|
||||
if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
|
||||
minadbd_main();
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t start = time(nullptr);
|
||||
|
||||
// redirect_stdio should be called only in non-sideload mode. Otherwise we may have two logger
|
||||
@@ -445,6 +435,8 @@ int main(int argc, char** argv) {
|
||||
ui->Print("Warning: No file_contexts\n");
|
||||
}
|
||||
|
||||
SetLoggingSehandle(sehandle);
|
||||
|
||||
std::atomic<Device::BuiltinAction> action;
|
||||
std::thread listener_thread(ListenRecoverySocket, ui, std::ref(action));
|
||||
listener_thread.detach();
|
||||
|
||||
Reference in New Issue
Block a user