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

Commit e72c378e authored by Andreas Gampe's avatar Andreas Gampe Committed by Android (Google) Code Review
Browse files

Merge "Otapreopt: Adapt for actual A/B" into nyc-dev

parents 26bd34c9 01ad5984
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -80,6 +80,36 @@ LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)

# OTA chroot tool

include $(CLEAR_VARS)
LOCAL_MODULE := otapreopt_chroot
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS := $(common_cflags)

LOCAL_SRC_FILES := otapreopt_chroot.cpp
LOCAL_SHARED_LIBRARIES := \
    libbase \
    liblog \

LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)

# OTA postinstall script

include $(CLEAR_VARS)
LOCAL_MODULE:= otapreopt_script
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := otapreopt_script.sh

# Let this depend on otapreopt and the chroot tool, so we just have to mention one in a
# configuration.
LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot

include $(BUILD_PREBUILT)

# Tests.

include $(LOCAL_PATH)/tests/Android.mk
 No newline at end of file
+31 −20
Original line number Diff line number Diff line
@@ -216,19 +216,30 @@ static int do_destroy_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSE
    return destroy_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
}

// We use otapreopt_chroot to get into the chroot.
static constexpr const char* kOtaPreopt = "/system/bin/otapreopt_chroot";

static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
    // Time to fork and run otapreopt.

    // Check that the tool exists.
    struct stat s;
    if (stat(kOtaPreopt, &s) != 0) {
        LOG(ERROR) << "Otapreopt chroot tool not found.";
        return -1;
    }

    pid_t pid = fork();
    if (pid == 0) {
        const char* argv[1 + 9 + 1];
    argv[0] = "/system/bin/otapreopt";
        argv[0] = kOtaPreopt;
        for (size_t i = 1; i <= 9; ++i) {
            argv[i] = arg[i - 1];
        }
        argv[10] = nullptr;

        execv(argv[0], (char * const *)argv);
    ALOGE("execv(OTAPREOPT) failed: %s\n", strerror(errno));
        PLOG(ERROR) << "execv(OTAPREOPT_CHROOT) failed";
        exit(99);
    } else {
        int res = wait_child(pid);
+99 −0
Original line number Diff line number Diff line
/*
 ** Copyright 2016, 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 <linux/unistd.h>
#include <sys/mount.h>
#include <sys/wait.h>

#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>

#ifndef LOG_TAG
#define LOG_TAG "otapreopt"
#endif

using android::base::StringPrintf;

namespace android {
namespace installd {

static int otapreopt_chroot(const int argc, char **arg) {
    // We need to run the otapreopt tool from the postinstall partition. As such, set up a
    // mount namespace and change root.

    // Create our own mount namespace.
    if (unshare(CLONE_NEWNS) != 0) {
        PLOG(ERROR) << "Failed to unshare() for otapreopt.";
        exit(200);
    }

    // Make postinstall private, so that our changes don't propagate.
    if (mount("", "/postinstall", nullptr, MS_PRIVATE, nullptr) != 0) {
        PLOG(ERROR) << "Failed to mount private.";
        exit(201);
    }

    // Bind mount necessary directories.
    constexpr const char* kBindMounts[] = {
            "/data", "/dev", "/proc", "/sys"
    };
    for (size_t i = 0; i < arraysize(kBindMounts); ++i) {
        std::string trg = StringPrintf("/postinstall%s", kBindMounts[i]);
        if (mount(kBindMounts[i], trg.c_str(), nullptr, MS_BIND, nullptr) != 0) {
            PLOG(ERROR) << "Failed to bind-mount " << kBindMounts[i];
            exit(202);
        }
    }

    // Chdir into /postinstall.
    if (chdir("/postinstall") != 0) {
        PLOG(ERROR) << "Unable to chdir into /postinstall.";
        exit(203);
    }

    // Make /postinstall the root in our mount namespace.
    if (chroot(".")  != 0) {
        PLOG(ERROR) << "Failed to chroot";
        exit(204);
    }

    if (chdir("/") != 0) {
        PLOG(ERROR) << "Unable to chdir into /.";
        exit(205);
    }

    // Now go on and run otapreopt.

    const char* argv[1 + 9 + 1];
    CHECK_EQ(argc, 10);
    argv[0] = "/system/bin/otapreopt";
    for (size_t i = 1; i <= 9; ++i) {
        argv[i] = arg[i];
    }
    argv[10] = nullptr;

    execv(argv[0], (char * const *)argv);
    PLOG(ERROR) << "execv(OTAPREOPT) failed.";
    exit(99);
}

}  // namespace installd
}  // namespace android

int main(const int argc, char *argv[]) {
    return android::installd::otapreopt_chroot(argc, argv);
}
+50 −0
Original line number Diff line number Diff line
#!/system/bin/sh

#
# Copyright (C) 2016 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.
#

# This script will run as a postinstall step to drive otapreopt.

# Maximum number of packages/steps.
MAXIMUM_PACKAGES=1000

PREPARE=$(cmd otadexopt prepare)
if [ "$PREPARE" != "Success" ] ; then
  echo "Failed to prepare."
  exit 1
fi

i=0
while ((i<MAXIMUM_PACKAGES)) ; do
  cmd otadexopt step
  DONE=$(cmd otadexopt done)
  if [ "$DONE" = "OTA complete." ] ; then
    break
  fi
  sleep 1
  i=$((i+1))
done

DONE=$(cmd otadexopt done)
if [ "$DONE" = "OTA incomplete." ] ; then
  echo "Incomplete."
else
  echo "Complete or error."
fi

cmd otadexopt cleanup

exit 0