Skip to content

Commit

Permalink
recovery: Implement a volume manager
Browse files Browse the repository at this point in the history
This is a copy of the pre-binderized vold which has been converted to
use direct calls instead of sockets and stripped down to only what is
needed to support recovery.

Includes:
  * Replace security_context_t type

    security_context_t has been marked as deprecated in libselinux from
    version 3.2. Update to the `char*` type.

    Bug: 190808996
    Test: m
    Change-Id: I6f40e161251c79893d41e12c368715736578aacc

  * recovery: volmgr: remove unused IsSupported

    Change-Id: If8206658fdfb6108221806c09c99bf0a30f4a586
    Signed-off-by: Jesse Chan <[email protected]>

  * recovery: volmgr: remove filesystem checks

    Those checks are not strictly necessary and we are
    not building fsck tools for recovery for now.

    Remove those checks so volmgr can be useful.

    Change-Id: I87756c61b933b6cdccd281c6276b686fbd36019f
    Signed-off-by: Jesse Chan <[email protected]>

  * recovery: fixup `EmulatedVolume creating`

    Avoid dangling pointer. Instead of pointing to FstabEntry create copy.

    Change-Id: I57f76006db09a6add2c173f43175f0f6b848d87b

  * recovery: fix volmgr cleaning up

    Don't reset pointer to netlink manager
    Delete disks in stop() rather then in ~VolumeManager
    Call destroy() before deleting disks cause delete expects the
      disk to be destroyed
    Clear the lists or we would read garbage data on the next scan

    Change-Id: Idadfa1f33b7cb5f2f3c780848a99344a6608420e

  * recovery: handle interrupts in apply update menu

    Change-Id: I1f78f9196634353b77986545332d7d52a5f0c161

Change-Id: Ic82d929e052b5ba70ecf7b475e0a223d77d9687e
  • Loading branch information
tdm authored and mikeNG committed Oct 8, 2023
1 parent a981611 commit 3cc950d
Show file tree
Hide file tree
Showing 52 changed files with 3,800 additions and 56 deletions.
2 changes: 2 additions & 0 deletions Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ cc_defaults {
"liblog",
"libprotobuf-cpp-lite",
"libziparchive",
"libvolume_manager",
],

