diff options
26 files changed, 1054 insertions, 107 deletions
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp index 65ec4d46a27c..3e277e8a0cab 100644 --- a/api/StubLibraries.bp +++ b/api/StubLibraries.bp @@ -54,34 +54,34 @@ non_updatable_exportable_droidstubs { baseline_file: ":non-updatable-lint-baseline.txt", }, }, - dists: [ - { - targets: ["sdk"], - dir: "apistubs/android/public/api", - dest: "android-non-updatable.txt", - }, - { - targets: ["sdk"], - dir: "apistubs/android/public/api", - dest: "android-non-updatable-removed.txt", - }, - ], soong_config_variables: { release_hidden_api_exportable_stubs: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/public/api", + dest: "android-non-updatable.txt", tag: ".exportable.api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/public/api", + dest: "android-non-updatable-removed.txt", tag: ".exportable.removed-api.txt", }, ], conditions_default: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/public/api", + dest: "android-non-updatable.txt", tag: ".api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/public/api", + dest: "android-non-updatable-removed.txt", tag: ".removed-api.txt", }, ], @@ -134,34 +134,34 @@ non_updatable_exportable_droidstubs { baseline_file: ":non-updatable-system-lint-baseline.txt", }, }, - dists: [ - { - targets: ["sdk"], - dir: "apistubs/android/system/api", - dest: "android-non-updatable.txt", - }, - { - targets: ["sdk"], - dir: "apistubs/android/system/api", - dest: "android-non-updatable-removed.txt", - }, - ], soong_config_variables: { release_hidden_api_exportable_stubs: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/system/api", + dest: "android-non-updatable.txt", tag: ".exportable.api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/system/api", + dest: "android-non-updatable-removed.txt", tag: ".exportable.removed-api.txt", }, ], conditions_default: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/system/api", + dest: "android-non-updatable.txt", tag: ".api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/system/api", + dest: "android-non-updatable-removed.txt", tag: ".removed-api.txt", }, ], @@ -189,56 +189,58 @@ non_updatable_exportable_droidstubs { baseline_file: ":non-updatable-test-lint-baseline.txt", }, }, - dists: [ - { - targets: ["sdk"], - dir: "apistubs/android/test/api", - dest: "android.txt", - }, - { - targets: ["sdk"], - dir: "apistubs/android/test/api", - dest: "removed.txt", - }, - { - targets: ["sdk"], - dir: "apistubs/android/test/api", - dest: "android-non-updatable.txt", - }, - { - targets: ["sdk"], - dir: "apistubs/android/test/api", - dest: "android-non-updatable-removed.txt", - }, - ], soong_config_variables: { release_hidden_api_exportable_stubs: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "android.txt", tag: ".exportable.api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "removed.txt", tag: ".exportable.removed-api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "android-non-updatable.txt", tag: ".exportable.api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "android-non-updatable-removed.txt", tag: ".exportable.removed-api.txt", }, ], conditions_default: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "android.txt", tag: ".api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "removed.txt", tag: ".removed-api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "android-non-updatable.txt", tag: ".api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/test/api", + dest: "android-non-updatable-removed.txt", tag: ".removed-api.txt", }, ], @@ -271,34 +273,34 @@ non_updatable_exportable_droidstubs { baseline_file: ":non-updatable-module-lib-lint-baseline.txt", }, }, - dists: [ - { - targets: ["sdk"], - dir: "apistubs/android/module-lib/api", - dest: "android-non-updatable.txt", - }, - { - targets: ["sdk"], - dir: "apistubs/android/module-lib/api", - dest: "android-non-updatable-removed.txt", - }, - ], soong_config_variables: { release_hidden_api_exportable_stubs: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android-non-updatable.txt", tag: ".exportable.api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android-non-updatable-removed.txt", tag: ".exportable.removed-api.txt", }, ], conditions_default: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android-non-updatable.txt", tag: ".api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android-non-updatable-removed.txt", tag: ".removed-api.txt", }, ], diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt index 5178f09f0301..5efda98a1518 100644 --- a/api/coverage/tools/ExtractFlaggedApis.kt +++ b/api/coverage/tools/ExtractFlaggedApis.kt @@ -17,6 +17,7 @@ package android.platform.coverage import com.android.tools.metalava.model.ClassItem +import com.android.tools.metalava.model.Item import com.android.tools.metalava.model.MethodItem import com.android.tools.metalava.model.text.ApiFile import java.io.File @@ -44,20 +45,9 @@ fun extractFlaggedApisFromClass( builder: FlagApiMap.Builder ) { if (methods.isEmpty()) return - val classFlag = - classItem.modifiers - .findAnnotation("android.annotation.FlaggedApi") - ?.findAttribute("value") - ?.value - ?.value() as? String + val classFlag = getClassFlag(classItem) for (method in methods) { - val methodFlag = - method.modifiers - .findAnnotation("android.annotation.FlaggedApi") - ?.findAttribute("value") - ?.value - ?.value() as? String - ?: classFlag + val methodFlag = getFlagAnnotation(method) ?: classFlag val api = JavaMethod.newBuilder() .setPackageName(packageName) @@ -81,3 +71,23 @@ fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: St builder.putFlagToApi(flag, apis) } } + +fun getClassFlag(classItem: ClassItem): String? { + var classFlag = getFlagAnnotation(classItem) + var cur = classItem + // If a class is not an inner class, use its @FlaggedApi annotation value. + // Otherwise, use the flag value of the closest outer class that is annotated by @FlaggedApi. + while (cur.isInnerClass() && classFlag == null) { + cur = cur.parent() as ClassItem + classFlag = getFlagAnnotation(cur) + } + return classFlag +} + +fun getFlagAnnotation(item: Item): String? { + return item.modifiers + .findAnnotation("android.annotation.FlaggedApi") + ?.findAttribute("value") + ?.value + ?.value() as? String +} diff --git a/api/coverage/tools/ExtractFlaggedApisTest.kt b/api/coverage/tools/ExtractFlaggedApisTest.kt index ee5aaf15cb57..427be36254d3 100644 --- a/api/coverage/tools/ExtractFlaggedApisTest.kt +++ b/api/coverage/tools/ExtractFlaggedApisTest.kt @@ -141,6 +141,84 @@ class ExtractFlaggedApisTest { assertThat(result).isEqualTo(expected.build()) } + @Test + fun extractFlaggedApis_unflaggedNestedClassShouldUseOuterClassFlag() { + val apiText = + """ + // Signature format: 2.0 + package android.location.provider { + @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public final class ForwardGeocodeRequest implements android.os.Parcelable { + method public int describeContents(); + } + public static final class ForwardGeocodeRequest.Builder { + method @NonNull public android.location.provider.ForwardGeocodeRequest build(); + } + } + """ + .trimIndent() + Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND) + + val process = Runtime.getRuntime().exec(createCommand()) + process.waitFor() + + val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8) + val result = TextFormat.parse(content, FlagApiMap::class.java) + + val expected = FlagApiMap.newBuilder() + val api1 = + JavaMethod.newBuilder() + .setPackageName("android.location.provider") + .setClassName("ForwardGeocodeRequest") + .setMethodName("describeContents") + addFlaggedApi(expected, api1, "Flags.FLAG_NEW_GEOCODER") + val api2 = + JavaMethod.newBuilder() + .setPackageName("android.location.provider") + .setClassName("ForwardGeocodeRequest.Builder") + .setMethodName("build") + addFlaggedApi(expected, api2, "Flags.FLAG_NEW_GEOCODER") + assertThat(result).ignoringRepeatedFieldOrder().isEqualTo(expected.build()) + } + + @Test + fun extractFlaggedApis_unflaggedNestedClassShouldUseOuterClassFlag_deeplyNested() { + val apiText = + """ + // Signature format: 2.0 + package android.package.xyz { + @FlaggedApi(outer_class_flag) public final class OuterClass { + method public int apiInOuterClass(); + } + public final class OuterClass.Deeply.NestedClass { + method public void apiInNestedClass(); + } + } + """ + .trimIndent() + Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND) + + val process = Runtime.getRuntime().exec(createCommand()) + process.waitFor() + + val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8) + val result = TextFormat.parse(content, FlagApiMap::class.java) + + val expected = FlagApiMap.newBuilder() + val api1 = + JavaMethod.newBuilder() + .setPackageName("android.package.xyz") + .setClassName("OuterClass") + .setMethodName("apiInOuterClass") + addFlaggedApi(expected, api1, "outer_class_flag") + val api2 = + JavaMethod.newBuilder() + .setPackageName("android.package.xyz") + .setClassName("OuterClass.Deeply.NestedClass") + .setMethodName("apiInNestedClass") + addFlaggedApi(expected, api2, "outer_class_flag") + assertThat(result).ignoringRepeatedFieldOrder().isEqualTo(expected.build()) + } + private fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) { if (builder.containsFlagToApi(flag)) { val updatedApis = diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java index a51a74075298..d9a18d785537 100644 --- a/core/java/android/ddm/DdmHandleHello.java +++ b/core/java/android/ddm/DdmHandleHello.java @@ -42,12 +42,6 @@ public class DdmHandleHello extends DdmHandle { private static DdmHandleHello mInstance = new DdmHandleHello(); - private static final String[] FRAMEWORK_FEATURES = new String[] { - "opengl-tracing", - "view-hierarchy", - "support_boot_stages" - }; - /* singleton, do not instantiate */ private DdmHandleHello() {} @@ -193,22 +187,25 @@ public class DdmHandleHello extends DdmHandle { if (false) Log.v("ddm-heap", "Got feature list request"); - int size = 4 + 4 * (vmFeatures.length + FRAMEWORK_FEATURES.length); - for (int i = vmFeatures.length-1; i >= 0; i--) + String[] fmFeatures = Debug.getFeatureList(); + int size = 4 + 4 * (vmFeatures.length + fmFeatures.length); + for (int i = vmFeatures.length - 1; i >= 0; i--) { size += vmFeatures[i].length() * 2; - for (int i = FRAMEWORK_FEATURES.length-1; i>= 0; i--) - size += FRAMEWORK_FEATURES[i].length() * 2; + } + for (int i = fmFeatures.length - 1; i >= 0; i--) { + size += fmFeatures[i].length() * 2; + } ByteBuffer out = ByteBuffer.allocate(size); out.order(ChunkHandler.CHUNK_ORDER); - out.putInt(vmFeatures.length + FRAMEWORK_FEATURES.length); + out.putInt(vmFeatures.length + fmFeatures.length); for (int i = vmFeatures.length-1; i >= 0; i--) { out.putInt(vmFeatures[i].length()); putString(out, vmFeatures[i]); } - for (int i = FRAMEWORK_FEATURES.length-1; i >= 0; i--) { - out.putInt(FRAMEWORK_FEATURES[i].length()); - putString(out, FRAMEWORK_FEATURES[i]); + for (int i = fmFeatures.length - 1; i >= 0; i--) { + out.putInt(fmFeatures[i].length()); + putString(out, fmFeatures[i]); } return new Chunk(CHUNK_FEAT, out); diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index f785cca4e9f4..a55398ac9752 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -110,6 +110,12 @@ public final class Debug private static final String DEFAULT_TRACE_BODY = "dmtrace"; private static final String DEFAULT_TRACE_EXTENSION = ".trace"; + private static final String[] FRAMEWORK_FEATURES = new String[] { + "opengl-tracing", + "view-hierarchy", + "support_boot_stages", + }; + /** * This class is used to retrieved various statistics about the memory mappings for this * process. The returned info is broken down by dalvik, native, and other. All results are in kB. @@ -1106,6 +1112,17 @@ public final class Debug } /** + * Returns an array of strings that identify Framework features. This is + * used by DDMS to determine what sorts of operations the Framework can + * perform. + * + * @hide + */ + public static String[] getFeatureList() { + return FRAMEWORK_FEATURES; + } + + /** * Change the JDWP port. * * @deprecated no longer needed or useful diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 8c6bf79d9731..6412ddb3f6a7 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -21,6 +21,7 @@ soong_config_module_type { config_namespace: "ANDROID", bool_variables: [ "release_binder_death_recipient_weak_from_jni", + "release_package_libandroid_runtime_punch_holes", ], properties: [ "cflags", @@ -63,6 +64,9 @@ cc_library_shared_for_libandroid_runtime { release_binder_death_recipient_weak_from_jni: { cflags: ["-DBINDER_DEATH_RECIPIENT_WEAK_FROM_JNI"], }, + release_package_libandroid_runtime_punch_holes: { + cflags: ["-DENABLE_PUNCH_HOLES"], + }, }, cpp_std: "gnu++20", @@ -120,6 +124,7 @@ cc_library_shared_for_libandroid_runtime { srcs: [ "AndroidRuntime.cpp", "com_android_internal_content_F2fsUtils.cpp", + "com_android_internal_content_FileSystemUtils.cpp", "com_android_internal_content_NativeLibraryHelper.cpp", "com_google_android_gles_jni_EGLImpl.cpp", "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp new file mode 100644 index 000000000000..4bd2d72a1eb4 --- /dev/null +++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2024 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. + */ + +#define LOG_TAG "FileSystemUtils" + +#include "com_android_internal_content_FileSystemUtils.h" + +#include <android-base/file.h> +#include <android-base/hex.h> +#include <android-base/unique_fd.h> +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <linux/fs.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <utils/Log.h> + +#include <array> +#include <fstream> +#include <vector> + +using android::base::HexString; +using android::base::ReadFullyAtOffset; + +namespace android { +bool punchHoles(const char *filePath, const uint64_t offset, + const std::vector<Elf64_Phdr> &programHeaders) { + struct stat64 beforePunch; + lstat64(filePath, &beforePunch); + uint64_t blockSize = beforePunch.st_blksize; + IF_ALOGD() { + ALOGD("Total number of LOAD segments %zu", programHeaders.size()); + + ALOGD("Size before punching holes st_blocks: %" PRIu64 + ", st_blksize: %ld, st_size: %" PRIu64 "", + beforePunch.st_blocks, beforePunch.st_blksize, + static_cast<uint64_t>(beforePunch.st_size)); + } + + android::base::unique_fd fd(open(filePath, O_RDWR | O_CLOEXEC)); + if (!fd.ok()) { + ALOGE("Can't open file to punch %s", filePath); + return false; + } + + // read in chunks of 64KB + constexpr uint64_t kChunkSize = 64 * 1024; + + // malloc is used to gracefully handle oom which might occur during the allocation of buffer. + // allocating using new or vector here results in oom/exception on failure where as malloc will + // return nullptr. + std::unique_ptr<uint8_t, decltype(&free)> buffer(static_cast<uint8_t *>(malloc(kChunkSize)), + &free); + if (buffer == nullptr) { + ALOGE("Failed to allocate read buffer"); + return false; + } + + for (size_t index = 0; programHeaders.size() >= 2 && index < programHeaders.size() - 1; + index++) { + // find LOAD segments from program headers, calculate padding and punch holes + uint64_t punchOffset; + if (__builtin_add_overflow(programHeaders[index].p_offset, programHeaders[index].p_filesz, + &punchOffset)) { + ALOGE("Overflow occurred when adding offset and filesize"); + return false; + } + + uint64_t punchLen; + if (__builtin_sub_overflow(programHeaders[index + 1].p_offset, punchOffset, &punchLen)) { + ALOGE("Overflow occurred when calculating length"); + return false; + } + + if (punchLen < blockSize) { + continue; + } + + uint64_t punchStartOffset; + if (__builtin_add_overflow(offset, punchOffset, &punchStartOffset)) { + ALOGE("Overflow occurred when calculating length"); + return false; + } + + uint64_t position = punchStartOffset; + uint64_t endPosition; + if (__builtin_add_overflow(position, punchLen, &endPosition)) { + ALOGE("Overflow occurred when calculating length"); + return false; + } + + // Read content in kChunkSize and verify it is zero + while (position <= endPosition) { + uint64_t uncheckedChunkEnd; + if (__builtin_add_overflow(position, kChunkSize, &uncheckedChunkEnd)) { + ALOGE("Overflow occurred when calculating uncheckedChunkEnd"); + return false; + } + + uint64_t readLength; + if (__builtin_sub_overflow(std::min(uncheckedChunkEnd, endPosition), position, + &readLength)) { + ALOGE("Overflow occurred when calculating readLength"); + return false; + } + + if (!ReadFullyAtOffset(fd, buffer.get(), readLength, position)) { + ALOGE("Failed to read content to punch holes"); + return false; + } + + IF_ALOGD() { + ALOGD("Punching holes for length:%" PRIu64 " content which should be zero: %s", + readLength, HexString(buffer.get(), readLength).c_str()); + } + + bool isZero = std::all_of(buffer.get(), buffer.get() + readLength, + [](uint8_t i) constexpr { return i == 0; }); + if (!isZero) { + ALOGE("Found non zero content while trying to punch hole. Skipping operation"); + return false; + } + + position = uncheckedChunkEnd; + } + + // if we have a uncompressed file which is being opened from APK, use the offset to + // punch native lib inside Apk. + int result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, punchStartOffset, + punchLen); + if (result < 0) { + ALOGE("fallocate failed to punch hole, error:%d", errno); + return false; + } + } + + IF_ALOGD() { + struct stat64 afterPunch; + lstat64(filePath, &afterPunch); + ALOGD("Size after punching holes st_blocks: %" PRIu64 ", st_blksize: %ld, st_size: %" PRIu64 + "", + afterPunch.st_blocks, afterPunch.st_blksize, + static_cast<uint64_t>(afterPunch.st_size)); + } + + return true; +} + +bool punchHolesInElf64(const char *filePath, const uint64_t offset) { + // Open Elf file + Elf64_Ehdr ehdr; + std::ifstream inputStream(filePath, std::ifstream::in); + + // If this is a zip file, set the offset so that we can read elf file directly + inputStream.seekg(offset); + // read executable headers + inputStream.read((char *)&ehdr, sizeof(ehdr)); + if (!inputStream.good()) { + return false; + } + + // only consider elf64 for punching holes + if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) { + ALOGE("Provided file is not ELF64"); + return false; + } + + // read the program headers from elf file + uint64_t programHeaderOffset = ehdr.e_phoff; + uint16_t programHeaderNum = ehdr.e_phnum; + + IF_ALOGD() { + ALOGD("Punching holes in file: %s programHeaderOffset: %" PRIu64 " programHeaderNum: %hu", + filePath, programHeaderOffset, programHeaderNum); + } + + // if this is a zip file, also consider elf offset inside a file + uint64_t phOffset; + if (__builtin_add_overflow(offset, programHeaderOffset, &phOffset)) { + ALOGE("Overflow occurred when calculating phOffset"); + return false; + } + inputStream.seekg(phOffset); + + std::vector<Elf64_Phdr> programHeaders; + for (int headerIndex = 0; headerIndex < programHeaderNum; headerIndex++) { + Elf64_Phdr header; + inputStream.read((char *)&header, sizeof(header)); + if (!inputStream.good()) { + return false; + } + + if (header.p_type != PT_LOAD) { + continue; + } + programHeaders.push_back(header); + } + + return punchHoles(filePath, offset, programHeaders); +} + +}; // namespace android diff --git a/core/jni/com_android_internal_content_FileSystemUtils.h b/core/jni/com_android_internal_content_FileSystemUtils.h new file mode 100644 index 000000000000..a6b145c690d1 --- /dev/null +++ b/core/jni/com_android_internal_content_FileSystemUtils.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 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. + */ +#pragma once + +#include <sys/types.h> + +namespace android { + +/* + * This function deallocates space used by zero padding at the end of LOAD segments in given + * uncompressed ELF file. Read ELF headers and find out the offset and sizes of LOAD segments. + * [fallocate(2)](http://man7.org/linux/man-pages/man2/fallocate.2.html) is used to deallocate the + * zero ranges at the end of LOAD segments. If ELF file is present inside of ApK/Zip file, offset to + * the start of the ELF file should be provided. + */ +bool punchHolesInElf64(const char* filePath, uint64_t offset); + +} // namespace android
\ No newline at end of file diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 149e57a6f5e1..faa83f8017f7 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -36,6 +36,7 @@ #include <memory> +#include "com_android_internal_content_FileSystemUtils.h" #include "core_jni_helpers.h" #define RS_BITCODE_SUFFIX ".bc" @@ -169,6 +170,15 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr return INSTALL_FAILED_INVALID_APK; } +#ifdef ENABLE_PUNCH_HOLES + // if library is uncompressed, punch hole in it in place + if (!punchHolesInElf64(zipFile->getZipFileName(), offset)) { + ALOGW("Failed to punch uncompressed elf file :%s inside apk : %s at offset: " + "%" PRIu64 "", + fileName, zipFile->getZipFileName(), offset); + } +#endif // ENABLE_PUNCH_HOLES + return INSTALL_SUCCEEDED; } diff --git a/core/tests/FileSystemUtilsTest/Android.bp b/core/tests/FileSystemUtilsTest/Android.bp new file mode 100644 index 000000000000..53c22df67b85 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/Android.bp @@ -0,0 +1,78 @@ +// Copyright (C) 2024 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: ["frameworks_base_license"], + default_team: "trendy_team_android_kernel", +} + +cc_library { + name: "libpunchtest", + stl: "none", + host_supported: true, + srcs: ["jni/android_test_jni_source.cpp"], + header_libs: ["jni_headers"], +} + +android_test_helper_app { + name: "embedded_native_libs_test_app", + srcs: ["apk_embedded_native_libs/src/**/*.java"], + manifest: "apk_embedded_native_libs/embedded_native_libs_test_app.xml", + compile_multilib: "64", + jni_libs: [ + "libpunchtest", + ], + static_libs: [ + "androidx.test.rules", + "platform-test-annotations", + ], + use_embedded_native_libs: true, +} + +android_test_helper_app { + name: "extract_native_libs_test_app", + srcs: ["apk_extract_native_libs/src/**/*.java"], + manifest: "apk_extract_native_libs/extract_native_libs_test_app.xml", + compile_multilib: "64", + jni_libs: [ + "libpunchtest", + ], + static_libs: [ + "androidx.test.rules", + "platform-test-annotations", + ], + use_embedded_native_libs: false, +} + +java_test_host { + name: "FileSystemUtilsTests", + // Include all test java files + srcs: ["src/**/*.java"], + static_libs: [ + "junit", + "platform-test-annotations", + "truth", + ], + libs: [ + "tradefed", + "compatibility-host-util", + "compatibility-tradefed", + ], + data: [ + ":embedded_native_libs_test_app", + ":extract_native_libs_test_app", + ], + test_suites: ["general-tests"], + test_config: "AndroidTest.xml", +} diff --git a/core/tests/FileSystemUtilsTest/AndroidManifest.xml b/core/tests/FileSystemUtilsTest/AndroidManifest.xml new file mode 100644 index 000000000000..acd5ef3c90c2 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + android:installLocation="internalOnly" + package="com.android.internal.content.fstests"> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.internal.content.fstests" + android:label="Frameworks FileSystemUtils Tests" /> + +</manifest> diff --git a/core/tests/FileSystemUtilsTest/AndroidTest.xml b/core/tests/FileSystemUtilsTest/AndroidTest.xml new file mode 100644 index 000000000000..27f49b2289ba --- /dev/null +++ b/core/tests/FileSystemUtilsTest/AndroidTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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="Runs FileSystemUtilsTest."> + <option name="test-suite-tag" value="apct"/> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="embedded_native_libs_test_app.apk" /> + <option name="test-file-name" value="extract_native_libs_test_app.apk" /> + </target_preparer> + + <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > + <option name="jar" value="FileSystemUtilsTests.jar" /> + </test> +</configuration> diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml new file mode 100644 index 000000000000..868f7f3b7799 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.embedded"> + <application android:extractNativeLibs="false"> + <uses-library android:name="android.test.runner"/> + <activity android:name=".MainActivity" + android:exported="true" + android:process=":NewProcess"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + </application> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.embedded"/> +</manifest>
\ No newline at end of file diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java new file mode 100644 index 000000000000..efa2a39881dc --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 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 android.test.embedded; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import androidx.annotation.VisibleForTesting; + +public class MainActivity extends Activity { + + static { + System.loadLibrary("punchtest"); + } + + @VisibleForTesting + static final String INTENT_TYPE = "android.test.embedded.EMBEDDED_LIB_LOADED"; + + @VisibleForTesting + static final String KEY_OPERAND_1 = "OP1"; + + @VisibleForTesting + static final String KEY_OPERAND_2 = "OP2"; + + @VisibleForTesting + static final String KEY_RESULT = "RESULT"; + + @Override + public void onCreate(Bundle savedOnstanceState) { + super.onCreate(savedOnstanceState); + + Intent received = getIntent(); + int op1 = received.getIntExtra(KEY_OPERAND_1, -1); + int op2 = received.getIntExtra(KEY_OPERAND_2, -1); + int result = add(op1, op2); + + // Send broadcast so that test can know app has launched and lib is loaded + // attach result which has been fetched from JNI lib + Intent intent = new Intent(INTENT_TYPE); + intent.putExtra(KEY_RESULT, result); + sendBroadcast(intent); + } + + private native int add(int op1, int op2); +} diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java new file mode 100644 index 000000000000..d7d67b888490 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 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 android.test.embedded; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class PunchEmbeddedLibTest { + + @Test + public void testPunchedNativeLibs_embeddedLib() throws Exception { + Context context = InstrumentationRegistry.getContext(); + CountDownLatch receivedSignal = new CountDownLatch(1); + + // Test app is expected to receive this and perform addition of operands using punched lib + int op1 = 48; + int op2 = 75; + IntentFilter intentFilter = new IntentFilter(MainActivity.INTENT_TYPE); + BroadcastReceiver broadcastReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + receivedSignal.countDown(); + int result = intent.getIntExtra(MainActivity.KEY_RESULT, 1000); + Assert.assertEquals(result, op1 + op2); + + } + }; + context.registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED); + + Intent launchIntent = + context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); + launchIntent.putExtra(MainActivity.KEY_OPERAND_1, op1); + launchIntent.putExtra(MainActivity.KEY_OPERAND_2, op2); + context.startActivity(launchIntent); + + Assert.assertTrue("Failed to launch app", receivedSignal.await(10, TimeUnit.SECONDS)); + } +} diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml new file mode 100644 index 000000000000..6db96f79b3f1 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.extract"> + <application android:extractNativeLibs="true"> + <uses-library android:name="android.test.runner"/> + <activity android:name=".MainActivity" + android:exported="true" + android:process=":NewProcess"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + </application> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.extract"/> +</manifest>
\ No newline at end of file diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java new file mode 100644 index 000000000000..b1c157e17985 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 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 android.test.extract; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import androidx.annotation.VisibleForTesting; + +public class MainActivity extends Activity { + + static { + System.loadLibrary("punchtest"); + } + + @VisibleForTesting + static final String INTENT_TYPE = "android.test.extract.EXTRACTED_LIB_LOADED"; + + @VisibleForTesting + static final String KEY_OPERAND_1 = "OP1"; + + @VisibleForTesting + static final String KEY_OPERAND_2 = "OP2"; + + @VisibleForTesting + static final String KEY_RESULT = "RESULT"; + + @Override + public void onCreate(Bundle savedOnstanceState) { + super.onCreate(savedOnstanceState); + + Intent received = getIntent(); + int op1 = received.getIntExtra(KEY_OPERAND_1, -1); + int op2 = received.getIntExtra(KEY_OPERAND_2, -1); + int result = subtract(op1, op2); + + // Send broadcast so that test can know app has launched and lib is loaded + // attach result which has been fetched from JNI lib + Intent intent = new Intent(INTENT_TYPE); + intent.putExtra(KEY_RESULT, result); + sendBroadcast(intent); + } + + private native int subtract(int op1, int op2); +} diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java new file mode 100644 index 000000000000..7cc101751b3d --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 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 android.test.extract; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class PunchExtractedLibTest { + + @Test + public void testPunchedNativeLibs_extractedLib() throws Exception { + Context context = InstrumentationRegistry.getContext(); + CountDownLatch receivedSignal = new CountDownLatch(1); + + // Test app is expected to receive this and perform subtraction using extracted lib + int op1 = 100; + int op2 = 71; + IntentFilter intentFilter = new IntentFilter(MainActivity.INTENT_TYPE); + BroadcastReceiver broadcastReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + receivedSignal.countDown(); + int result = intent.getIntExtra(MainActivity.KEY_RESULT, 1000); + Assert.assertEquals(result, op1 - op2); + } + }; + context.registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED); + + Intent launchIntent = + context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); + launchIntent.putExtra(MainActivity.KEY_OPERAND_1, op1); + launchIntent.putExtra(MainActivity.KEY_OPERAND_2, op2); + context.startActivity(launchIntent); + + Assert.assertTrue("Failed to launch app", receivedSignal.await(10, TimeUnit.SECONDS)); + } +} diff --git a/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp b/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp new file mode 100644 index 000000000000..2a5ba817d9db --- /dev/null +++ b/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 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 <jni.h> + +// This will be called from embedded_native_libs_test_app +extern "C" JNIEXPORT +jint JNICALL Java_android_test_embedded_MainActivity_add(JNIEnv*, jclass, jint op1, jint op2) { + return op1 + op2; +} + +// This will be called from extract_native_libs_test_app +extern "C" JNIEXPORT +jint JNICALL Java_android_test_extract_MainActivity_subtract(JNIEnv*, jclass, jint op1, jint op2) { + return op1 - op2; +} + +// Initialize JNI +jint JNI_OnLoad(JavaVM *jvm, void */* reserved */) { + JNIEnv *e; + + // Check JNI version + if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} diff --git a/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java b/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java new file mode 100644 index 000000000000..77802e5e811a --- /dev/null +++ b/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 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.internal.content; + +import static org.junit.Assert.assertTrue; + +import android.platform.test.annotations.AppModeFull; + +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class FileSystemUtilsTest extends BaseHostJUnit4Test { + + @Test + @AppModeFull + public void runPunchedApp_embeddedNativeLibs() throws DeviceNotAvailableException { + String appPackage = "android.test.embedded"; + String testName = "PunchEmbeddedLibTest"; + assertTrue(isPackageInstalled(appPackage)); + runDeviceTests(appPackage, appPackage + "." + testName); + } + + @Test + @AppModeFull + public void runPunchedApp_extractedNativeLibs() throws DeviceNotAvailableException { + String appPackage = "android.test.extract"; + String testName = "PunchExtractedLibTest"; + assertTrue(isPackageInstalled(appPackage)); + runDeviceTests(appPackage, appPackage + "." + testName); + } +} diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 2f2215fd51a2..d1d7c145680f 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,8 +16,6 @@ package android.security; -import android.compat.annotation.UnsupportedAppUsage; - /** * This class provides some constants and helper methods related to Android's Keystore service. * This class was originally much larger, but its functionality was superseded by other classes. @@ -30,11 +28,4 @@ public class KeyStore { // Used for UID field to indicate the calling UID. public static final int UID_SELF = -1; - - private static final KeyStore KEY_STORE = new KeyStore(); - - @UnsupportedAppUsage - public static KeyStore getInstance() { - return KEY_STORE; - } } diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp index 9d4b426a6759..34a6bc27b93f 100644 --- a/libs/androidfw/ZipFileRO.cpp +++ b/libs/androidfw/ZipFileRO.cpp @@ -310,3 +310,7 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const return true; } + +const char* ZipFileRO::getZipFileName() { + return mFileName; +} diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h index be1f98f4843d..031d2e8fd48f 100644 --- a/libs/androidfw/include/androidfw/ZipFileRO.h +++ b/libs/androidfw/include/androidfw/ZipFileRO.h @@ -187,6 +187,8 @@ public: */ bool uncompressEntry(ZipEntryRO entry, int fd) const; + const char* getZipFileName(); + ~ZipFileRO(); private: diff --git a/proto/src/am_capabilities.proto b/proto/src/am_capabilities.proto index d97bf816b150..fc9f7a4590bd 100644 --- a/proto/src/am_capabilities.proto +++ b/proto/src/am_capabilities.proto @@ -7,6 +7,16 @@ message Capability { string name = 1; } +message VMCapability { + string name = 1; +} + +message FrameworkCapability { + string name = 1; +} + message Capabilities { repeated Capability values = 1; + repeated VMCapability vm_capabilities = 2; + repeated FrameworkCapability framework_capabilities = 3; } diff --git a/services/Android.bp b/services/Android.bp index 32a8bbba9e55..888e044ed274 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -285,34 +285,34 @@ non_updatable_exportable_droidstubs { baseline_file: "api/lint-baseline.txt", }, }, - dists: [ - { - targets: ["sdk"], - dir: "apistubs/android/system-server/api", - dest: "android-non-updatable.txt", - }, - { - targets: ["sdk"], - dir: "apistubs/android/system-server/api", - dest: "android-non-updatable-removed.txt", - }, - ], soong_config_variables: { release_hidden_api_exportable_stubs: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/system-server/api", + dest: "android-non-updatable.txt", tag: ".exportable.api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/system-server/api", + dest: "android-non-updatable-removed.txt", tag: ".exportable.removed-api.txt", }, ], conditions_default: { dists: [ { + targets: ["sdk"], + dir: "apistubs/android/system-server/api", + dest: "android-non-updatable.txt", tag: ".api.txt", }, { + targets: ["sdk"], + dir: "apistubs/android/system-server/api", + dest: "android-non-updatable-removed.txt", tag: ".removed-api.txt", }, ], diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 7c6673145d34..de039fbdd509 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -96,6 +96,7 @@ import android.opengl.GLES10; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.Debug; import android.os.IProgressListener; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; @@ -124,6 +125,8 @@ import com.android.server.LocalServices; import com.android.server.am.LowMemDetector.MemFactor; import com.android.server.am.nano.Capabilities; import com.android.server.am.nano.Capability; +import com.android.server.am.nano.FrameworkCapability; +import com.android.server.am.nano.VMCapability; import com.android.server.compat.PlatformCompat; import com.android.server.pm.UserManagerInternal; import com.android.server.utils.Slogf; @@ -442,6 +445,22 @@ final class ActivityManagerShellCommand extends ShellCommand { capabilities.values[i] = cap; } + String[] vmCapabilities = Debug.getVmFeatureList(); + capabilities.vmCapabilities = new VMCapability[vmCapabilities.length]; + for (int i = 0; i < vmCapabilities.length; i++) { + VMCapability cap = new VMCapability(); + cap.name = vmCapabilities[i]; + capabilities.vmCapabilities[i] = cap; + } + + String[] fmCapabilities = Debug.getFeatureList(); + capabilities.frameworkCapabilities = new FrameworkCapability[fmCapabilities.length]; + for (int i = 0; i < fmCapabilities.length; i++) { + FrameworkCapability cap = new FrameworkCapability(); + cap.name = fmCapabilities[i]; + capabilities.frameworkCapabilities[i] = cap; + } + try { getRawOutputStream().write(Capabilities.toByteArray(capabilities)); } catch (IOException e) { @@ -451,10 +470,16 @@ final class ActivityManagerShellCommand extends ShellCommand { } else { // Unfortunately we don't have protobuf text format capabilities here. // Fallback to line separated list instead for text parser. - pw.println("Format: 1"); + pw.println("Format: 2"); for (String capability : CAPABILITIES) { pw.println(capability); } + for (String capability : Debug.getVmFeatureList()) { + pw.println("vm:" + capability); + } + for (String capability : Debug.getFeatureList()) { + pw.println("framework:" + capability); + } } return 0; } |