Skip the f2fs check for the automotive devices in Android 13. am: a3e0d50468 am: 1863abd733 am: cacc6a75bf am: ccd1383721 am: f71ecd3aeb am: f05e390bf9 am: fc104df9bf Original change: https://android-review.googlesource.com/c/platform/system/gsid/+/2557090 Change-Id: I9f63ac8974a0bd5c5d5cda72ad4f49912419a3cc Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp index 50618f9..1b78971 100644 --- a/Android.bp +++ b/Android.bp
@@ -74,21 +74,19 @@ recovery_available: true, vendor_available: true, export_include_dirs: ["include"], + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], + min_sdk_version: "31", } -cc_binary { - name: "gsid", +cc_defaults { + name: "gsid_defaults", srcs: [ - "daemon.cpp", "gsi_service.cpp", "partition_installer.cpp", ], - required: [ - "mke2fs", - ], - init_rc: [ - "gsid.rc", - ], shared_libs: [ "libbase", "libbinder", @@ -124,6 +122,22 @@ local_include_dirs: ["include"], } +cc_binary { + name: "gsid", + defaults: [ + "gsid_defaults", + ], + srcs: [ + "daemon.cpp", + ], + required: [ + "mke2fs", + ], + init_rc: [ + "gsid.rc", + ], +} + aidl_interface { name: "gsi_aidl_interface", unstable: true, @@ -149,3 +163,22 @@ ], path: "aidl", } + +cc_fuzz { + name: "gsi_service_fuzzer", + defaults: [ + "gsid_defaults", + "service_fuzzer_defaults", + "fuzzer_disable_leaks", + ], + srcs: [ + "fuzzers/GsiServiceFuzzer.cpp", + ], + fuzz_config: { + triage_assignee: "waghpawan@google.com", + cc: [ + "elsk@google.com", + "yochiang@google.com", + ] + }, +}
diff --git a/OWNERS b/OWNERS index a9d0479..e8bcfb2 100644 --- a/OWNERS +++ b/OWNERS
@@ -1,4 +1,4 @@ -# Bug component: 30545 +# Bug component: 322150 dvander@google.com sspatil@google.com elsk@google.com
diff --git a/fuzzers/GsiServiceFuzzer.cpp b/fuzzers/GsiServiceFuzzer.cpp new file mode 100644 index 0000000..1d100d8 --- /dev/null +++ b/fuzzers/GsiServiceFuzzer.cpp
@@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 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 <fuzzbinder/libbinder_driver.h> + +#include "gsi_service.h" + +using android::fuzzService; +using android::sp; +using android::gsi::GsiService; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + auto binder = sp<GsiService>::make(); + fuzzService(binder, FuzzedDataProvider(data, size)); + return 0; +} \ No newline at end of file
diff --git a/gsi_service.cpp b/gsi_service.cpp index 6fc593e..224f520 100644 --- a/gsi_service.cpp +++ b/gsi_service.cpp
@@ -352,10 +352,11 @@ } binder::Status GsiService::removeGsiAsync(const sp<IGsiServiceCallback>& resultCallback) { - bool result = false; - auto status = removeGsi(&result); - if (!status.isOk()) { - LOG(ERROR) << "Could not removeGsi: " << status.exceptionMessage().string(); + int result = IGsiService::INSTALL_OK; + bool success = true; + auto status = removeGsi(&success); + if (!status.isOk() || !success) { + LOG(ERROR) << "Could not removeGsi: " << status.exceptionMessage().c_str(); result = IGsiService::INSTALL_ERROR_GENERIC; } resultCallback->onResult(result); @@ -505,6 +506,12 @@ return binder::Status::ok(); } int fd = installer_->GetPartitionFd(); + if (fd == -1) { + LOG(ERROR) << "Failed to get partition fd"; + *_aidl_return = INSTALL_ERROR_GENERIC; + return binder::Status::ok(); + } + if (!GetAvbPublicKeyFromFd(fd, dst)) { LOG(ERROR) << "Failed to extract AVB public key"; *_aidl_return = INSTALL_ERROR_GENERIC; @@ -619,7 +626,7 @@ auto status = on_progress->onProgress(static_cast<int64_t>(current), static_cast<int64_t>(total)); if (!status.isOk()) { - LOG(ERROR) << "progress callback returned: " << status.toString8().string(); + LOG(ERROR) << "progress callback returned: " << status.toString8().c_str(); return false; } return true;
diff --git a/gsi_service.h b/gsi_service.h index 3c4c278..0dce269 100644 --- a/gsi_service.h +++ b/gsi_service.h
@@ -86,11 +86,11 @@ std::string GetActiveInstalledImageDir(); static std::vector<std::string> GetInstalledDsuSlots(); + GsiService(); private: friend class ImageService; - GsiService(); static int ValidateInstallParams(std::string& install_dir); int EnableGsi(bool one_shot, const std::string& dsu_slot); bool DisableGsiInstall();
diff --git a/gsi_tool.cpp b/gsi_tool.cpp index 01033ae..6aa0fb5 100644 --- a/gsi_tool.cpp +++ b/gsi_tool.cpp
@@ -83,7 +83,7 @@ static std::string ErrorMessage(const android::binder::Status& status, int error_code = IGsiService::INSTALL_ERROR_GENERIC) { if (!status.isOk()) { - return status.exceptionMessage().string(); + return status.exceptionMessage().c_str(); } return "error code " + std::to_string(error_code); } @@ -533,7 +533,7 @@ bool running; auto status = gsid->isGsiRunning(&running); if (!status.isOk()) { - std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } if (running) { @@ -544,7 +544,7 @@ bool installed; status = gsid->isGsiInstalled(&installed); if (!status.isOk()) { - std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } if (!installed) { @@ -569,7 +569,7 @@ bool running; auto status = gsid->isGsiRunning(&running); if (!status.isOk()) { - std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } else if (running) { std::cout << "running" << std::endl; @@ -577,7 +577,7 @@ bool installed; status = gsid->isGsiInstalled(&installed); if (!status.isOk()) { - std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } else if (installed) { std::cout << "installed" << std::endl; @@ -585,7 +585,7 @@ bool enabled; status = gsid->isGsiEnabled(&enabled); if (!status.isOk()) { - std::cerr << status.exceptionMessage().string() << std::endl; + std::cerr << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } else if (running || installed) { std::cout << (enabled ? "enabled" : "disabled") << std::endl; @@ -599,7 +599,7 @@ std::vector<std::string> dsu_slots; status = gsid->getInstalledDsuSlots(&dsu_slots); if (!status.isOk()) { - std::cerr << status.exceptionMessage().string() << std::endl; + std::cerr << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } int n = 0; @@ -613,13 +613,13 @@ // because we can't stat the "outside" userdata. continue; } - std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } std::vector<std::string> images; status = image_service->getAllBackingImages(&images); if (!status.isOk()) { - std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } for (auto&& image : images) { @@ -645,7 +645,7 @@ bool cancelled = false; auto status = gsid->cancelGsiInstall(&cancelled); if (!status.isOk()) { - std::cerr << status.exceptionMessage().string() << std::endl; + std::cerr << status.exceptionMessage().c_str() << std::endl; return EX_SOFTWARE; } if (!cancelled) {
diff --git a/libgsid.cpp b/libgsid.cpp index 4689dcd..fc75c90 100644 --- a/libgsid.cpp +++ b/libgsid.cpp
@@ -27,7 +27,7 @@ sp<IGsiService> GetGsiService() { auto sm = android::defaultServiceManager(); auto name = android::String16(kGsiServiceName); - android::sp<android::IBinder> res = sm->waitForService(name); + static android::sp<android::IBinder> res = sm->waitForService(name); if (res) { return android::interface_cast<IGsiService>(res); }
diff --git a/partition_installer.cpp b/partition_installer.cpp index ebd3b64..ebfb329 100644 --- a/partition_installer.cpp +++ b/partition_installer.cpp
@@ -256,6 +256,9 @@ } int PartitionInstaller::GetPartitionFd() { + if (!system_device_) { + return -1; + } return system_device_->fd(); }
diff --git a/tests/DSUEndtoEndTest.java b/tests/DSUEndtoEndTest.java index 79799bf..8179d59 100644 --- a/tests/DSUEndtoEndTest.java +++ b/tests/DSUEndtoEndTest.java
@@ -21,16 +21,20 @@ import com.android.tradefed.config.Option; import com.android.tradefed.config.Option.Importance; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.util.FileUtil; +import com.android.tradefed.util.SparseImageUtil; +import com.android.tradefed.util.StreamUtil; import com.android.tradefed.util.ZipUtil2; import org.apache.commons.compress.archivers.zip.ZipFile; +import org.junit.Before; import org.junit.After; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.util.concurrent.TimeUnit; /** @@ -40,7 +44,6 @@ public class DSUEndtoEndTest extends DsuTestBase { private static final long kDefaultUserdataSize = 4L * 1024 * 1024 * 1024; private static final String LPUNPACK_PATH = "bin/lpunpack"; - private static final String SIMG2IMG_PATH = "bin/simg2img"; // Example: atest -v DSUEndtoEndTest -- --test-arg \ // com.android.tradefed.testtype.HostTest:set-option:system_image_path:/full/path/to/system.img @@ -51,56 +54,83 @@ importance=Importance.ALWAYS) private String mSystemImagePath; - private File mUnsparseSystemImage; + private File mTempDir; + + private File getTempPath(String relativePath) throws IOException { + if (mTempDir == null) { + mTempDir = FileUtil.createTempDir("DSUEndtoEndTest"); + } + return new File(mTempDir, relativePath); + } + + /** Extract system.img from build info to a temproary file. */ + private File extractSystemImageFromBuildInfo(IBuildInfo buildInfo) + throws IOException, InterruptedException { + File imgZip = ((IDeviceBuildInfo) buildInfo).getDeviceImageFile(); + Assert.assertNotNull( + "Failed to fetch system image. See system_image_path parameter", imgZip); + + File superImg = getTempPath("super.img"); + try (ZipFile zip = new ZipFile(imgZip)) { + File systemImg = getTempPath("system.img"); + if (ZipUtil2.extractFileFromZip(zip, "system.img", systemImg)) { + return systemImg; + } + Assert.assertTrue( + "No system.img or super.img in img zip.", + ZipUtil2.extractFileFromZip(zip, "super.img", superImg)); + } + + if (SparseImageUtil.isSparse(superImg)) { + File unsparseSuperImage = getTempPath("super.raw"); + SparseImageUtil.unsparse(superImg, unsparseSuperImage); + superImg = unsparseSuperImage; + } + + File otaTools = buildInfo.getFile("otatools.zip"); + Assert.assertNotNull("No otatools.zip in BuildInfo.", otaTools); + File otaToolsDir = getTempPath("otatools"); + ZipUtil2.extractZip(otaTools, otaToolsDir); + + String lpunpackPath = new File(otaToolsDir, LPUNPACK_PATH).getAbsolutePath(); + File outputDir = getTempPath("lpunpack_output"); + outputDir.mkdirs(); + String[] cmd = { + lpunpackPath, "-p", "system_a", superImg.getAbsolutePath(), outputDir.getAbsolutePath() + }; + Process p = Runtime.getRuntime().exec(cmd); + p.waitFor(); + if (p.exitValue() != 0) { + String stderr = StreamUtil.getStringFromStream(p.getErrorStream()); + Assert.fail(String.format("lpunpack returned %d. (%s)", p.exitValue(), stderr)); + } + return new File(outputDir, "system_a.img"); + } + + @Before + public void setUp() { + mTempDir = null; + } @After - public void teardown() throws Exception { - if (mUnsparseSystemImage != null) { - mUnsparseSystemImage.delete(); - } + public void tearDown() { + FileUtil.recursiveDelete(mTempDir); } @Test public void testDSU() throws Exception { - String simg2imgPath = "simg2img"; - if (mSystemImagePath == null) { - IBuildInfo buildInfo = getBuild(); - File imgs = ((IDeviceBuildInfo) buildInfo).getDeviceImageFile(); - Assert.assertNotEquals("Failed to fetch system image. See system_image_path parameter", null, imgs); - File otaTools = buildInfo.getFile("otatools.zip"); - File tempdir = ZipUtil2.extractZipToTemp(otaTools, "otatools"); - File system = ZipUtil2.extractFileFromZip(new ZipFile(imgs), "system.img"); - if (system == null) { - File superImg = ZipUtil2.extractFileFromZip(new ZipFile(imgs), "super.img"); - String lpunpackPath = new File(tempdir, LPUNPACK_PATH).getAbsolutePath(); - String outputDir = superImg.getParentFile().getAbsolutePath(); - String[] cmd = {lpunpackPath, "-p", "system_a", superImg.getAbsolutePath(), outputDir}; - Process p = Runtime.getRuntime().exec(cmd); - p.waitFor(); - if (p.exitValue() == 0) { - mSystemImagePath = new File(outputDir, "system_a.img").getAbsolutePath(); - } else { - ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - int len; - byte[] buf = new byte[1024]; - while ((len = p.getErrorStream().read(buf)) != -1) { - stderr.write(buf, 0, len); - } - Assert.assertEquals("non-zero exit value (" + stderr.toString("UTF-8") + ")", 0, p.exitValue()); - } - } else { - mSystemImagePath = system.getAbsolutePath(); - } - simg2imgPath = new File(tempdir, SIMG2IMG_PATH).getAbsolutePath(); + File systemImage; + if (mSystemImagePath != null) { + systemImage = new File(mSystemImagePath); + } else { + systemImage = extractSystemImageFromBuildInfo(getBuild()); } - File gsi = new File(mSystemImagePath); - Assert.assertTrue("not a valid file", gsi.isFile()); - String[] cmd = {simg2imgPath, mSystemImagePath, mSystemImagePath + ".raw"}; - Process p = Runtime.getRuntime().exec(cmd); - p.waitFor(); - if (p.exitValue() == 0) { - mUnsparseSystemImage = new File(mSystemImagePath + ".raw"); - gsi = mUnsparseSystemImage; + Assert.assertTrue("not a valid file", systemImage.isFile()); + + if (SparseImageUtil.isSparse(systemImage)) { + File unsparseSystemImage = getTempPath("system.raw"); + SparseImageUtil.unsparse(systemImage, unsparseSystemImage); + systemImage = unsparseSystemImage; } boolean wasRoot = getDevice().isAdbRoot(); @@ -117,8 +147,8 @@ "gsi_tool install --userdata-size %d" + " --gsi-size %d" + " && sleep 10000000", - getDsuUserdataSize(kDefaultUserdataSize), gsi.length()), - gsi, + getDsuUserdataSize(kDefaultUserdataSize), systemImage.length()), + systemImage, null, 10, TimeUnit.MINUTES,
diff --git a/tests/DsuGsiIntegrationTest.java b/tests/DsuGsiIntegrationTest.java index 78d001c..bb0014a 100644 --- a/tests/DsuGsiIntegrationTest.java +++ b/tests/DsuGsiIntegrationTest.java
@@ -122,6 +122,7 @@ getDevice().executeShellV2Command("gsi_tool wipe"); if (isDsuRunning()) { getDevice().reboot(); + getDevice().disableAdbRoot(); } } catch (DeviceNotAvailableException e) { CLog.w("Failed to clean up DSU installation on device: %s", e); @@ -140,6 +141,7 @@ CLog.i("Wipe existing DSU installation"); assertShellCommand("gsi_tool wipe"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuNotRunning(); } @@ -160,6 +162,7 @@ CLog.i("Test 'gsi_tool enable -s' and 'gsi_tool enable'"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuNotRunning(); final long freeSpaceAfterInstall = getDevice().getPartitionFreeSpace("/data") << 10; @@ -173,12 +176,14 @@ assertShellCommand("gsi_tool enable"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuRunning(); CLog.i("Set up 'adb remount' for testing (requires reboot)"); assertAdbRoot(); assertShellCommand("remount"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuRunning(); assertAdbRoot(); assertShellCommand("remount"); @@ -190,12 +195,14 @@ CLog.i("DSU and original system have separate remount overlays"); assertShellCommand("gsi_tool disable"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuNotRunning(); assertDevicePathNotExist(REMOUNT_TEST_PATH); CLog.i("Test that 'adb remount' is consistent after reboot"); assertShellCommand("gsi_tool enable"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuRunning(); assertDevicePathExist(REMOUNT_TEST_FILE); assertEquals( @@ -208,12 +215,14 @@ assertAdbRoot(); assertShellCommand("enable-verity"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuRunning(); assertDevicePathNotExist(REMOUNT_TEST_PATH); CLog.i("Test 'gsi_tool wipe'"); assertShellCommand("gsi_tool wipe"); getDevice().reboot(); + getDevice().disableAdbRoot(); assertDsuNotRunning(); final double dampeningCoefficient = 0.9;