static_libs: [
Expand Down Expand Up @@ -160,6 +161,7 @@ cc_binary {

srcs: [
"recovery_main.cpp",
"volclient.cpp",
],

shared_libs: [
Expand Down
11 changes: 11 additions & 0 deletions etc/init.rc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ on init
chown root shell /tmp
chmod 0775 /tmp

mkdir /storage 0050 root sdcard_r
mount tmpfs tmpfs /storage mode=0050,uid=0,gid=1028

mkdir /mnt 0775 root system

# See storage config details at http://source.android.com/tech/storage/
mkdir /mnt/shell 0700 shell shell

# Directory for staging bindmounts
mkdir /mnt/staging 0700 root root

write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/vm/max_map_count 1000000

Expand Down
1 change: 1 addition & 0 deletions install/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ cc_library_static {

shared_libs: [
"librecovery_ui",
"libvolume_manager",
],

export_include_dirs: [
Expand Down
25 changes: 9 additions & 16 deletions install/fuse_install.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
#include "install/install.h"
#include "recovery_utils/roots.h"

static constexpr const char* SDCARD_ROOT = "/data/media/0";
using android::volmgr::VolumeInfo;
using android::volmgr::VolumeManager;

// How long (in seconds) we wait for the fuse-provided package file to
// appear, before timing out.
static constexpr int SDCARD_INSTALL_TIMEOUT = 10;
Expand All @@ -56,8 +58,6 @@ static void SetSdcardUpdateBootloaderMessage() {

// Returns the selected filename, or an empty string.
static std::string BrowseDirectory(const std::string& path, Device* device, RecoveryUI* ui) {
ensure_path_mounted(path);

std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
if (!d) {
PLOG(ERROR) << "error opening " << path;
Expand Down Expand Up @@ -140,12 +140,6 @@ static bool StartInstallPackageFuse(std::string_view path) {
return false;
}

if (android::base::StartsWith(path, SDCARD_ROOT)) {
// The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
// that our open file continues to work but new references see it as unmounted.
umount2("/data", MNT_DETACH);
}

return run_fuse_sideload(std::move(fuse_data_provider)) == 0;
}

Expand Down Expand Up @@ -208,17 +202,15 @@ InstallResult InstallWithFuseFromPath(std::string_view path, Device* device) {
return result;
}

InstallResult ApplyFromSdcard(Device* device) {
InstallResult ApplyFromStorage(Device* device, VolumeInfo& vi) {
auto ui = device->GetUI();
if (ensure_path_mounted(SDCARD_ROOT) != 0) {
LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
if (!VolumeManager::Instance()->volumeMount(vi.mId)) {
return INSTALL_NONE;
}

std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
std::string path = BrowseDirectory(vi.mPath, device, ui);
if (path.empty()) {
LOG(ERROR) << "\n-- No package file selected.\n";
ensure_path_unmounted(SDCARD_ROOT);
VolumeManager::Instance()->volumeUnmount(vi.mId);
return INSTALL_NONE;
}

Expand All @@ -231,6 +223,7 @@ InstallResult ApplyFromSdcard(Device* device) {
SetSdcardUpdateBootloaderMessage();

auto result = InstallWithFuseFromPath(path, device);
ensure_path_unmounted(SDCARD_ROOT);

VolumeManager::Instance()->volumeUnmount(vi.mId);
return result;
}
6 changes: 5 additions & 1 deletion install/include/install/fuse_install.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@
#include "recovery_ui/device.h"
#include "recovery_ui/ui.h"

#include <volume_manager/VolumeManager.h>

using android::volmgr::VolumeInfo;

// Starts FUSE with the package from |path| as the data source. And installs the package from
// |FUSE_SIDELOAD_HOST_PATHNAME|. The |path| can point to the location of a package zip file or a
// block map file with the prefix '@'; e.g. /sdcard/package.zip, @/cache/recovery/block.map.
InstallResult InstallWithFuseFromPath(std::string_view path, Device* device);

InstallResult ApplyFromSdcard(Device* device);
InstallResult ApplyFromStorage(Device* device, VolumeInfo& vi);
72 changes: 62 additions & 10 deletions recovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <android-base/strings.h>
#include <cutils/properties.h> /* for property_list */
#include <fs_mgr/roots.h>
#include <volume_manager/VolumeManager.h>
#include <ziparchive/zip_archive.h>

#include "bootloader_message/bootloader_message.h"
Expand All @@ -62,6 +63,10 @@
#include "recovery_utils/battery_utils.h"
#include "recovery_utils/logging.h"
#include "recovery_utils/roots.h"
#include "volclient.h"

using android::volmgr::VolumeManager;
using android::volmgr::VolumeInfo;

static constexpr const char* COMMAND_FILE = "/cache/recovery/command";
static constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
Expand Down Expand Up @@ -198,6 +203,47 @@ static bool ask_to_wipe_data(Device* device) {
return (chosen_item == 1);
}

static InstallResult apply_update_menu(Device* device, Device::BuiltinAction* reboot_action){
RecoveryUI* ui = device->GetUI();
std::vector<std::string> headers{ "Apply update" };
std::vector<std::string> items;

const int item_sideload = 0;
std::vector<VolumeInfo> volumes;

InstallResult status = INSTALL_NONE;

for (;;) {
items.clear();
items.push_back("Apply from ADB");
VolumeManager::Instance()->getVolumeInfo(volumes);
for (auto& vitr : volumes) {
items.push_back("Choose from " + vitr.mLabel);
}

int chosen = ui->ShowMenu(
headers, items, 0, false,
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2),
true /* refreshable */);
if (chosen == Device::kRefresh) {
continue;
}
if (chosen == Device::kGoBack) {
break;
}
if (chosen == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
return INSTALL_KEY_INTERRUPTED;
}

if (chosen == item_sideload) {
status = ApplyFromAdb(device, false /* rescue_mode */, reboot_action);
} else {
status = ApplyFromStorage(device, volumes[chosen - 1]);
}
}
return status;
}

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{
Expand Down Expand Up @@ -428,7 +474,6 @@ static Device::BuiltinAction PromptAndWait(Device* device, InstallResult status)

switch (chosen_action) {
case Device::MENU_BASE:
case Device::MENU_UPDATE:
case Device::MENU_WIPE:
case Device::MENU_ADVANCED:
goto change_menu;
Expand Down Expand Up @@ -493,35 +538,30 @@ static Device::BuiltinAction PromptAndWait(Device* device, InstallResult status)
break;
}

case Device::APPLY_ADB_SIDELOAD:
case Device::APPLY_SDCARD:
case Device::APPLY_UPDATE:
case Device::ENTER_RESCUE: {
save_current_log = true;

update_in_progress = true;
WriteUpdateInProgress();

bool adb = true;
Device::BuiltinAction reboot_action;
if (chosen_action == Device::ENTER_RESCUE) {
// Switch to graphics screen.
ui->ShowText(false);
status = ApplyFromAdb(device, true /* rescue_mode */, &reboot_action);
} else if (chosen_action == Device::APPLY_ADB_SIDELOAD) {
status = ApplyFromAdb(device, false /* rescue_mode */, &reboot_action);
} else {
adb = false;
status = ApplyFromSdcard(device);
} else if (chosen_action == Device::APPLY_UPDATE) {
status = apply_update_menu(device, &reboot_action);
}

ui->Print("\nInstall from %s completed with status %d.\n", adb ? "ADB" : "SD card", status);
if (status == INSTALL_REBOOT) {
return reboot_action;
}
if (status == INSTALL_NONE) {
update_in_progress = false;
}

ui->Print("\nInstall completed with status %d.\n", status);
if (status == INSTALL_SUCCESS) {
update_in_progress = false;
if (!ui->IsTextVisible()) {
Expand Down Expand Up @@ -740,6 +780,12 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri

auto ui = device->GetUI();

VolumeClient* volclient = new VolumeClient(device);
VolumeManager* volmgr = VolumeManager::Instance();
if (!volmgr->start(volclient)) {
printf("Failed to start volume manager\n");
}

// Set background string to "installing security update" for security update,
// otherwise set it to "installing system update".
ui->SetSystemUpdateText(security_update);
Expand Down Expand Up @@ -935,5 +981,11 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
// Save logs and clean up before rebooting or shutting down.
FinishRecovery(ui);

volmgr->unmountAll();
volmgr->stop();
delete volclient;

sync();

return next_action;
}
1 change: 1 addition & 0 deletions recovery_ui/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ cc_library {
"libbase",
"libpng",
"libz",
"libvolume_manager",
],
}

Expand Down
21 changes: 6 additions & 15 deletions recovery_ui/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ typedef std::pair<std::string, Device::BuiltinAction> menu_action_t;
static std::vector<std::string> g_main_header{};
static std::vector<menu_action_t> g_main_actions{
{ "Reboot system now", Device::REBOOT },
{ "Apply update", Device::MENU_UPDATE },
{ "Apply update", Device::APPLY_UPDATE },
{ "Factory reset", Device::MENU_WIPE },
{ "Advanced", Device::MENU_ADVANCED },
};
Expand All @@ -58,12 +58,6 @@ static std::vector<menu_action_t> g_wipe_actions{
{ "Format system partition", Device::WIPE_SYSTEM },
};

static std::vector<std::string> g_update_header{ "Apply update" };
static std::vector<menu_action_t> g_update_actions{
{ "Apply from ADB", Device::APPLY_ADB_SIDELOAD },
{ "Choose from internal storage", Device::APPLY_SDCARD },
};

static std::vector<menu_action_t>* current_menu_ = &g_main_actions;
static std::vector<std::string> g_menu_items;

Expand Down Expand Up @@ -91,7 +85,6 @@ static void RemoveMenuItemForAction(std::vector<menu_action_t>& menu, Device::Bu
}

void Device::RemoveMenuItemForAction(Device::BuiltinAction action) {
::RemoveMenuItemForAction(g_update_actions, action);
::RemoveMenuItemForAction(g_wipe_actions, action);
::RemoveMenuItemForAction(g_advanced_actions, action);
}
Expand All @@ -101,11 +94,9 @@ const std::vector<std::string>& Device::GetMenuItems() {
}

const std::vector<std::string>& Device::GetMenuHeaders() {
if (current_menu_ == &g_update_actions)
return g_update_header;
else if (current_menu_ == &g_wipe_actions)
if (current_menu_ == &g_wipe_actions)
return g_wipe_header;
else if (current_menu_ == &g_advanced_actions)
if (current_menu_ == &g_advanced_actions)
return g_advanced_header;
return g_main_header;
}
Expand All @@ -115,9 +106,6 @@ Device::BuiltinAction Device::InvokeMenuItem(size_t menu_position) {

if (action > MENU_BASE) {
switch (action) {
case Device::BuiltinAction::MENU_UPDATE:
current_menu_ = &g_update_actions;
break;
case Device::BuiltinAction::MENU_WIPE:
current_menu_ = &g_wipe_actions;
break;
Expand Down Expand Up @@ -171,6 +159,9 @@ int Device::HandleMenuKey(int key, bool visible) {
case KEY_AGAIN:
return kDoSideload;

case KEY_REFRESH:
return kRefresh;

default:
// If you have all of the above buttons, any other buttons
// are ignored. Otherwise, any button cycles the highlight.
Expand Down
13 changes: 8 additions & 5 deletions recovery_ui/include/recovery_ui/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
#include <string>
#include <vector>

// Forward declaration to avoid including "ui.h".
class RecoveryUI;
#include "ui.h"

class BootState;

Expand All @@ -41,6 +40,7 @@ class Device {
static constexpr const int kDoSideload = -7;
static constexpr const int kScrollUp = -8;
static constexpr const int kScrollDown = -9;
static constexpr const int kRefresh = -10;

// ENTER vs REBOOT: The latter will trigger a reboot that goes through bootloader, which allows
// using a new bootloader / recovery image if applicable. For example, REBOOT_RESCUE goes from
Expand All @@ -49,9 +49,9 @@ class Device {
enum BuiltinAction {
NO_ACTION = 0,
REBOOT = 1,
APPLY_SDCARD = 2,
APPLY_UPDATE = 2,
// APPLY_CACHE was 3.
APPLY_ADB_SIDELOAD = 4,
// APPLY_ADB_SIDELOAD was 4.
WIPE_DATA = 5,
WIPE_CACHE = 6,
REBOOT_BOOTLOADER = 7,
Expand All @@ -72,7 +72,6 @@ class Device {
WIPE_SYSTEM = 100,
ENABLE_ADB = 101,
MENU_BASE = 200,
MENU_UPDATE = 201,
MENU_WIPE = 202,
MENU_ADVANCED = 203,
};
Expand Down Expand Up @@ -165,6 +164,10 @@ class Device {
std::optional<std::string> GetReason() const;
std::optional<std::string> GetStage() const;

virtual void handleVolumeChanged() {
ui_->onVolumeChanged();
}

private:
// The RecoveryUI object that should be used to display the user interface for this device.
std::unique_ptr<RecoveryUI> ui_;
Expand Down
Loading

0 comments on commit 3cc950d

Please sign in to comment.