diff options
author | Yifan Hong <elsk@google.com> | 2022-08-24 16:05:43 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-08-24 16:05:43 +0000 |
commit | bfaecc580a8cd183e50ea1d3dce70c79fc4059db (patch) | |
tree | 2fd7b299fb019dccf02c386f456f71785a0563f5 | |
parent | 5f39b354f7a185ffa5d77468d034922715c00513 (diff) | |
parent | 463fbba495c072cb7789ac33319670a01ccc1264 (diff) | |
download | Gki-bfaecc580a8cd183e50ea1d3dce70c79fc4059db.tar.gz |
Clean up packages/modules/Gki am: dfb8d4b52a am: 1dcb982f4d am: fa50d143da am: 463fbba495android-u-beta-1-gplmain-16k-with-phones
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Gki/+/2193802
Change-Id: I560c48538c97a114c250b0570a3bc7c24a0ced2e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | Android.bp | 151 | ||||
-rw-r--r-- | TEST_MAPPING | 3 | ||||
-rw-r--r-- | build/Android.bp | 41 | ||||
-rw-r--r-- | build/gki.go | 311 | ||||
-rw-r--r-- | build/kmi.go | 45 | ||||
-rw-r--r-- | build/kmi_test.go | 48 | ||||
-rw-r--r-- | build/prebuilt.go | 125 | ||||
-rw-r--r-- | build/properties.go | 50 | ||||
-rw-r--r-- | build/raw_img_ota.go | 250 | ||||
-rw-r--r-- | build_gki_apex_manifest.cpp | 133 | ||||
-rw-r--r-- | com.android.gki.avbpubkey | bin | 1032 -> 0 bytes | |||
-rw-r--r-- | com.android.gki.pem | 51 | ||||
-rwxr-xr-x | download_boot_prebuilt.py | 140 | ||||
-rw-r--r-- | extract_img_from_apex.py | 96 | ||||
-rw-r--r-- | ota_from_raw_image.py | 113 | ||||
-rw-r--r-- | preinstall.sh | 39 | ||||
-rw-r--r-- | test/Android.bp | 55 | ||||
-rw-r--r-- | test/AndroidTest.xml | 21 | ||||
-rw-r--r-- | test/com.android.gki.kmi_5_4_android12_0_test_prebuilt.apex | bin | 1258765 -> 0 bytes | |||
-rw-r--r-- | test/src/com/android/gki/tests/GkiInstallTest.java | 318 |
20 files changed, 0 insertions, 1990 deletions
diff --git a/Android.bp b/Android.bp deleted file mode 100644 index 509ffa3..0000000 --- a/Android.bp +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (C) 2020 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 { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -python_defaults { - name: "gki_python_defaults", - libs: [ - "releasetools_ota_from_target_files", - ], - version: { - py3: { - embedded_launcher: true, - }, - }, - target: { - darwin: { - // required module "brillo_update_payload" is disabled on darwin - enabled: false, - }, - }, -} - -python_binary_host { - name: "ota_from_raw_image", - defaults: ["gki_python_defaults"], - srcs: ["ota_from_raw_image.py"], - required: [ - "brillo_update_payload", - ], -} - -python_binary_host { - name: "extract_img_from_apex", - defaults: ["gki_python_defaults"], - srcs: ["extract_img_from_apex.py"], - required: [ - "debugfs", - "delta_generator", - ], -} - -apex_key { - name: "com.android.gki.key", - public_key: "com.android.gki.avbpubkey", - private_key: "com.android.gki.pem", -} - -sh_binary { - name: "com.android.gki.preinstall", - product_specific: true, - src: "preinstall.sh", -} - -// Common defaults for all GKI APEXes. -apex_defaults { - name: "com.android.gki_defaults", - product_specific: true, - binaries: [ - "update_engine_stable_client", - "com.android.gki.preinstall", - ], - file_contexts: ":com.android.gki-file_contexts", - // Key to sign apex_payload.img - key: "com.android.gki.key", - // Key to sign APEX. Left empty to use defaults. - certificate: "", - updatable: false, -} - -// Helper binary to build APEX manifest for GKI. -cc_binary_host { - name: "build_gki_apex_manifest", - srcs: [ - "build_gki_apex_manifest.cpp", - ], - static_libs: [ - "libbase", - "libgflags", - "libjsoncpp", - "libkver", - "liblog", - ], - cflags: [ - "-Wall", - "-Werror", - ], -} - -// Build GKI APEX 5.4-android12-unstable from $(PRODUCT_OUT)/boot.img. -// Also generate test packages. -gki_apex { - name: "com.android.gki.kmi_5_4_android12_unstable", - installable: true, - kmi_version: "5.4-android12-unstable", - product_out_path: "boot.img", - gen_test: true, -} - -// Build GKI APEX 5.10-android12-unstable from $(PRODUCT_OUT)/boot.img. -// Also generate test packages. -gki_apex { - name: "com.android.gki.kmi_5_10_android12_unstable", - installable: true, - kmi_version: "5.10-android12-unstable", - product_out_path: "boot.img", - gen_test: true, -} - -// Build GKI APEX 5.4-android12-unstable from $(PRODUCT_OUT)/boot-5.4.img -gki_apex { - name: "com.android.gki.kmi_5_4_android12_unstable_boot-5.4", - installable: false, - kmi_version: "5.4-android12-unstable", - product_out_path: "boot-5.4.img", -} - -// Build GKI APEX 5.10-android12-unstable from $(PRODUCT_OUT)/boot-5.10.img -gki_apex { - name: "com.android.gki.kmi_5_10_android12_unstable_boot-5.10", - installable: false, - kmi_version: "5.10-android12-unstable", - product_out_path: "boot-5.10.img", -} - -// List of all test APEXes for GkiInstallTest. Append "_test_high" and "_test_low" for each -// gki_apex with gen_test:true. -filegroup { - name: "gki_install_test_files", - srcs: [ - ":com.android.gki.kmi_5_4_android12_unstable_test_high", - ":com.android.gki.kmi_5_4_android12_unstable_test_low", - ":com.android.gki.kmi_5_10_android12_unstable_test_high", - ":com.android.gki.kmi_5_10_android12_unstable_test_low", - ], -} diff --git a/TEST_MAPPING b/TEST_MAPPING index 592bd85..ce2bc64 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -2,9 +2,6 @@ "presubmit": [ { "name": "libkver_test" - }, - { - "name": "GkiInstallTest" } ] } diff --git a/build/Android.bp b/build/Android.bp deleted file mode 100644 index d9cb6ff..0000000 --- a/build/Android.bp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2020 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 { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -bootstrap_go_package { - name: "gki-soong-rules", - pkgPath: "android/soong/gki", - pluginFor: ["soong_build"], - deps: [ - "blueprint", - "blueprint-proptools", - "soong", - "soong-android", - "soong-apex", - "soong-phony", - ], - srcs: [ - "gki.go", - "kmi.go", - "prebuilt.go", - "properties.go", - "raw_img_ota.go", - ], - testSrcs: [ - "kmi_test.go", - ], -} diff --git a/build/gki.go b/build/gki.go deleted file mode 100644 index e34130b..0000000 --- a/build/gki.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright (C) 2020 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 gki - -import ( - "path/filepath" - "strings" - - "android/soong/android" - "android/soong/apex" - "android/soong/etc" - "android/soong/genrule" - - "github.com/google/blueprint/proptools" -) - -type gkiApexProperties struct { - // Path relative to $(PRODUCT_OUT) that points to the boot image. This is - // passed to the generated makefile_goal. - // Exactly one of [factory, product_out_path] must be set. - Product_out_path *string - - // Declared KMI version of the boot image. Example: "5.4-android12-0" - Kmi_version *string - - // The certificate to sign the OTA payload. - // The name of a certificate in the default certificate directory, blank to - // use the default product certificate, - // or an android_app_certificate module name in the form ":module". - Ota_payload_certificate *string - - // Whether test APEXes are generated. Test APEXes are named with - // ${name}_test_high and ${name}_test_low, respectively. - Gen_test *bool - - // Whether this APEX is installable to one of the partitions. Default: - // see apex.installable. - Installable *bool - - // Whether modules should be enabled according to board variables. - ModulesEnabled bool `blueprint:"mutated"` - // APEX package name that will be declared in the APEX manifest. - // e.g. com.android.gki.kmi_5_4_android12_0 - ApexName *string `blueprint:"mutated"` -} - -type gkiApex struct { - android.ModuleBase - properties gkiApexProperties -} - -func init() { - android.RegisterModuleType("gki_apex", gkiApexFactory) -} - -// Declare a GKI APEX. Generate a set of modules to define an apex with name -// "com.android.gki" + sanitized(kmi_version). -func gkiApexFactory() android.Module { - g := &gkiApex{} - g.AddProperties(&g.properties) - android.InitAndroidModule(g) - android.AddLoadHook(g, func(ctx android.LoadHookContext) { gkiApexMutator(ctx, g) }) - return g -} - -func gkiApexMutator(mctx android.LoadHookContext, g *gkiApex) { - g.validateAndSetMutableProperties(mctx) - g.createModulesRealApexes(mctx) -} - -func (g *gkiApex) validateAndSetMutableProperties(mctx android.LoadHookContext) { - // Parse kmi_version property to find APEX name. - apexName, err := kmiVersionToApexName(proptools.String(g.properties.Kmi_version)) - if err != nil { - mctx.PropertyErrorf("kmi_version", err.Error()) - return - } - - // Set mutable properties. - g.properties.ModulesEnabled = g.bootImgHasRules(mctx) && g.boardDefinesKmiVersion(mctx) - g.properties.ApexName = proptools.StringPtr(apexName) -} - -func testApexBundleFactory() android.Module { - return apex.ApexBundleFactory(true /* testApex */) -} - -// Create modules for a real APEX package that contains an OTA payload. -func (g *gkiApex) createModulesRealApexes(mctx android.LoadHookContext) { - // Import $(PRODUCT_OUT)/boot.img to Soong - bootImage := g.moduleName() + "_bootimage" - mctx.CreateModule(android.MakefileGoalFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(bootImage), - Enabled: proptools.BoolPtr(g.properties.ModulesEnabled), - }, &makefileGoalProperties{ - Product_out_path: g.properties.Product_out_path, - }) - // boot.img -> kernel_release.txt - mctx.CreateModule(genrule.GenRuleFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(g.kernelReleaseFileName()), - Enabled: proptools.BoolPtr(g.properties.ModulesEnabled), - }, &genRuleProperties{ - Defaults: []string{"extract_kernel_release_defaults"}, - Srcs: []string{":" + bootImage}, - }) - // boot.img -> payload.bin and payload_properties.txt - otaPayloadGen := g.moduleName() + "_ota_payload_gen" - mctx.CreateModule(rawImageOtaFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(otaPayloadGen), - Enabled: proptools.BoolPtr(g.properties.ModulesEnabled), - }, &rawImageOtaProperties{ - Certificate: g.properties.Ota_payload_certificate, - Image_goals: []string{"boot:" + bootImage}, - }) - // copy payload.bin to <apex>/etc/ota - mctx.CreateModule(etc.PrebuiltEtcFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(g.otaPayloadName()), - Enabled: proptools.BoolPtr(g.properties.ModulesEnabled), - }, &prebuiltEtcProperties{ - Src: proptools.StringPtr(":" + otaPayloadGen + "{" + payloadTag + "}"), - Filename_from_src: proptools.BoolPtr(true), - Relative_install_path: proptools.StringPtr("ota"), - Installable: proptools.BoolPtr(false), - }) - // copy payload_properties.txt to <apex>/etc/ota - mctx.CreateModule(etc.PrebuiltEtcFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(g.otaPropertiesName()), - Enabled: proptools.BoolPtr(g.properties.ModulesEnabled), - }, &prebuiltEtcProperties{ - Src: proptools.StringPtr(":" + otaPayloadGen + "{" + payloadPropertiesTag + "}"), - Filename_from_src: proptools.BoolPtr(true), - Relative_install_path: proptools.StringPtr("ota"), - Installable: proptools.BoolPtr(false), - }) - // Create the APEX module with name g.moduleName(). Use factory APEX version. - g.createModulesRealApex(mctx, g.moduleName(), false, "") - - // Create test APEX modules if gen_test. Test packages are not installable. - // Use hard-coded APEX version. - if proptools.Bool(g.properties.Gen_test) { - g.createModulesRealApex(mctx, g.moduleName()+"_test_high", true, "1000000000") - g.createModulesRealApex(mctx, g.moduleName()+"_test_low", true, "1") - } -} - -func (g *gkiApex) createModulesRealApex(mctx android.LoadHookContext, - moduleName string, - isTestApex bool, - overrideApexVersion string) { - // Check kmi_version property against kernel_release.txt, then - // kernel_release.txt -> apex_manifest.json. - apexManifest := moduleName + "_apex_manifest" - mctx.CreateModule(genrule.GenRuleFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(apexManifest), - Enabled: proptools.BoolPtr(g.properties.ModulesEnabled), - }, &genRuleProperties{ - Tools: []string{"build_gki_apex_manifest"}, - Out: []string{"apex_manifest.json"}, - Srcs: []string{":" + g.kernelReleaseFileName()}, - Cmd: proptools.StringPtr(g.createApexManifestCmd(overrideApexVersion)), - }) - - // The APEX module. - - // For test APEXes, if module is not enabled because KMI version is not - // compatible with the device, create a stub module that produces an empty - // file. This is so that the module name can be used in tests. - if isTestApex && !g.properties.ModulesEnabled { - mctx.CreateModule(genrule.GenRuleFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(moduleName), - }, &genRuleProperties{ - Out: []string{moduleName + ".apex"}, - Cmd: proptools.StringPtr(`touch $(out)`), - }) - return - } - - // For test APEXes, if module is enabled, build an apex_test with installable: false. - // For installed APEXes, build apex, respecting installable and enabled. - apexFactory := apex.BundleFactory - overrideInstallable := g.properties.Installable - if isTestApex { - apexFactory = testApexBundleFactory - overrideInstallable = proptools.BoolPtr(false) - } - - mctx.CreateModule(apexFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(moduleName), - Enabled: proptools.BoolPtr(g.properties.ModulesEnabled), - }, &apexProperties{ - Apex_name: g.properties.ApexName, - Manifest: proptools.StringPtr(":" + apexManifest), - Defaults: []string{"com.android.gki_defaults"}, - // A real GKI APEX cannot be preinstalled to the device. - // It can only be provided as an update. - Installable: overrideInstallable, - Prebuilts: []string{ - g.otaPayloadName(), - g.otaPropertiesName(), - }, - }) -} - -// Original module name as specified by the "name" property. -// This is also the APEX module name, i.e. the file name of the APEX file. -// This is also the prefix of names of all generated modules that the phony module depends on. -// e.g. com.android.gki.kmi_5_4_android12_0_boot -func (g *gkiApex) moduleName() string { - return g.BaseModuleName() -} - -// The appeared name of this gkiApex object. Exposed to Soong to avoid conflicting with -// the generated APEX module with name moduleName(). -// e.g. com.android.gki.kmi_5_4_android12_0_boot_all -func (g *gkiApex) Name() string { - return g.moduleName() + "_all" -} - -// Names for intermediate modules. -func (g *gkiApex) kernelReleaseFileName() string { - return g.moduleName() + "_bootimage_kernel_release_file" -} - -func (g *gkiApex) otaPayloadName() string { - return g.moduleName() + "_ota_payload" -} - -func (g *gkiApex) otaPropertiesName() string { - return g.moduleName() + "_ota_payload_properties" -} - -// If the boot image pointed at product_out_path has no rule to be generated, do not generate any -// build rules for this gki_apex module. For example, if this gki_apex module is: -// { name: "foo", product_out_path: "boot-bar.img" } -// But there is no rule to generate boot-bar.img, then -// - `m foo` fails with `unknown target 'foo'` -// - checkbuild is still successful. The module foo doesn't even exist, so there -// is no dependency on boot-bar.img -// -// There is a rule to generate "boot-foo.img" if "kernel-foo" is in BOARD_KERNEL_BINARIES. -// As a special case, there is a rule to generate "boot.img" if BOARD_KERNEL_BINARIES is empty, -// or "kernel" is in BOARD_KERNEL_BINARIES. -func (g *gkiApex) bootImgHasRules(mctx android.EarlyModuleContext) bool { - kernelNames := mctx.DeviceConfig().BoardKernelBinaries() - if len(kernelNames) == 0 { - return proptools.String(g.properties.Product_out_path) == "boot.img" - } - for _, kernelName := range kernelNames { - validBootImagePath := strings.Replace(kernelName, "kernel", "boot", -1) + ".img" - if proptools.String(g.properties.Product_out_path) == validBootImagePath { - return true - } - } - return false -} - -// Only generate if this module's kmi_version property is in BOARD_KERNEL_MODULE_INTERFACE_VERSIONS. -// Otherwise, this board does not support GKI APEXes, so no modules are generated at all. -// This function also avoids building invalid modules in checkbuild. For example, if these -// gki_apex modules are defined: -// gki_apex { name: "boot-kmi-1", kmi_version: "1", product_out_path: "boot.img" } -// gki_apex { name: "boot-kmi-2", kmi_version: "2", product_out_path: "boot.img" } -// But a given device's $PRODUCT_OUT/boot.img can only support at most one KMI version. -// Disable some modules accordingly to make sure checkbuild still works. -func boardDefinesKmiVersion(mctx android.EarlyModuleContext, kmiVersion string) bool { - kmiVersions := mctx.DeviceConfig().BoardKernelModuleInterfaceVersions() - return android.InList(kmiVersion, kmiVersions) -} - -func (g *gkiApex) boardDefinesKmiVersion(mctx android.EarlyModuleContext) bool { - return boardDefinesKmiVersion(mctx, proptools.String(g.properties.Kmi_version)) -} - -// Transform kernel release file in $(in) to KMI version + sublevel. -// e.g. 5.4.42-android12-0 => name: "com.android.gki.kmi_5_4_android12_0", version: "300000000" -// Finally, write APEX manifest JSON to $(out). -func (g *gkiApex) createApexManifestCmd(apexVersion string) string { - ret := `$(location build_gki_apex_manifest) ` + - `--kmi_version "` + proptools.String(g.properties.Kmi_version) + `" ` + - `--apex_manifest $(out) --kernel_release_file $(in)` - // Override version field if set. - if apexVersion != "" { - ret += ` --apex_version ` + apexVersion - } - return ret -} - -func (g *gkiApex) DepsMutator(ctx android.BottomUpMutatorContext) { -} - -func (g *gkiApex) GenerateAndroidBuildActions(ctx android.ModuleContext) { -} - -// OTA payload binary is signed with default_system_dev_certificate, which is equivalent to -// DefaultAppCertificate(). -func getDefaultCertificate(ctx android.EarlyModuleContext) string { - pem, _ := ctx.Config().DefaultAppCertificate(ctx) - return strings.TrimSuffix(pem.String(), filepath.Ext(pem.String())) -} diff --git a/build/kmi.go b/build/kmi.go deleted file mode 100644 index cf03cb2..0000000 --- a/build/kmi.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2020 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. - -// Minimum support of KMI version in Go. Keep in sync with libkver. - -package gki - -import ( - "fmt" - "regexp" -) - -var digits = "([0-9]+)" -var reKmi = regexp.MustCompile("^([0-9]+)[.]([0-9]+)-(android[0-9]+)-([0-9]+|unstable)$") - -// Input is a valid KMI version, e.g. 5.4-android12-0. -// Return a sanitized string to be used as a suffix of APEX package name -// com.android.gki.kmi_5_4_android12_0 -// Keep in sync with libkver. -func kmiVersionToApexName(s string) (string, error) { - matches := reKmi.FindAllStringSubmatch(s, 4) - - if matches == nil { - return "", fmt.Errorf("Poorly formed KMI version: %q must match regex %q", s, reKmi) - } - - version := matches[0][1] - patchLevel := matches[0][2] - androidRelease := matches[0][3] - kmiGeneration := matches[0][4] - - return fmt.Sprintf("com.android.gki.kmi_%s_%s_%s_%s", - version, patchLevel, androidRelease, kmiGeneration), nil -} diff --git a/build/kmi_test.go b/build/kmi_test.go deleted file mode 100644 index de7642b..0000000 --- a/build/kmi_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2020 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. - -// Minimum support of KMI version in Go. Keep in sync with libkver. - -package gki - -import ( - "testing" -) - -func expectValid(t *testing.T, kmi string, expectedApexName string) { - t.Helper() - got, e := kmiVersionToApexName(kmi) - if e != nil { - t.Errorf("Expected no error when parsing %q, got %q", kmi, e) - } - if got != expectedApexName { - t.Errorf("Expected kmiVersionToApexName(%q) == %q, got %q", kmi, expectedApexName, got) - } -} - -func expectInvalid(t *testing.T, kmi string) { - t.Helper() - got, e := kmiVersionToApexName(kmi) - if e == nil { - t.Errorf("Expected error when parsing %q, got no error with result %q", kmi, got) - } -} - -func TestParse(t *testing.T) { - expectInvalid(t, "") - expectInvalid(t, "foobar") - expectInvalid(t, "1") - expectValid(t, "5.4-android12-0", "com.android.gki.kmi_5_4_android12_0") - expectValid(t, "5.4-android12-42", "com.android.gki.kmi_5_4_android12_42") -} diff --git a/build/prebuilt.go b/build/prebuilt.go deleted file mode 100644 index da8a123..0000000 --- a/build/prebuilt.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (C) 2020 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 gki - -import ( - "fmt" - "io" - - "android/soong/android" - "android/soong/apex" - "github.com/google/blueprint/proptools" -) - -var ( - prebuiltApexTag = dependencyTag{name: "prebuilt_apex"} -) - -type prebuiltGkiApexProperties struct { - apex.PrebuiltProperties - - // Declared KMI version of the boot image. Example: "5.4-android12-0" - Kmi_version *string -} - -type prebuiltGkiApex struct { - android.ModuleBase - properties prebuiltGkiApexProperties - - extractedBootImage android.WritablePath -} - -func init() { - android.RegisterModuleType("prebuilt_gki_apex", prebuiltGkiApexFactory) -} - -// Declare a prebuilt GKI APEX. When installed, the boot image is extracted from -// the module. -func prebuiltGkiApexFactory() android.Module { - g := &prebuiltGkiApex{} - g.AddProperties(&g.properties) - android.InitAndroidModule(g) - android.AddLoadHook(g, func(ctx android.LoadHookContext) { prebuiltGkiApexMutator(ctx, g) }) - return g -} -func prebuiltGkiApexMutator(mctx android.LoadHookContext, g *prebuiltGkiApex) { - // Whether modules should be enabled according to board variables. - enabled := boardDefinesKmiVersion(mctx, proptools.String(g.properties.Kmi_version)) - if !enabled { - g.Disable() - } - - // The prebuilt_apex module. - mctx.CreateModule(apex.PrebuiltFactory, &moduleCommonProperties{ - Name: proptools.StringPtr(g.BaseModuleName()), - Enabled: proptools.BoolPtr(enabled), - Product_specific: proptools.BoolPtr(true), - }, &g.properties.PrebuiltProperties) -} - -// The appeared name of this prebuiltGkiApex object. Exposed to Soong to avoid conflicting with -// the generated prebuilt_apex module with name BaseModuleName(). -func (g *prebuiltGkiApex) Name() string { - return g.BaseModuleName() + "_boot_img" -} - -func (g *prebuiltGkiApex) DepsMutator(ctx android.BottomUpMutatorContext) { - ctx.AddDependency(ctx.Module(), prebuiltApexTag, g.BaseModuleName()) -} - -func (g *prebuiltGkiApex) GenerateAndroidBuildActions(ctx android.ModuleContext) { - var apexFile android.OptionalPath - ctx.VisitDirectDepsWithTag(prebuiltApexTag, func(m android.Module) { - if prebuiltApex, ok := m.(*apex.Prebuilt); ok { - srcFiles, err := prebuiltApex.OutputFiles("") - if err != nil { - ctx.ModuleErrorf("Cannot get output files from %q: %s", ctx.OtherModuleName(m), err) - } else if len(srcFiles) != 1 { - ctx.ModuleErrorf("%q generated %d files", ctx.OtherModuleName(m), len(srcFiles)) - } else { - apexFile = android.OptionalPathForPath(srcFiles[0]) - } - } else { - ctx.ModuleErrorf("%q is not a prebuilt_apex", ctx.OtherModuleName(m)) - } - }) - if !apexFile.Valid() { - ctx.ModuleErrorf("Can't determine the prebuilt APEX file") - return - } - - genDir := android.PathForModuleOut(ctx, "extracted") - g.extractedBootImage = genDir.Join(ctx, "boot.img") - - rule := android.NewRuleBuilder(pctx, ctx) - rule.Command(). - ImplicitOutput(g.extractedBootImage). - BuiltTool("extract_img_from_apex"). - Flag("--tool").BuiltTool("debugfs"). - Flag("--tool").BuiltTool("delta_generator"). - Input(apexFile.Path()). - Text(genDir.String()) - rule.Build("extractImgFromApex", "Extract boot image from prebuilt GKI APEX") - - ctx.Phony(g.BaseModuleName(), g.extractedBootImage) -} - -func (g *prebuiltGkiApex) AndroidMk() android.AndroidMkData { - return android.AndroidMkData{ - Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { - fmt.Fprintf(w, "ALL_MODULES.%s.EXTRACTED_BOOT_IMAGE := %s\n", name, g.extractedBootImage) - }, - } -} diff --git a/build/properties.go b/build/properties.go deleted file mode 100644 index af68446..0000000 --- a/build/properties.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2020 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 gki - -type moduleCommonProperties struct { - Name *string - Enabled *bool - Required []string - Product_specific *bool -} - -type makefileGoalProperties struct { - Product_out_path *string -} - -type genRuleProperties struct { - Cmd *string - Defaults []string - Out []string - Srcs []string - Tools []string -} - -type prebuiltEtcProperties struct { - Src *string - Filename_from_src *bool - Relative_install_path *string - Installable *bool -} - -type apexProperties struct { - Apex_name *string - Manifest *string - Defaults []string - Installable *bool - Prebuilts []string - Overrides []string -} diff --git a/build/raw_img_ota.go b/build/raw_img_ota.go deleted file mode 100644 index 2f29e2e..0000000 --- a/build/raw_img_ota.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (C) 2020 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. - -// A special genrule that creates OTA payload and payload_properties from a raw -// image. This rule is created so that the two outputs, payload and -// payload_properties, can be distinguished with tags. - -package gki - -import ( - "fmt" - "sort" - "strings" - - "android/soong/android" - "android/soong/java" - - "github.com/google/blueprint" - "github.com/google/blueprint/proptools" -) - -type dependencyTag struct { - blueprint.BaseDependencyTag - name string -} - -// {"foo": "fooVal", "bar": "barVal"} -> ["${foo}", "${bar}"] -func keysToVars(deps map[string]string) []string { - var ret []string - for dep := range deps { - ret = append(ret, fmt.Sprintf("${%s}", dep)) - } - sort.Strings(ret) - return ret -} - -var ( - certificateTag = dependencyTag{name: "certificate"} - rawImageTag = dependencyTag{name: "raw_image"} - - pctx = android.NewPackageContext("android/gki") - - otaFromRawImageDeps = map[string]string{ - "ota_from_raw_image": "ota_from_raw_image", - - // Needed by ota_from_target_files - "brillo_update_payload": "brillo_update_payload", - - // Needed by brillo_update_payload - "delta_generator": "delta_generator", - // b/171581299: shflags isn't built to the path where HostBinToolVariable - // points to without explicitly declaring it, even if it is stated as - // required by brillo_update_payload. - "shflags": "lib/shflags/shflags", - - // Needed by GetBootImageTimestamp - "lz4": "lz4", - "toybox": "toybox", - "unpack_bootimg": "unpack_bootimg", - } - - otaFromRawImageVarDeps = keysToVars(otaFromRawImageDeps) - - otaFromRawImageRule = pctx.AndroidStaticRule("ota_from_raw_image", blueprint.RuleParams{ - Command: `${ota_from_raw_image} --tools ` + strings.Join(otaFromRawImageVarDeps, " ") + - ` ${kwargs} --out ${outDir} -- ${inputArg}`, - CommandDeps: otaFromRawImageVarDeps, - Description: "ota_from_raw_image ${outDir}", - }, "kwargs", "outDir", "inputArg") - - // Tags to OutputFiles - payloadTag = "payload" - payloadPropertiesTag = "properties" -) - -func init() { - for dep := range otaFromRawImageDeps { - pctx.HostBinToolVariable(dep, otaFromRawImageDeps[dep]) - } - // Intentionally not register this module so that it can only be constructed by gki_apex. -} - -type rawImageOtaProperties struct { - // The name of a certificate in the default certificate directory, blank to use the default product certificate, - // or an android_app_certificate module name in the form ":module". - Certificate *string - - // A set of images and their related modules. Must be in this form - // IMAGE_NAME:MODULE, where IMAGE_NAME is an image name like "boot", and - // MODULE is the name of a makefile_goal. - Image_goals []string -} - -type rawImageOta struct { - android.ModuleBase - properties rawImageOtaProperties - - pem android.Path - key android.Path - - outPayload android.WritablePath - outProperties android.WritablePath -} - -// Declare a rule that generates a signed OTA payload from a raw image. This -// includes payload.bin and payload_properties.txt. -func rawImageOtaFactory() android.Module { - r := &rawImageOta{} - r.AddProperties(&r.properties) - android.InitAndroidModule(r) - return r -} - -func (r *rawImageOta) OutputFiles(tag string) (android.Paths, error) { - switch tag { - case "": - return android.Paths{r.outPayload, r.outProperties}, nil - case payloadTag: - return android.Paths{r.outPayload}, nil - case payloadPropertiesTag: - return android.Paths{r.outProperties}, nil - default: - return nil, fmt.Errorf("unsupported module reference tag %q", tag) - } -} - -var _ android.OutputFileProducer = (*rawImageOta)(nil) - -func (r *rawImageOta) getCertString(ctx android.BaseModuleContext) string { - moduleName := ctx.ModuleName() - certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(moduleName) - if overridden { - return ":" + certificate - } - return proptools.String(r.properties.Certificate) -} - -// Returns module->image_name mapping, e.g. "bootimage_soong"->"boot" -func (r *rawImageOta) goalToImage(ctx android.EarlyModuleContext) map[string]string { - ret := map[string]string{} - for _, imageGoal := range r.properties.Image_goals { - lst := strings.Split(imageGoal, ":") - if len(lst) != 2 { - ctx.PropertyErrorf("image_goals", "Must be in the form IMAGE_NAME:MODULE") - return map[string]string{} - } - ret[lst[1]] = lst[0] - } - return ret -} - -func (r *rawImageOta) DepsMutator(ctx android.BottomUpMutatorContext) { - // Add dependency to modules in image_goals - for module, _ := range r.goalToImage(ctx) { - ctx.AddVariationDependencies(nil, rawImageTag, module) - } - // Add dependency to certificate module, if any. - cert := android.SrcIsModule(r.getCertString(ctx)) - if cert != "" { - ctx.AddVariationDependencies(nil, certificateTag, cert) - } -} - -func (r *rawImageOta) GenerateAndroidBuildActions(ctx android.ModuleContext) { - inputArg := []string{} - kwargs := []string{} - implicits := android.Paths{} - - // Handle image_goals - goalToImage := r.goalToImage(ctx) - ctx.VisitDirectDepsWithTag(rawImageTag, func(module android.Module) { - depName := ctx.OtherModuleName(module) - imgPath := android.OutputFileForModule(ctx, module, "") - if imgPath != nil { - implicits = append(implicits, imgPath) - inputArg = append(inputArg, goalToImage[depName]+":"+imgPath.String()) - } else { - ctx.ModuleErrorf("image dependency %q does not generate any output", depName) - } - }) - - // Handle certificate - ctx.VisitDirectDepsWithTag(certificateTag, func(module android.Module) { - depName := ctx.OtherModuleName(module) - if cert, ok := module.(*java.AndroidAppCertificate); ok { - r.pem = cert.Certificate.Pem - r.key = cert.Certificate.Key - } else { - ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName) - } - }) - r.setCertificateAndPrivateKey(ctx) - keyName, keyError := removeCertExt(r.pem) - if keyError != nil { - ctx.ModuleErrorf("Cannot get certificate to sign the OTA payload binary: " + keyError.Error()) - } - implicits = append(implicits, r.pem, r.key) - kwargs = append(kwargs, "--key "+proptools.String(keyName)) - - // Set outputs - outDir := android.PathForModuleGen(ctx, "payload_files") - r.outPayload = outDir.Join(ctx, "payload.bin") - r.outProperties = outDir.Join(ctx, "payload_properties.txt") - - ctx.Build(pctx, android.BuildParams{ - Rule: otaFromRawImageRule, - Description: "Generate OTA from raw image", - Implicits: implicits, - Outputs: android.WritablePaths{r.outPayload, r.outProperties}, - Args: map[string]string{ - "kwargs": strings.Join(kwargs, " "), - "outDir": outDir.String(), - "inputArg": strings.Join(inputArg, " "), - }, - }) -} - -func (r *rawImageOta) setCertificateAndPrivateKey(ctx android.ModuleContext) { - if r.pem == nil { - cert := proptools.String(r.properties.Certificate) - if cert == "" { - pem, key := ctx.Config().DefaultAppCertificate(ctx) - r.pem = pem - r.key = key - } else { - defaultDir := ctx.Config().DefaultAppCertificateDir(ctx) - r.pem = defaultDir.Join(ctx, cert+".x509.pem") - r.key = defaultDir.Join(ctx, cert+".pk8") - } - } -} - -func removeCertExt(path android.Path) (*string, error) { - s := path.String() - if strings.HasSuffix(s, ".x509.pem") { - return proptools.StringPtr(strings.TrimSuffix(s, ".x509.pem")), nil - } - return nil, fmt.Errorf("Path %q does not end with .x509.pem", s) -} diff --git a/build_gki_apex_manifest.cpp b/build_gki_apex_manifest.cpp deleted file mode 100644 index 3e6a878..0000000 --- a/build_gki_apex_manifest.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// -// Copyright (C) 2020 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 <sysexits.h> - -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/strings.h> -#include <gflags/gflags.h> -#include <json/json.h> -#include <kver/kernel_release.h> -#include <kver/kmi_version.h> -#include <kver/utils.h> - -using android::kver::GetFactoryApexVersion; -using android::kver::KernelRelease; -using android::kver::KmiVersion; - -static constexpr uint64_t UNSTABLE_GENERATION = UINT64_MAX; - -namespace { - -int CheckKmi(const KernelRelease& kernel_release, const KmiVersion& kmi_version) { - const auto& actual_kmi_version = kernel_release.kmi_version(); - if (actual_kmi_version == kmi_version) { - return EX_OK; - } - if (kmi_version.generation() == UNSTABLE_GENERATION && - kmi_version.version() == actual_kmi_version.version() && - kmi_version.patch_level() == actual_kmi_version.patch_level() && - kmi_version.android_release() == actual_kmi_version.android_release()) { - LOG(WARNING) << "Actual KMI version " << actual_kmi_version.string() - << " matches unstable KMI version"; - return EX_OK; - } - LOG(ERROR) << "KMI version does not match. Actual: " << actual_kmi_version.string() - << ", expected: " << kmi_version.string(); - return EX_SOFTWARE; -} - -int WriteApexManifest(const std::string& apex_name, Json::UInt64 apex_version, - const std::string& out_file) { - Json::Value root; - root["name"] = apex_name; - root["version"] = apex_version; - root["preInstallHook"] = "bin/com.android.gki.preinstall"; - Json::StreamWriterBuilder factory; - std::string json_string = Json::writeString(factory, root); - if (!android::base::WriteStringToFile(json_string, out_file)) { - PLOG(ERROR) << "Cannot write to " << out_file; - return EX_SOFTWARE; - } - return EX_OK; -} - -} // namespace - -DEFINE_string(kernel_release_file, "", - "Input file that contains a kernel release string parsed from the boot image. " - "Exactly one of --kernel_release_file or --factory must be set."); -DEFINE_bool(factory, false, - "Set to true for factory APEX package. Exactly one of --kernel_release_file or " - "--factory must be set."); -DEFINE_string(kmi_version, "", "Declared KMI version for this APEX."); -DEFINE_string(apex_manifest, "", "Output APEX manifest JSON file."); -DEFINE_uint64(apex_version, GetFactoryApexVersion(), - "Override APEX version in APEX manifest. Use factory APEX version if unspecified."); - -int main(int argc, char** argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - - if (FLAGS_kmi_version.empty()) { - LOG(ERROR) << "--kmi_version must be set."; - return EX_SOFTWARE; - } - std::string_view kmi_version_sv(FLAGS_kmi_version); - std::string kmi_version_string; - if (android::base::ConsumeSuffix(&kmi_version_sv, "unstable")) { - kmi_version_string = std::string(kmi_version_sv) + std::to_string(UNSTABLE_GENERATION); - } else { - kmi_version_string = kmi_version_sv; - } - auto kmi_version = KmiVersion::Parse(kmi_version_string); - if (!kmi_version.has_value()) { - LOG(ERROR) << "--kmi_version is not a valid KMI version."; - return EX_SOFTWARE; - } - - if (FLAGS_factory + (!FLAGS_kernel_release_file.empty()) != 1) { - LOG(ERROR) << "Exactly one of --kernel_release_file or --factory must be set."; - return EX_SOFTWARE; - } - - if (!FLAGS_kernel_release_file.empty()) { - std::string kernel_release_string; - if (!android::base::ReadFileToString(FLAGS_kernel_release_file, &kernel_release_string)) { - PLOG(ERROR) << "Cannot read " << FLAGS_kernel_release_file; - return EX_SOFTWARE; - } - auto kernel_release = KernelRelease::Parse(kernel_release_string, true /* allow_suffix */); - if (!kernel_release.has_value()) { - LOG(ERROR) << kernel_release_string << " is not a valid GKI kernel release string"; - return EX_SOFTWARE; - } - int res = CheckKmi(*kernel_release, *kmi_version); - if (res != EX_OK) return res; - } - - std::string apex_name = GetApexName(*kmi_version); - uint64_t apex_version = FLAGS_apex_version; - - if (FLAGS_apex_manifest.empty()) { - LOG(WARNING) << "Skip writing APEX manifest because --apex_manifest is not set."; - } else { - int res = WriteApexManifest(apex_name, apex_version, FLAGS_apex_manifest); - if (res != EX_OK) return res; - } - - return EX_OK; -} diff --git a/com.android.gki.avbpubkey b/com.android.gki.avbpubkey Binary files differdeleted file mode 100644 index 166d37e..0000000 --- a/com.android.gki.avbpubkey +++ /dev/null diff --git a/com.android.gki.pem b/com.android.gki.pem deleted file mode 100644 index fd85678..0000000 --- a/com.android.gki.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/download_boot_prebuilt.py b/download_boot_prebuilt.py deleted file mode 100755 index bd665d7..0000000 --- a/download_boot_prebuilt.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2019-2020 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. -# - -import argparse -import collections -import functools -import glob -import json -import logging -import os -import pathlib -import re -import shlex -import shutil -import subprocess -import sys -import tempfile -import urllib.request - -from concurrent import futures -from pathlib import Path - -BASE_URL = "https://ci.android.com/builds/submitted/{build_id}/{target}/latest/raw" -SUPPORTED_ARCHS = ["arm64"] -VARIANTS = ["userdebug"] -BOOT_PREBUILT_REL_DIR = "packages/modules/BootPrebuilt" -ANDROID_BUILD_TOP = os.environ["ANDROID_BUILD_TOP"] - -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) - -def parse_args(): - parser = argparse.ArgumentParser() - parser.add_argument( - "build_id", - type=int, - help="the build id to download the build for, e.g. 6148204") - parser.add_argument( - "--bug", - type=str, - default=None, - help="optional bug number for git commit.") - - return parser.parse_args() - - -def download_file(url, dest_filename): - logger.info("Downloading %s -> %s", url, dest_filename) - urllib.request.urlretrieve(url, dest_filename) - - -def get_artifact_download_spec(build_id, device, variant, dest_dir): - target = "{}-{}".format(device, variant) - url_base = BASE_URL.format(build_id=build_id, target=target) - filename = "{}-img-{}.zip".format(device, build_id) - url = os.path.join(url_base, filename) - dest_filename = os.path.join(dest_dir, filename) - return url, dest_filename - - -def update_prebuilt(build_id, boot_prebuilt, ver, arch, variant, bug): - device = "aosp_" + arch - arch_dir = os.path.join(boot_prebuilt, ver, arch) - variant_dir = os.path.join(arch_dir, variant) - boot_img_name = "boot-{}.img".format(ver) - stored_img_name = "boot-{}.img".format(variant) - try: - subprocess.check_call(["repo", "start", "boot-prebuilt-{}".format(build_id)], cwd=arch_dir) - - os.makedirs(variant_dir) - url, dest_filename = get_artifact_download_spec(build_id, device, variant, variant_dir) - download_file(url, dest_filename) - args = ["unzip", "-d", variant_dir, dest_filename, boot_img_name] - logger.info("Calling: %s", " ".join(args)) - subprocess.check_call(args) - shutil.move(os.path.join(variant_dir, boot_img_name), os.path.join(arch_dir, stored_img_name)) - - finally: - shutil.rmtree(variant_dir) - - message = """Update prebuilts to {build_id}. - -Test: Treehugger -Bug: {bug} -""".format(build_id=build_id, bug=bug or "N/A") - - logger.info("Creating commit for %s", arch_dir) - subprocess.check_call(["git", "add", "."], cwd=arch_dir) - subprocess.check_call(["git", "commit", "-m", message], cwd=arch_dir) - - -def main(): - args = parse_args() - with futures.ThreadPoolExecutor(max_workers=10) as pool: - fs = [] - boot_prebuilt = os.path.join(ANDROID_BUILD_TOP, BOOT_PREBUILT_REL_DIR) - for ver in os.listdir(boot_prebuilt): - if not re.match(r'\d+[.]\d+', ver): - continue - for arch in os.listdir(os.path.join(boot_prebuilt, ver)): - if arch not in SUPPORTED_ARCHS: - continue - for variant in VARIANTS: - fs.append((ver, arch, pool.submit(update_prebuilt, args.build_id, boot_prebuilt, ver, - arch, variant, args.bug))) - - futures.wait([f for ver, arch, f in fs]) - success_dirs = [] - logger.info("===============") - logger.info("Summary:") - for ver, arch, future in fs: - if future.exception(): - logger.error("%s/%s: %s", ver, arch, future.exception()) - else: - logger.info("%s/%s: Updated.", ver, arch) - success_dirs.append(os.path.join(BOOT_PREBUILT_REL_DIR, ver, arch)) - - if success_dirs: - args = ["repo", "upload", "--verify", "--hashtag-branch", "--br", - "boot-prebuilt-{}".format(args.build_id)] + success_dirs - logger.info(" ".join(args)) - subprocess.check_call(args, cwd=ANDROID_BUILD_TOP) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/extract_img_from_apex.py b/extract_img_from_apex.py deleted file mode 100644 index 12eb987..0000000 --- a/extract_img_from_apex.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2020 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. - -""" -Extract boot.img from a GKI APEX. - -Usage: extract_img_from_apex [--tool host_tool [--tool ...]] \ - input_gki.apex out_dir -""" - -import logging -import os -import sys - -import common - -APEX_PAYLOAD_FILE = "apex_payload.img" -APEX_PAYLOAD_BIN_PATH = "/etc/ota/payload.bin" - -logger = logging.getLogger(__name__) -OPTIONS = common.OPTIONS - - -def ExtractImagesFromApex(apex, out_dir): - if not os.path.isdir(out_dir): - os.makedirs(out_dir) - apex_dir = common.UnzipTemp(apex, [APEX_PAYLOAD_FILE]) - apex_payload = os.path.join(apex_dir, APEX_PAYLOAD_FILE) - - payload_bin = common.MakeTempFile("payload_", ".bin") - debugfs_command = ['debugfs', '-R', "dump {} {}".format( - APEX_PAYLOAD_BIN_PATH, payload_bin), apex_payload] - - common.RunAndCheckOutput(debugfs_command) - assert os.path.getsize(payload_bin) > 0, payload_bin + " is an empty file!" - - boot_img = os.path.join(out_dir, 'boot.img') - with open(boot_img, 'w') as _: - pass - - delta_generator_command = [ - 'delta_generator', - '--is_partial_update=true', - '--in_file=' + payload_bin, - '--partition_names=boot', - '--new_partitions=' + boot_img - ] - common.RunAndCheckOutput(delta_generator_command) - - -def main(argv): - def option_handler(o, a): - if o == "--tool": - name = os.path.basename(a) - common.SetHostToolLocation(name, a) - else: - return False - return True - - args = common.ParseOptions( - argv, __doc__, - extra_long_opts=["tool="], - extra_option_handler=option_handler) - - if len(args) != 2: - common.Usage(__doc__) - sys.exit(1) - - common.InitLogging() - - ExtractImagesFromApex(args[0], args[1]) - logger.info("done.") - - -if __name__ == '__main__': - try: - common.CloseInheritedPipes() - main(sys.argv[1:]) - except common.ExternalError: - logger.exception("\n ERROR:\n") - sys.exit(1) - finally: - common.Cleanup() diff --git a/ota_from_raw_image.py b/ota_from_raw_image.py deleted file mode 100644 index acd0697..0000000 --- a/ota_from_raw_image.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2020 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. - -""" -Generate payload.bin from a single image. -""" - -import argparse -import logging -import os -import re -import shutil -import sys -from zipfile import ZipFile - -import common -from ota_from_target_files import (Payload, PayloadSigner) - -logger = logging.getLogger(__name__) -OPTIONS = common.OPTIONS - - -def _ParseArgs(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--tools", metavar="PATH", type=str, nargs="*", - help="A list of real paths of tools that this script depends on.") - parser.add_argument("--key", type=str, - help="Key to use to sign the package. If unspecified, script does not sign " - "the package and payload_properties.txt is not generated.") - parser.add_argument("--out", type=str, required=True, - help="Required output directory to payload.bin and payload_properties.txt") - parser.add_argument("input", metavar="NAME:IMAGE", nargs="+", - help="Name of the image and path to the image, e.g. boot:path/to/boot.img") - args = parser.parse_args() - - return args - - -def _PrepareEnvironment(args): - common.InitLogging() - if not args.tools: - return - for path in args.tools: - name = os.path.basename(path) - # Use absolute path because GetBootImageTimestamp changes cwd when running some tools. - common.SetHostToolLocation(name, os.path.abspath(path)) - # brillo_update_payload is a shell script that depends on this environment variable. - if name == "delta_generator": - os.environ["GENERATOR"] = path - - -def CreateOtaFromRawImages(args): - _PrepareEnvironment(args) - - tf = common.MakeTempFile("target_files", ".zip") - payload_additional_args = ["--is_partial_update", "true"] - with ZipFile(tf, "w") as zip: - names = [] - for pair_str in args.input: - pair = pair_str.split(":") - assert len(pair) == 2, "Incorrect format: " + pair_str - name, img_path = tuple(pair) - zip.write(img_path, arcname=os.path.join("IMAGES", name + ".img")) - names.append(name) - if name == "boot": - timestamp = common.GetBootImageTimestamp(img_path) - assert timestamp is not None, "Cannot extract timestamp from boot image" - payload_additional_args += ["--partition_timestamps", - "boot:" + str(timestamp)] - - zip.writestr("META/ab_partitions.txt", "\n".join(names) + "\n") - zip.writestr("META/dynamic_partitions_info.txt", """ -virtual_ab=true -super_partition_groups= - """) - - payload = Payload() - payload.Generate(tf, None, payload_additional_args) - - if args.key: - OPTIONS.package_key = args.key - OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) - payload_signer = PayloadSigner() - payload.Sign(payload_signer) - - shutil.copy(payload.payload_file, os.path.join(args.out, "payload.bin")) - if payload.payload_properties: - shutil.copy(payload.payload_properties, os.path.join(args.out, "payload_properties.txt")) - - -if __name__ == "__main__": - try: - common.CloseInheritedPipes() - args = _ParseArgs() - CreateOtaFromRawImages(args) - except common.ExternalError: - logger.exception("\n ERROR:\n") - sys.exit(1) - finally: - common.Cleanup() diff --git a/preinstall.sh b/preinstall.sh deleted file mode 100644 index fbd16e1..0000000 --- a/preinstall.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/system/bin/sh - -# sleep_exit [<exit_code>] -function sleep_exit() { - # Sleep before exit to ensure logs flushes. - sleep 5s - exit $@ -} - -# log_gki <priority> <message> -function log_gki() { - log -t gki -p $@ -} - -log_gki i "GKI APEX preinstall hook starting." - -mydir=$(dirname $(dirname $(realpath "$0"))) -if [[ $(dirname $mydir) != "/apex" ]] || [[ $(basename $mydir) != com.android.gki.* ]]; then - log_gki e "This script must be installed under /apex/com.android.gki.*" - sleep_exit 1 -fi - -# The pre-installed APEX does not contain any OTA payload. Just skip installing anything. -if [[ ! -f ${mydir}/etc/ota/payload.bin ]]; then - log_gki e "No payload.bin found." - sleep_exit 1 -fi - -log_gki i "Applying payload."; - -if ! ${mydir}/bin/update_engine_stable_client \ - --payload ${mydir}/etc/ota/payload.bin \ - --headers "$(cat ${mydir}/etc/ota/payload_properties.txt)"; then - log_gki e "OTA failed" - sleep_exit 1 -fi - -log_gki i "OTA successful" -sleep_exit 0 diff --git a/test/Android.bp b/test/Android.bp deleted file mode 100644 index 483b6d9..0000000 --- a/test/Android.bp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2020 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. - -// A list of names of test APEXes for GkiInstallTest to instantiate test cases. -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -genrule { - name: "gki_install_test_file_list", - srcs: [":gki_install_test_files"], - out: ["gki_install_test_file_list.txt"], - cmd: "for file in $(in); do basename $${file} >> $(out); done", -} - -java_test_host { - name: "GkiInstallTest", - srcs: [ - "src/**/*.java", - ":gki_install_test_file_list", - ], - test_suites: [ - "device-tests", - ], - libs: [ - "compatibility-tradefed", - "tradefed", - ], - static_libs: [ - "cts-host-utils", - "hamcrest-library", - ], - data: [":gki_install_test_files"], - java_resources: [":gki_install_test_file_list"], -} - -// Prebuilts - -prebuilt_gki_apex { - name: "com.android.gki.kmi_5_4_android12_0_test_prebuilt", - installable: false, - kmi_version: "5.4-android12-0", - src: "com.android.gki.kmi_5_4_android12_0_test_prebuilt.apex", -} diff --git a/test/AndroidTest.xml b/test/AndroidTest.xml deleted file mode 100644 index 5eceeb2..0000000 --- a/test/AndroidTest.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2020 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. ---> - -<configuration description="GKI Install test"> - <test class="com.android.tradefed.testtype.HostTest" > - <option name="jar" value="GkiInstallTest.jar" /> - </test> -</configuration> diff --git a/test/com.android.gki.kmi_5_4_android12_0_test_prebuilt.apex b/test/com.android.gki.kmi_5_4_android12_0_test_prebuilt.apex Binary files differdeleted file mode 100644 index 1c01dd9..0000000 --- a/test/com.android.gki.kmi_5_4_android12_0_test_prebuilt.apex +++ /dev/null diff --git a/test/src/com/android/gki/tests/GkiInstallTest.java b/test/src/com/android/gki/tests/GkiInstallTest.java deleted file mode 100644 index 0b00ba6..0000000 --- a/test/src/com/android/gki/tests/GkiInstallTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2020 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.android.gki.tests; - -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.either; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.io.FileMatchers.aFileWithSize; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeThat; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeTrue; - -import static java.util.stream.Collectors.toList; - -import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters; -import android.cts.host.utils.DeviceJUnit4Parameterized; - -import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; -import com.android.tradefed.device.ITestDevice; -import com.android.tradefed.device.ITestDevice.ApexInfo; -import com.android.tradefed.log.LogUtil.CLog; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; -import org.junit.runners.Parameterized.UseParametersRunnerFactory; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.io.File; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.Scanner; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@RunWith(DeviceJUnit4Parameterized.class) -@UseParametersRunnerFactory(DeviceJUnit4ClassRunnerWithParameters.RunnerFactory.class) -public class GkiInstallTest extends BaseHostJUnit4Test { - - // Keep in sync with gki.go. - private static final String HIGH_SUFFIX = "_test_high.apex"; - private static final String LOW_SUFFIX = "_test_low.apex"; - private static final long TEST_HIGH_VERSION = 1000000000L; - - // Timeout between device online for adb commands and boot completed flag is set. - private static final long DEVICE_AVAIL_TIMEOUT_MS = 180000; // 3mins - // Timeout for `adb install`. - private static final long INSTALL_TIMEOUT_MS = 600000; // 10mins - - @Parameter - public String mFileName; - - private String mPackageName; - private File mApexFile; - private boolean mExpectInstallSuccess; - private final Set<String> mOverlayfs = new HashSet(); - - @Parameters(name = "{0}") - public static Iterable<String> getTestFileNames() { - try (Scanner scanner = new Scanner( - GkiInstallTest.class.getClassLoader().getResourceAsStream( - "gki_install_test_file_list.txt"))) { - List<String> list = new ArrayList<>(); - scanner.forEachRemaining(list::add); - return list; - } - } - - @Before - public void setUp() throws Exception { - inferPackageName(); - skipTestIfPackageNotInstalled(); - skipTestIfWrongKernelVersion(); - findTestApexFile(); - prepareOverlayfs(); - } - - /** Set mPackageName and mExpectInstallSuccess according to mFileName. */ - private void inferPackageName() throws Exception { - if (mFileName.endsWith(HIGH_SUFFIX)) { - mPackageName = mFileName.substring(0, mFileName.length() - HIGH_SUFFIX.length()); - mExpectInstallSuccess = true; - } else if (mFileName.endsWith(LOW_SUFFIX)) { - mPackageName = mFileName.substring(0, mFileName.length() - LOW_SUFFIX.length()); - mExpectInstallSuccess = false; - } else { - fail("Unrecognized test data file: " + mFileName); - } - } - - /** Skip the test if mPackageName is not installed on the device. */ - private void skipTestIfPackageNotInstalled() throws Exception { - CLog.i("Wait for device to be available for %d ms...", DEVICE_AVAIL_TIMEOUT_MS); - getDevice().waitForDeviceAvailable(DEVICE_AVAIL_TIMEOUT_MS); - CLog.i("Device is available after %d ms", DEVICE_AVAIL_TIMEOUT_MS); - - // Skip if the device does not support this APEX package. - CLog.i("Checking if %s is installed on the device.", mPackageName); - ApexInfo oldApexInfo = getApexInfo(getDevice(), mPackageName); - assumeThat(oldApexInfo, is(notNullValue())); - assumeThat(oldApexInfo.name, is(mPackageName)); - } - - /** - * Skip the test if APEX package name does not match kernel version. - * - * Due to b/186566367, on mixed builds, the wrong GKI APEX may be installed. In that case, just - * skip the test. - * - * As an exception, the package may contain "unstable" as the generation. When this is the - * case, any generation number in kernel release is considered a match. - * - * @throws Exception - */ - private void skipTestIfWrongKernelVersion() throws Exception { - Pattern packagePattern = Pattern.compile( - "^com\\.android\\.gki\\.kmi_(?<w>\\d+)_(?<x>\\d+)_(?<z>android\\d+)_" + - "(?<k>\\d+|unstable)$"); - Matcher packageMatcher = packagePattern.matcher(mPackageName); - assertTrue(packageMatcher.matches()); - - Pattern kernelPattern = Pattern.compile( - "^Linux version (?<fullrel>(?<w>\\d+)\\.(?<x>\\d+)\\.(?<y>\\d+)-(?<z>android\\d+)" - + "-(?<k>\\d+))"); - String kernel = getDevice().executeShellCommand("cat /proc/version"); - Matcher kernelMatcher = kernelPattern.matcher(kernel); - assumeTrue("Not GKI: " + kernel, kernelMatcher.find()); - - String desc = String.format("package %s vs kernel release %s", mPackageName, - kernelMatcher.group("fullrel")); - - CLog.i("Checking: %s", desc); - - assumeThat(desc, packageMatcher.group("w"), is(kernelMatcher.group("w"))); - assumeThat(desc, packageMatcher.group("x"), is(kernelMatcher.group("x"))); - assumeThat(desc, packageMatcher.group("z"), is(kernelMatcher.group("z"))); - assumeThat(desc, packageMatcher.group("k"), - anyOf(is("unstable"), is(kernelMatcher.group("k")))); - } - - /** Find the corresponding APEX test file with mFileName. */ - private void findTestApexFile() throws Exception { - // Find the APEX file. - CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); - mApexFile = buildHelper.getTestFile(mFileName); - - // There may be empty .apex files in the directory for disabled APEXes. But if the device - // is known to install the package, the test must be built with non-empty APEXes for this - // particular package. - assertThat("Test is not built properly. It does not contain a non-empty " + mFileName, - mApexFile, is(aFileWithSize(greaterThan(0L)))); - } - - /** - * Record what partitions have overlayfs set up. Then, tear down overlayfs because it may - * make OTA fail. - * - * Usually, the test does not require root to run, but if the device has overlayfs set up, - * the test assumes that the device has root functionality, and attempts to tear down - * overlayfs before the test starts. - * Note that this function immediately reboots after enabling adb root to ensure the test runs - * with the same permission before it is called. - */ - private void prepareOverlayfs() throws Exception { - mOverlayfs.addAll(getOverlayfsState(getDevice())); - - if (!mOverlayfs.isEmpty()) { - getDevice().enableAdbRoot(); - getDevice().executeAdbCommand("enable-verity"); - rebootUntilAvailable(getDevice(), DEVICE_AVAIL_TIMEOUT_MS); - } - } - - @Test - public void testInstallAndReboot() throws Exception { - CLog.i("Installing %s with %d ms timeout", mApexFile, INSTALL_TIMEOUT_MS); - String result = getDevice().installPackage(mApexFile, false, - "--staged-ready-timeout", String.valueOf(INSTALL_TIMEOUT_MS)); - if (!mExpectInstallSuccess) { - assertNotNull("Should not be able to install downgrade package", result); - assertThat(result, either(containsString("Downgrade of APEX package " + mPackageName - + " is not allowed.")).or(containsString("INSTALL_FAILED_VERSION_DOWNGRADE"))); - return; - } - - assertNull("Installation failed with " + result, result); - rebootUntilAvailable(getDevice(), DEVICE_AVAIL_TIMEOUT_MS); - - ApexInfo newApexInfo = getApexInfo(getDevice(), mPackageName); - assertNotNull(newApexInfo); - assertThat(newApexInfo.versionCode, is(TEST_HIGH_VERSION)); - } - - /** - * Restore overlayfs on partitions. - * - * Usually, tearDown() does not require root to run, but if the device had overlayfs set up - * before the test has started, - * the test assumes that the device has root functionality, and attempts to re-set up - * overlayfs after the test ends. - * Note that tearDown() immediately reboots after enabling adb root to ensure the test ends up - * with the same permission before the test has started. - */ - @After - public void tearDown() throws Exception { - // Restore overlayfs for partitions that the test knows of. - CLog.i("Test ends, now restoring overlayfs partitions %s.", mOverlayfs); - if (mOverlayfs.contains("system")) { - getDevice().enableAdbRoot(); - getDevice().remountSystemWritable(); - } - if (mOverlayfs.contains("vendor")) { - getDevice().enableAdbRoot(); - getDevice().remountVendorWritable(); - } - CLog.i("Restoring overlayfs partition ends, now rebooting."); - - // Reboot device no matter what to avoid interference. - rebootUntilAvailable(getDevice(), DEVICE_AVAIL_TIMEOUT_MS); - - // remount*Writable should have enabled overlayfs for all necessary partitions. If not, - // throw an error. - Set<String> newOverlayfsState = getOverlayfsState(getDevice()); - assertThat("Some partitions did not restore overlayfs properly. Before test: " + mOverlayfs - + ", after test: " + newOverlayfsState, mOverlayfs, - everyItem(isIn(newOverlayfsState))); - CLog.i("All overlayfs states are restored."); - } - - /** - * @param device the device under test - * @param packageName the package name to look for - * @return The {@link ApexInfo} of the APEX named {@code packageName} on the - * {@code device}, or {@code null} if the device does not have the APEX installed. - * @throws Exception an error has occurred. - */ - private static ApexInfo getApexInfo(ITestDevice device, String packageName) - throws Exception { - assertNotNull(packageName); - List<ApexInfo> list = device.getActiveApexes().stream().filter( - apexInfo -> packageName.equals(apexInfo.name)).collect(toList()); - if (list.isEmpty()) return null; - assertThat(list.size(), is(1)); - return list.get(0); - } - - /** - * Similar to device.reboot(), but with a timeout on waitForDeviceAvailable. Note that - * the timeout does not include the rebootUntilOnline() call. - * - * @param device the device under test - * @param timeoutMs timeout for waitForDeviceAvailable() call - * @throws Exception an error has occurred. - */ - private static void rebootUntilAvailable(ITestDevice device, long timeoutMs) - throws Exception { - CLog.i("Reboot and waiting for device to be online"); - device.rebootUntilOnline(); - CLog.i("Device online, wait for device to be available for %d ms...", timeoutMs); - device.waitForDeviceAvailable(timeoutMs); - CLog.i("Device is available after %d ms", timeoutMs); - } - - /** - * Get all partitions that have overlayfs setup. Parse /proc/mounts and if it finds lines like: - * {@code overlayfs /vendor ...}, then put {@code vendor} in the returned set. - * @param device the device under test - * @return a list of partitions like {@code system}, {@code vendor} that has overlayfs set up - * @throws Exception an error has occurred. - */ - private static Set<String> getOverlayfsState(ITestDevice device) throws Exception { - Set<String> ret = new HashSet(); - File mounts = device.pullFile("/proc/mounts"); - try (Scanner scanner = new Scanner(mounts)) { - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - String[] tokens = line.split("\\s"); - if (tokens.length < 2) continue; - if (!"overlay".equals(tokens[0])) continue; - Path path = Paths.get(tokens[1]); - if (path.getNameCount() == 0) continue; - ret.add(path.getName(0).toString()); - } - } - CLog.i("Device has overlayfs set up on partitions %s", ret); - return ret; - } -} |