diff options
| author | android-build-prod (mdb) <android-build-team-robot@google.com> | 2020-10-01 20:32:09 +0000 |
|---|---|---|
| committer | android-build-prod (mdb) <android-build-team-robot@google.com> | 2020-10-01 20:32:09 +0000 |
| commit | 7c501746e217b3e8e3af5aa02cc49b2b742f026f (patch) | |
| tree | 9c900f8a269b5b79b8f0637269bf8c4adeee0325 | |
| parent | 2d8684d825519dd7e4e646eb5dfa86436ed1a2ee (diff) | |
| parent | f465eb8c7bd7596566a885c747304f117d801afe (diff) | |
| download | platform_system_gsid-sdk-release.tar.gz platform_system_gsid-sdk-release.tar.bz2 platform_system_gsid-sdk-release.zip | |
Snap for 6877830 from f465eb8c7bd7596566a885c747304f117d801afe to sdk-releasesdk-release
Change-Id: I9a8c5aea93598164c362b4f8e48e1f53bf7057eb
| -rw-r--r-- | aidl/android/gsi/IGsiService.aidl | 13 | ||||
| -rw-r--r-- | gsi_service.cpp | 21 | ||||
| -rw-r--r-- | gsi_service.h | 1 | ||||
| -rw-r--r-- | gsi_tool.cpp | 2 | ||||
| -rw-r--r-- | partition_installer.cpp | 52 | ||||
| -rw-r--r-- | partition_installer.h | 15 | ||||
| -rw-r--r-- | tests/Android.bp | 10 | ||||
| -rw-r--r-- | tests/AndroidManifest.xml | 30 | ||||
| -rw-r--r-- | tests/DSUEndtoEndTest.java | 34 | ||||
| -rw-r--r-- | tests/LockScreenAutomation.java | 151 |
10 files changed, 70 insertions, 259 deletions
diff --git a/aidl/android/gsi/IGsiService.aidl b/aidl/android/gsi/IGsiService.aidl index 5503493..8b38504 100644 --- a/aidl/android/gsi/IGsiService.aidl +++ b/aidl/android/gsi/IGsiService.aidl @@ -179,6 +179,16 @@ interface IGsiService { int createPartition(in @utf8InCpp String name, long size, boolean readOnly); /** + * Complete the current partition installation. A partition installation is + * complete after all pending bytes are written successfully. + * Returns an error if current installation still have pending bytes. + * Returns an error if there is any internal filesystem error. + * + * @return 0 on success, an error code on failure. + */ + int closePartition(); + + /** * Wipe a partition. This will not work if the GSI is currently running. * The partition will not be removed, but the first block will be zeroed. * @@ -212,7 +222,8 @@ interface IGsiService { * 2. Open a new partition installer. * 3. Create and map the new partition. * - * In other words, getAvbPublicKey() works between two createPartition() calls. + * In other words, getAvbPublicKey() should be called after + * createPartition() is called and before closePartition() is called. * * @param dst Output the AVB public key. * @return 0 on success, an error code on failure. diff --git a/gsi_service.cpp b/gsi_service.cpp index 1bcd3dc..3c875f8 100644 --- a/gsi_service.cpp +++ b/gsi_service.cpp @@ -182,6 +182,21 @@ binder::Status GsiService::createPartition(const ::std::string& name, int64_t si return binder::Status::ok(); } +binder::Status GsiService::closePartition(int32_t* _aidl_return) { + ENFORCE_SYSTEM; + std::lock_guard<std::mutex> guard(lock_); + + if (installer_ == nullptr) { + LOG(ERROR) << "createPartition() has to be called before closePartition()"; + *_aidl_return = IGsiService::INSTALL_ERROR_GENERIC; + return binder::Status::ok(); + } + // It is important to not reset |installer_| here because other methods such + // as enableGsi() relies on the state of |installer_|. + *_aidl_return = installer_->FinishInstall(); + return binder::Status::ok(); +} + binder::Status GsiService::commitGsiChunkFromStream(const android::os::ParcelFileDescriptor& stream, int64_t bytes, bool* _aidl_return) { ENFORCE_SYSTEM; @@ -272,7 +287,13 @@ binder::Status GsiService::enableGsi(bool one_shot, const std::string& dsuSlot, } if (installer_) { ENFORCE_SYSTEM; + int status = installer_->FinishInstall(); installer_ = {}; + if (status != IGsiService::INSTALL_OK) { + *_aidl_return = status; + LOG(ERROR) << "Installation failed, cannot enable DSU for slot: " << dsuSlot; + return binder::Status::ok(); + } // Note: create the install status file last, since this is the actual boot // indicator. if (!SetBootMode(one_shot) || !CreateInstallStatusFile()) { diff --git a/gsi_service.h b/gsi_service.h index 229db36..3f81786 100644 --- a/gsi_service.h +++ b/gsi_service.h @@ -42,6 +42,7 @@ class GsiService : public BinderService<GsiService>, public BnGsiService { binder::Status closeInstall(int32_t* _aidl_return) override; binder::Status createPartition(const ::std::string& name, int64_t size, bool readOnly, int32_t* _aidl_return) override; + binder::Status closePartition(int32_t* _aidl_return) override; binder::Status commitGsiChunkFromStream(const ::android::os::ParcelFileDescriptor& stream, int64_t bytes, bool* _aidl_return) override; binder::Status getInstallProgress(::android::gsi::GsiProgress* _aidl_return) override; diff --git a/gsi_tool.cpp b/gsi_tool.cpp index f24fa5d..8839246 100644 --- a/gsi_tool.cpp +++ b/gsi_tool.cpp @@ -255,7 +255,7 @@ static int Install(sp<IGsiService> gsid, int argc, char** argv) { return EX_SOFTWARE; } - android::base::unique_fd input(dup(1)); + android::base::unique_fd input(dup(STDIN_FILENO)); if (input < 0) { std::cerr << "Error duplicating descriptor: " << strerror(errno) << std::endl; return EX_SOFTWARE; diff --git a/partition_installer.cpp b/partition_installer.cpp index 357df50..35ac884 100644 --- a/partition_installer.cpp +++ b/partition_installer.cpp @@ -56,33 +56,32 @@ PartitionInstaller::PartitionInstaller(GsiService* service, const std::string& i } PartitionInstaller::~PartitionInstaller() { - Finish(); - if (!succeeded_) { - // Close open handles before we remove files. - system_device_ = nullptr; - PostInstallCleanup(images_.get()); + if (FinishInstall() != IGsiService::INSTALL_OK) { + LOG(ERROR) << "Installation failed: install_dir=" << install_dir_ + << ", dsu_slot=" << active_dsu_ << ", partition_name=" << name_; } if (IsAshmemMapped()) { UnmapAshmem(); } } -void PartitionInstaller::PostInstallCleanup() { - auto manager = ImageManager::Open(MetadataDir(active_dsu_), install_dir_); - if (!manager) { - LOG(ERROR) << "Could not open image manager"; - return; - } - return PostInstallCleanup(manager.get()); -} - -void PartitionInstaller::PostInstallCleanup(ImageManager* manager) { - std::string file = GetBackingFile(name_); - if (manager->IsImageMapped(file)) { - LOG(ERROR) << "unmap " << file; - manager->UnmapImageDevice(file); +int PartitionInstaller::FinishInstall() { + if (finished_) { + return finished_status_; + } + finished_ = true; + finished_status_ = CheckInstallState(); + system_device_ = nullptr; + if (finished_status_ != IGsiService::INSTALL_OK) { + auto file = GetBackingFile(name_); + LOG(ERROR) << "Installation failed, clean up: " << file; + if (images_->IsImageMapped(file)) { + LOG(ERROR) << "unmap " << file; + images_->UnmapImageDevice(file); + } + images_->DeleteBackingImage(file); } - manager->DeleteBackingImage(file); + return finished_status_; } int PartitionInstaller::StartInstall() { @@ -96,7 +95,6 @@ int PartitionInstaller::StartInstall() { if (!Format()) { return IGsiService::INSTALL_ERROR_GENERIC; } - succeeded_ = true; } else { // Map ${name}_gsi so we can write to it. system_device_ = OpenPartition(GetBackingFile(name_)); @@ -308,26 +306,22 @@ bool PartitionInstaller::Format() { return true; } -int PartitionInstaller::Finish() { - if (readOnly_ && gsi_bytes_written_ != size_) { +int PartitionInstaller::CheckInstallState() { + if (readOnly_ && !IsFinishedWriting()) { // We cannot boot if the image is incomplete. LOG(ERROR) << "image incomplete; expected " << size_ << " bytes, waiting for " << (size_ - gsi_bytes_written_) << " bytes"; return IGsiService::INSTALL_ERROR_GENERIC; } - if (system_device_ != nullptr && fsync(system_device_->fd())) { - PLOG(ERROR) << "fsync failed for " << name_ << "_gsi"; + if (system_device_ != nullptr && fsync(GetPartitionFd())) { + PLOG(ERROR) << "fsync failed for " << GetBackingFile(name_); return IGsiService::INSTALL_ERROR_GENERIC; } - system_device_ = {}; - // If files moved (are no longer pinned), the metadata file will be invalid. // This check can be removed once b/133967059 is fixed. if (!images_->Validate()) { return IGsiService::INSTALL_ERROR_GENERIC; } - - succeeded_ = true; return IGsiService::INSTALL_OK; } diff --git a/partition_installer.h b/partition_installer.h index 1503648..920af47 100644 --- a/partition_installer.h +++ b/partition_installer.h @@ -53,14 +53,17 @@ class PartitionInstaller final { static int WipeWritable(const std::string& active_dsu, const std::string& install_dir, const std::string& name); - // Clean up install state if gsid crashed and restarted. - void PostInstallCleanup(); - void PostInstallCleanup(ImageManager* manager); + // Finish a partition installation and release resources. + // If the installation is incomplete or corrupted, the backing image would + // be cleaned up and an error code is returned. + // No method other than FinishInstall() and ~PartitionInstaller() should be + // called after calling this method. + // This method is also called by the destructor to free up resources. + int FinishInstall(); const std::string& install_dir() const { return install_dir_; } private: - int Finish(); int PerformSanityChecks(); int Preallocate(); bool Format(); @@ -82,10 +85,12 @@ class PartitionInstaller final { bool readOnly_; // Remaining data we're waiting to receive for the GSI image. uint64_t gsi_bytes_written_ = 0; - bool succeeded_ = false; uint64_t ashmem_size_ = -1; void* ashmem_data_ = MAP_FAILED; + bool finished_ = false; + int finished_status_ = 0; + std::unique_ptr<MappedDevice> system_device_; }; diff --git a/tests/Android.bp b/tests/Android.bp index 034209f..70d73ee 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -58,13 +58,3 @@ java_test_host { test_config: "dsu-test.xml", test_suites: ["general-tests"], } - -android_test { - name: "LockScreenAutomation", - srcs: ["LockScreenAutomation.java"], - libs: ["junit", "android.test.base.stubs"], - static_libs: ["androidx.test.uiautomator"], - certificate: "platform", - manifest: "AndroidManifest.xml", - test_suites: ["general-tests"], -} diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml deleted file mode 100644 index 19d0c53..0000000 --- a/tests/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 Google Inc. - - 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. ---> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.lockscreenautomation" - android:sharedUserId="android.uid.system" - > - - <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="28"/> - - <application debuggable="true"> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation android:name="androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner" - android:targetPackage="com.google.android.lockscreenautomation" - android:label="Lock Screen Automation"/> -</manifest> diff --git a/tests/DSUEndtoEndTest.java b/tests/DSUEndtoEndTest.java index 69d40ad..e717079 100644 --- a/tests/DSUEndtoEndTest.java +++ b/tests/DSUEndtoEndTest.java @@ -47,11 +47,6 @@ import java.util.concurrent.TimeUnit; @RunWith(DeviceJUnit4ClassRunner.class) public class DSUEndtoEndTest extends BaseHostJUnit4Test { private static final long kDefaultUserdataSize = 4L * 1024 * 1024 * 1024; - private static final String APK = "LockScreenAutomation.apk"; - private static final String PACKAGE = "com.google.android.lockscreenautomation"; - private static final String UI_AUTOMATOR_INSTRUMENTATION_RUNNER = - "androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner"; - private static final String CLASS = "LockScreenAutomation"; private static final String LPUNPACK_PATH = "bin/lpunpack"; private static final String SIMG2IMG_PATH = "bin/simg2img"; @@ -74,7 +69,6 @@ public class DSUEndtoEndTest extends BaseHostJUnit4Test { @After public void teardown() throws Exception { - uninstallPackage(PACKAGE); if (mUnsparseSystemImage != null) { mUnsparseSystemImage.delete(); } @@ -129,13 +123,6 @@ public class DSUEndtoEndTest extends BaseHostJUnit4Test { expectGsiStatus("normal"); - installPackage(APK); - String method = "setPin"; - String testClass = PACKAGE + "." + CLASS; - String testMethod = testClass + "." + method; - Assert.assertTrue(testMethod + " failed.", - runDeviceTests(UI_AUTOMATOR_INSTRUMENTATION_RUNNER, PACKAGE, testClass, method)); - // Sleep after installing to allow time for gsi_tool to reboot. This prevents a race between // the device rebooting and waitForDeviceAvailable() returning. getDevice().executeShellV2Command("gsi_tool install --userdata-size " + mUserdataSize + @@ -145,7 +132,7 @@ public class DSUEndtoEndTest extends BaseHostJUnit4Test { expectGsiStatus("running"); - rebootAndUnlock(); + getDevice().rebootUntilOnline(); expectGsiStatus("installed"); @@ -162,16 +149,10 @@ public class DSUEndtoEndTest extends BaseHostJUnit4Test { getDevice().executeShellV2Command("gsi_tool wipe"); - rebootAndUnlock(); + getDevice().rebootUntilOnline(); expectGsiStatus("normal"); - method = "removePin"; - testClass = PACKAGE + "." + CLASS; - testMethod = testClass + "." + method; - Assert.assertTrue(testMethod + " failed.", - runDeviceTests(UI_AUTOMATOR_INSTRUMENTATION_RUNNER, PACKAGE, testClass, method)); - if (wasRoot) { getDevice().enableAdbRoot(); } @@ -182,16 +163,5 @@ public class DSUEndtoEndTest extends BaseHostJUnit4Test { String status = result.getStdout().split("\n", 2)[0].trim(); Assert.assertEquals("Device not in expected DSU state", expected, status); } - - private void rebootAndUnlock() throws Exception { - getDevice().rebootUntilOnline(); - getDevice().executeShellV2Command("input keyevent 224"); // KeyEvent.KEYCODE_WAKEUP - getDevice().executeShellV2Command("wm dismiss-keyguard"); - getDevice().executeShellV2Command("input keyevent 7"); // KeyEvent.KEYCODE_0 - getDevice().executeShellV2Command("input keyevent 7"); - getDevice().executeShellV2Command("input keyevent 7"); - getDevice().executeShellV2Command("input keyevent 7"); - getDevice().executeShellV2Command("input keyevent 66"); // KeyEvent.KEYCODE_ENTER - } } diff --git a/tests/LockScreenAutomation.java b/tests/LockScreenAutomation.java deleted file mode 100644 index afefa1c..0000000 --- a/tests/LockScreenAutomation.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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. - */ - -package com.google.android.lockscreenautomation; - -import org.junit.Assert; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.provider.Settings; -import androidx.test.uiautomator.By; -import androidx.test.uiautomator.BySelector; -import androidx.test.uiautomator.UiAutomatorTestCase; -import androidx.test.uiautomator.UiDevice; -import androidx.test.uiautomator.UiObject2; -import androidx.test.uiautomator.UiObjectNotFoundException; -import androidx.test.uiautomator.UiSelector; -import androidx.test.uiautomator.Until; -import android.view.KeyEvent; - -/** - * Methods for configuring lock screen settings - */ -public class LockScreenAutomation extends UiAutomatorTestCase { - - private static final String SETTINGS_PACKAGE = "com.android.settings"; - - private static final long TIMEOUT = 2000L; - - private Context mContext; - private UiDevice mDevice; - - public void setPin() throws Exception { - mContext = getInstrumentation().getContext(); - mDevice = UiDevice.getInstance(getInstrumentation()); - - mDevice.wakeUp(); - mDevice.pressKeyCode(KeyEvent.KEYCODE_MENU); - mDevice.waitForIdle(TIMEOUT); - launchLockScreenSettings(); - - PackageManager pm = mContext.getPackageManager(); - Resources res = pm.getResourcesForApplication(SETTINGS_PACKAGE); - - int resId = res.getIdentifier("unlock_set_unlock_pin_title", "string", SETTINGS_PACKAGE); - findAndClick(By.text(res.getString(resId))); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressEnter(); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - - // Re-enter PIN - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressEnter(); - - findAndClick(By.res(SETTINGS_PACKAGE, "redact_sensitive")); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - findAndClick(By.clazz("android.widget.Button")); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - } - - public void unlock() throws Exception { - mContext = getInstrumentation().getContext(); - mDevice = UiDevice.getInstance(getInstrumentation()); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.pressKeyCode(KeyEvent.KEYCODE_ENTER); - } - - public void removePin() throws Exception { - mContext = getInstrumentation().getContext(); - mDevice = UiDevice.getInstance(getInstrumentation()); - - mDevice.wakeUp(); - mDevice.pressKeyCode(KeyEvent.KEYCODE_MENU); - mDevice.waitForIdle(TIMEOUT); - launchLockScreenSettings(); - - PackageManager pm = mContext.getPackageManager(); - Resources res = pm.getResourcesForApplication(SETTINGS_PACKAGE); - - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressKeyCode(KeyEvent.KEYCODE_0); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - mDevice.pressEnter(); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - - int resId = res.getIdentifier("unlock_set_unlock_off_title", "string", SETTINGS_PACKAGE); - findAndClick(By.text(res.getString(resId))); - mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); - - findAndClick(By.res("android", "button1")); - mDevice.waitForIdle(TIMEOUT); - } - - private void findAndClick(BySelector selector) - { - for (int i = 0; i < 3; i++) { - mDevice.wait(Until.findObject(selector), TIMEOUT); - UiObject2 obj = mDevice.findObject(selector); - if (obj != null) { - obj.click(); - return; - } - } - Assert.fail("Could not find and click " + selector); - } - - private void launchLockScreenSettings() { - final Intent intent = new Intent().setClassName(SETTINGS_PACKAGE, "com.android.settings.password.ChooseLockGeneric"); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - mContext.startActivity(intent); - mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT); - } -} |
