Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e83b7cf8 authored by Doug Zongker's avatar Doug Zongker
Browse files

support "sideload over ADB" mode

Rather than depending on the existence of some place to store a file
that is accessible to users on an an unbootable device (eg, a physical
sdcard, external USB drive, etc.), add support for sideloading
packages sent to the device with adb.

This change adds a "minimal adbd" which supports nothing but receiving
a package over adb (with the "adb sideload" command) and storing it to
a fixed filename in the /tmp ramdisk, from where it can be verified
and sideloaded in the usual way.  This should be leave available even
on locked user-build devices.

The user can select "apply package from ADB" from the recovery menu,
which starts minimal-adb mode (shutting down any real adbd that may be
running).  Once minimal-adb has received a package it exits
(restarting real adbd if appropriate) and then verification and
installation of the received package proceeds.

always initialize usb product, vendor, etc. for adb in recovery

Set these values even on non-debuggable builds, so that the mini-adb
now in recovery can work.
parent d538eb77
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := \
    roots.cpp \
    ui.cpp \
    screen_ui.cpp \
    verifier.cpp
    verifier.cpp \
    adb_install.cpp

LOCAL_MODULE := recovery

@@ -40,7 +41,7 @@ else
  LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
endif
LOCAL_STATIC_LIBRARIES += libext4_utils libz
LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt
LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt libminadbd
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
LOCAL_STATIC_LIBRARIES += libstdc++ libc

@@ -67,6 +68,7 @@ include $(BUILD_EXECUTABLE)
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minelf/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/minadbd/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
include $(commands_recovery_local_path)/tools/Android.mk
include $(commands_recovery_local_path)/edify/Android.mk

adb_install.cpp

0 → 100644
+110 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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 <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>

#include "ui.h"
#include "cutils/properties.h"
#include "install.h"
#include "common.h"
#include "adb_install.h"
extern "C" {
#include "minadbd/adb.h"
}

static RecoveryUI* ui = NULL;

static void
set_usb_driver(bool enabled) {
    int fd = open("/sys/class/android_usb/android0/enable", O_WRONLY);
    if (fd < 0) {
        ui->Print("failed to open driver control: %s\n", strerror(errno));
        return;
    }
    if (write(fd, enabled ? "1" : "0", 1) < 0) {
        ui->Print("failed to set driver control: %s\n", strerror(errno));
    }
    if (close(fd) < 0) {
        ui->Print("failed to close driver control: %s\n", strerror(errno));
    }
}

static void
stop_adbd() {
    property_set("ctl.stop", "adbd");
    set_usb_driver(false);
}


static void
maybe_restart_adbd() {
    char value[PROPERTY_VALUE_MAX+1];
    int len = property_get("ro.debuggable", value, NULL);
    if (len == 1 && value[0] == '1') {
        ui->Print("Restarting adbd...\n");
        set_usb_driver(true);
        property_set("ctl.start", "adbd");
    }
}

int
apply_from_adb(RecoveryUI* ui_, int* wipe_cache, const char* install_file) {
    ui = ui_;

    stop_adbd();
    set_usb_driver(true);

    ui->Print("\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("/sbin/recovery", "recovery", "--adbd", NULL);
        _exit(-1);
    }
    int status;
    // TODO(dougz): 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) {
        ui->Print("status %d\n", WEXITSTATUS(status));
    }

    set_usb_driver(false);
    maybe_restart_adbd();

    struct stat st;
    if (stat(ADB_SIDELOAD_FILENAME, &st) != 0) {
        if (errno == ENOENT) {
            ui->Print("No package received.\n");
        } else {
            ui->Print("Error reading package:\n  %s\n", strerror(errno));
        }
        return INSTALL_ERROR;
    }
    return install_package(ADB_SIDELOAD_FILENAME, wipe_cache, install_file);
}

adb_install.h

0 → 100644
+24 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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.
 */

#ifndef _ADB_INSTALL_H
#define _ADB_INSTALL_H

class RecoveryUI;

int apply_from_adb(RecoveryUI* h, int* wipe_cache, const char* install_file);

#endif
+4 −6
Original line number Diff line number Diff line
@@ -26,8 +26,7 @@ static const char* HEADERS[] = { "Volume up/down to move highlight;",
                                 NULL };

static const char* ITEMS[] =  {"reboot system now",
                               "apply update from external storage",
                               "apply update from cache",
                               "apply update from ADB",
                               "wipe data/factory reset",
                               "wipe cache partition",
                               NULL };
@@ -72,10 +71,9 @@ class DefaultDevice : public Device {
    BuiltinAction InvokeMenuItem(int menu_position) {
        switch (menu_position) {
          case 0: return REBOOT;
          case 1: return APPLY_EXT;
          case 2: return APPLY_CACHE;
          case 3: return WIPE_DATA;
          case 4: return WIPE_CACHE;
          case 1: return APPLY_ADB_SIDELOAD;
          case 2: return WIPE_DATA;
          case 3: return WIPE_CACHE;
          default: return NO_ACTION;
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ class Device {
    virtual int HandleMenuKey(int key, int visible) = 0;

    enum BuiltinAction { NO_ACTION, REBOOT, APPLY_EXT, APPLY_CACHE,
                         WIPE_DATA, WIPE_CACHE };
                         APPLY_ADB_SIDELOAD, WIPE_DATA, WIPE_CACHE };

    // Perform a recovery action selected from the menu.
    // 'menu_position' will be the item number of the selected menu
Loading