From 4bf59a583eefeb8b27a79fbd1fc5093ddb79d747 Mon Sep 17 00:00:00 2001 From: TYM Tsai Date: Mon, 4 Dec 2023 13:02:03 +0000 Subject: Move package parsing implementations to internal 1. Move implementations and related utils to internal 2. Make calling SystemConfig methods from ParsingPackageUtils.Callback to avoid calling from the client side. 3. Move isMatch and isEnabled from ComponentParseUtils to PackageInfoUtils 4. Move string from SELinuxUtil to SeinfoUtil 5. Move some methods from AndroidPackageUtils to AndroidPackageLegacyUtils 6. Copy some methods from PackageInfoUtils to AppInfoUtils 7. Use PackageParserException instead of PackageManagerException for validatePackageDexMetadata method Bug: 309596860 Test: build pass and boot to home Test: atest PackageManagerServiceServerTests Test: atest PackageManagerComponentOverrideTests Test: atest PermissionServiceMockingTests Test: atest PackageManagerServiceUnitTests Test: atest PackageManagerPerfTests Change-Id: I3de48d0d8adf714447823408673e07ed379f27ab --- .../src/android/os/PackageParsingPerfTest.kt | 8 +- .../android/internal/pm/parsing/AppInfoUtils.java | 124 + .../pm/parsing/PackageParserException.java | 30 + .../pm/parsing/pkg/AndroidPackageLegacyUtils.java | 128 + .../internal/pm/parsing/pkg/PackageImpl.java | 3788 ++++++++++++++++++++ .../pm/permission/CompatibilityPermissionInfo.java | 111 + .../com/android/internal/pm/pkg/SEInfoUtil.java | 30 + .../pm/pkg/component/ComponentMutateUtils.java | 98 + .../pm/pkg/component/ComponentParseUtils.java | 171 + .../pkg/component/InstallConstraintsTagParser.java | 129 + .../pm/pkg/component/ParsedActivityImpl.java | 709 ++++ .../pm/pkg/component/ParsedActivityUtils.java | 648 ++++ .../pkg/component/ParsedApexSystemServiceImpl.java | 261 ++ .../component/ParsedApexSystemServiceUtils.java | 72 + .../pm/pkg/component/ParsedAttributionImpl.java | 220 ++ .../pm/pkg/component/ParsedAttributionUtils.java | 161 + .../pm/pkg/component/ParsedComponentImpl.java | 318 ++ .../pm/pkg/component/ParsedComponentUtils.java | 126 + .../pkg/component/ParsedInstrumentationImpl.java | 179 + .../pkg/component/ParsedInstrumentationUtils.java | 84 + .../pm/pkg/component/ParsedIntentInfoImpl.java | 183 + .../pm/pkg/component/ParsedIntentInfoUtils.java | 289 ++ .../pm/pkg/component/ParsedMainComponentImpl.java | 240 ++ .../pm/pkg/component/ParsedMainComponentUtils.java | 150 + .../pkg/component/ParsedPermissionGroupImpl.java | 185 + .../pm/pkg/component/ParsedPermissionImpl.java | 249 ++ .../pm/pkg/component/ParsedPermissionUtils.java | 327 ++ .../pm/pkg/component/ParsedProcessImpl.java | 317 ++ .../pm/pkg/component/ParsedProcessUtils.java | 220 ++ .../pm/pkg/component/ParsedProviderImpl.java | 312 ++ .../pm/pkg/component/ParsedProviderUtils.java | 369 ++ .../pm/pkg/component/ParsedServiceImpl.java | 153 + .../pm/pkg/component/ParsedServiceUtils.java | 185 + .../pm/pkg/component/ParsedUsesPermissionImpl.java | 171 + .../pm/pkg/parsing/ParsingPackageUtils.java | 3459 ++++++++++++++++++ .../internal/pm/pkg/parsing/ParsingUtils.java | 221 ++ .../internal/pm/split/DefaultSplitAssetLoader.java | 107 + .../pm/split/SplitAssetDependencyLoader.java | 137 + .../internal/pm/split/SplitAssetLoader.java | 32 + .../com/android/server/pm/pkg/AndroidPackage.java | 7 +- .../android/server/am/ActivityManagerService.java | 2 +- .../integrity/AppIntegrityManagerServiceImpl.java | 2 +- .../java/com/android/server/pm/InitAppsHelper.java | 4 +- .../android/server/pm/InstallPackageHelper.java | 14 +- .../java/com/android/server/pm/InstallRequest.java | 2 +- .../android/server/pm/PackageInstallerSession.java | 2 +- .../android/server/pm/PackageManagerService.java | 12 +- .../android/server/pm/ReconcilePackageUtils.java | 2 +- .../com/android/server/pm/RemovePackageHelper.java | 6 +- .../com/android/server/pm/ScanPackageUtils.java | 4 +- .../java/com/android/server/pm/ScanRequest.java | 2 +- .../core/java/com/android/server/pm/Settings.java | 2 +- .../com/android/server/pm/SharedUserSetting.java | 4 +- .../com/android/server/pm/StorageEventHelper.java | 2 +- .../android/server/pm/parsing/PackageCacher.java | 2 +- .../server/pm/parsing/PackageInfoUtils.java | 39 +- .../android/server/pm/parsing/PackageParser2.java | 20 +- .../server/pm/parsing/pkg/AndroidPackageUtils.java | 65 +- .../android/server/pm/parsing/pkg/PackageImpl.java | 3783 ------------------- .../pm/permission/CompatibilityPermissionInfo.java | 111 - .../permission/PermissionManagerServiceImpl.java | 5 +- .../com/android/server/pm/pkg/SELinuxUtil.java | 6 +- .../pm/pkg/component/ComponentMutateUtils.java | 106 - .../pm/pkg/component/ComponentParseUtils.java | 188 - .../pkg/component/InstallConstraintsTagParser.java | 131 - .../pm/pkg/component/ParsedActivityImpl.java | 710 ---- .../pm/pkg/component/ParsedActivityUtils.java | 649 ---- .../pkg/component/ParsedApexSystemServiceImpl.java | 262 -- .../component/ParsedApexSystemServiceUtils.java | 74 - .../pm/pkg/component/ParsedAttributionImpl.java | 221 -- .../pm/pkg/component/ParsedAttributionUtils.java | 162 - .../pm/pkg/component/ParsedComponentImpl.java | 320 -- .../pm/pkg/component/ParsedComponentUtils.java | 126 - .../pkg/component/ParsedInstrumentationImpl.java | 180 - .../pkg/component/ParsedInstrumentationUtils.java | 85 - .../pm/pkg/component/ParsedIntentInfoImpl.java | 184 - .../pm/pkg/component/ParsedIntentInfoUtils.java | 290 -- .../pm/pkg/component/ParsedMainComponentImpl.java | 241 -- .../pm/pkg/component/ParsedMainComponentUtils.java | 152 - .../pkg/component/ParsedPermissionGroupImpl.java | 186 - .../pm/pkg/component/ParsedPermissionImpl.java | 251 -- .../pm/pkg/component/ParsedPermissionUtils.java | 329 -- .../server/pm/pkg/component/ParsedProcessImpl.java | 318 -- .../pm/pkg/component/ParsedProcessUtils.java | 221 -- .../pm/pkg/component/ParsedProviderImpl.java | 313 -- .../pm/pkg/component/ParsedProviderUtils.java | 370 -- .../server/pm/pkg/component/ParsedServiceImpl.java | 155 - .../pm/pkg/component/ParsedServiceUtils.java | 186 - .../pm/pkg/component/ParsedUsesPermissionImpl.java | 172 - .../server/pm/pkg/parsing/ParsingPackageUtils.java | 3489 ------------------ .../server/pm/pkg/parsing/ParsingUtils.java | 222 -- .../server/pm/resolution/ComponentResolver.java | 4 +- .../server/pm/split/DefaultSplitAssetLoader.java | 107 - .../pm/split/SplitAssetDependencyLoader.java | 137 - .../android/server/pm/split/SplitAssetLoader.java | 32 - .../access/permission/AppIdPermissionPolicy.kt | 2 +- .../pm/CrossProfileAppsServiceImplRoboTest.java | 2 +- ...PackageManagerComponentLabelIconOverrideTest.kt | 6 +- .../com/android/server/pm/AppsFilterImplTest.java | 16 +- .../android/server/pm/CompatibilityModeTest.java | 4 +- .../server/pm/PackageManagerSettingsTests.java | 2 +- .../com/android/server/pm/PackageManagerTests.java | 4 +- .../com/android/server/pm/PackageParserTest.java | 34 +- .../src/com/android/server/pm/ScanTests.java | 8 +- .../pm/parsing/PackageParserLegacyCoreTest.java | 4 +- .../pm/parsing/PackageParsingDeferErrorTest.kt | 3 +- .../android/server/pm/parsing/ParsingUtils.java | 81 + .../server/pm/parsing/SystemPartitionParseTest.kt | 4 +- .../pm/parsing/library/AndroidHidlUpdaterTest.java | 2 +- .../library/AndroidNetIpSecIkeUpdaterTest.java | 2 +- .../library/AndroidTestBaseUpdaterTest.java | 2 +- .../library/AndroidTestRunnerSplitUpdaterTest.java | 2 +- .../library/ApexSharedLibraryUpdaterTest.java | 2 +- .../library/ComGoogleAndroidMapsUpdaterTest.java | 2 +- .../library/OrgApacheHttpLegacyUpdaterTest.java | 2 +- .../library/PackageBackwardCompatibilityTest.java | 2 +- ...emoveUnnecessaryAndroidTestBaseLibraryTest.java | 2 +- ...eUnnecessaryOrgApacheHttpLegacyLibraryTest.java | 2 +- .../test/parsing/parcelling/AndroidPackageTest.kt | 44 +- .../test/parsing/parcelling/ParsedActivityTest.kt | 2 +- .../parsing/parcelling/ParsedAttributionTest.kt | 2 +- .../test/parsing/parcelling/ParsedComponentTest.kt | 4 +- .../parcelling/ParsedInstrumentationTest.kt | 2 +- .../parsing/parcelling/ParsedIntentInfoTest.kt | 2 +- .../parsing/parcelling/ParsedMainComponentTest.kt | 2 +- .../parcelling/ParsedPermissionGroupTest.kt | 2 +- .../parsing/parcelling/ParsedPermissionTest.kt | 4 +- .../test/parsing/parcelling/ParsedProcessTest.kt | 4 +- .../test/parsing/parcelling/ParsedProviderTest.kt | 4 +- .../test/parsing/parcelling/ParsedServiceTest.kt | 2 +- .../parsing/parcelling/ParsedUsesPermissionTest.kt | 2 +- .../android/server/pm/test/pkg/PackageStateTest.kt | 22 +- .../domain/DomainVerificationCollectorTest.kt | 4 +- .../domain/DomainVerificationEnforcerTest.kt | 14 +- .../domain/DomainVerificationManagerApiTest.kt | 10 +- .../verify/domain/DomainVerificationPackageTest.kt | 12 +- .../DomainVerificationSettingsMutationTest.kt | 6 +- .../DomainVerificationUserSelectionOverrideTest.kt | 7 +- .../src/com/android/server/pm/ApexManagerTest.java | 22 +- .../src/com/android/server/pm/MockSystem.kt | 20 +- .../android/server/pm/SharedLibrariesImplTest.kt | 4 +- .../src/com/android/server/pm/SELinuxMMACTest.java | 2 +- .../server/pm/UserSystemPackageInstallerTest.java | 2 +- .../com/android/server/pm/dex/DexoptUtilsTest.java | 2 +- .../parsing/AndroidPackageParsingValidationTest.kt | 6 +- .../server/pm/parsing/TestPackageParser2.kt | 4 + .../android/server/rollback/RollbackUnitTest.java | 5 +- 147 files changed, 15048 insertions(+), 14732 deletions(-) create mode 100644 core/java/com/android/internal/pm/parsing/AppInfoUtils.java create mode 100644 core/java/com/android/internal/pm/parsing/PackageParserException.java create mode 100644 core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java create mode 100644 core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java create mode 100644 core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java create mode 100644 core/java/com/android/internal/pm/pkg/SEInfoUtil.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java create mode 100644 core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java create mode 100644 core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java create mode 100644 core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java create mode 100644 core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java create mode 100644 core/java/com/android/internal/pm/split/SplitAssetLoader.java delete mode 100644 services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java delete mode 100644 services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java delete mode 100644 services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java delete mode 100644 services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java delete mode 100644 services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java delete mode 100644 services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java delete mode 100644 services/core/java/com/android/server/pm/split/SplitAssetLoader.java create mode 100644 services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt index 6d1e6d0cbd73..4352c8ae982e 100644 --- a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt +++ b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt @@ -24,10 +24,11 @@ import android.content.pm.parsing.result.ParseTypeImpl import android.content.res.TypedArray import android.perftests.utils.BenchmarkState import android.perftests.utils.PerfStatusReporter +import android.util.ArraySet import androidx.test.filters.LargeTest +import com.android.internal.pm.parsing.pkg.PackageImpl +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils import com.android.internal.util.ConcurrentUtils -import com.android.server.pm.parsing.pkg.PackageImpl -import com.android.server.pm.pkg.parsing.ParsingPackageUtils import java.io.File import java.io.FileOutputStream import java.util.concurrent.ArrayBlockingQueue @@ -214,7 +215,10 @@ public class PackageParsingPerfTest { path, manifestArray, isCoreApp, + this, ) + override fun getHiddenApiWhitelistedApps() = ArraySet() + override fun getInstallConstraintsAllowlist() = ArraySet() }) override fun parseImpl(file: File) = diff --git a/core/java/com/android/internal/pm/parsing/AppInfoUtils.java b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java new file mode 100644 index 000000000000..38a2fe2a77a1 --- /dev/null +++ b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.pm.parsing; + +import android.annotation.CheckResult; +import android.content.pm.ApplicationInfo; + +import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.server.pm.pkg.AndroidPackage; + +public class AppInfoUtils { + + /** + * @see ApplicationInfo#flags + */ + public static int appInfoFlags(AndroidPackage pkg) { + // @formatter:off + int pkgWithoutStateFlags = flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE) + | flag(pkg.isHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED) + | flag(pkg.isBackupAllowed(), ApplicationInfo.FLAG_ALLOW_BACKUP) + | flag(pkg.isKillAfterRestoreAllowed(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE) + | flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION) + | flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY) + | flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT) + | flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE) + | flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE) + | flag(pkg.isDeclaredHavingCode(), ApplicationInfo.FLAG_HAS_CODE) + | flag(pkg.isTaskReparentingAllowed(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) + | flag(pkg.isClearUserDataAllowed(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) + | flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP) + | flag(pkg.isCleartextTrafficAllowed(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) + | flag(pkg.isRtlSupported(), ApplicationInfo.FLAG_SUPPORTS_RTL) + | flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY) + | flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH) + | flag(pkg.isExtractNativeLibrariesRequested(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) + | flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME) + | flag(pkg.isSmallScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) + | flag(pkg.isNormalScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) + | flag(pkg.isLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) + | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) + | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) + | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) + | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM) + | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST); + + return pkgWithoutStateFlags; + // @formatter:on + } + + /** @see ApplicationInfo#privateFlags */ + public static int appInfoPrivateFlags(AndroidPackage pkg) { + // @formatter:off + int pkgWithoutStateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) + | flag(pkg.isResourceOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY) + | flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) + | flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) + | flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) + | flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND) + | flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) + | flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) + | flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) + | flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) + | flag(pkg.isClearUserDataOnFailedRestoreAllowed(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE) + | flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE) + | flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) + | flag(pkg.isNonSdkApiRequested(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) + | flag(pkg.isUserDataFragile(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA) + | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) + | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) + | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING) + | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) + | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) + | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM) + | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR) + | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT) + | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM) + | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY); + + Boolean resizeableActivity = pkg.getResizeableActivity(); + if (resizeableActivity != null) { + if (resizeableActivity) { + pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; + } else { + pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; + } + } + + return pkgWithoutStateFlags; + // @formatter:on + } + + + /** @see ApplicationInfo#privateFlagsExt */ + public static int appInfoPrivateFlagsExt(AndroidPackage pkg, + boolean isAllowlistedForHiddenApis) { + // @formatter:off + int pkgWithoutStateFlags = flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE) + | flag(pkg.hasRequestForegroundServiceExemption(), ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION) + | flag(pkg.isAttributionsUserVisible(), ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE) + | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK) + | flag(isAllowlistedForHiddenApis, ApplicationInfo.PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS); + return pkgWithoutStateFlags; + // @formatter:on + } + + @CheckResult + private static int flag(boolean hasFlag, int flag) { + return hasFlag ? flag : 0; + } +} diff --git a/core/java/com/android/internal/pm/parsing/PackageParserException.java b/core/java/com/android/internal/pm/parsing/PackageParserException.java new file mode 100644 index 000000000000..4250bbd9baf6 --- /dev/null +++ b/core/java/com/android/internal/pm/parsing/PackageParserException.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.pm.parsing; + +public class PackageParserException extends Exception { + public final int error; + + public PackageParserException(int error, String detailMessage) { + super(detailMessage); + this.error = error; + } + + public PackageParserException(int error, String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + this.error = error; + } +} \ No newline at end of file diff --git a/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java new file mode 100644 index 000000000000..e65f1c960b6a --- /dev/null +++ b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.pm.parsing.pkg; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; + +import com.android.internal.pm.pkg.parsing.ParsingPackageHidden; +import com.android.server.pm.pkg.AndroidPackage; + +/** @hide */ +public class AndroidPackageLegacyUtils { + + private AndroidPackageLegacyUtils() { + } + + /** + * Returns the primary ABI as parsed from the package. Used only during parsing and derivation. + * Otherwise prefer {@link PackageState#getPrimaryCpuAbi()}. + */ + public static String getRawPrimaryCpuAbi(AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).getPrimaryCpuAbi(); + } + + /** + * Returns the secondary ABI as parsed from the package. Used only during parsing and + * derivation. Otherwise prefer {@link PackageState#getSecondaryCpuAbi()}. + */ + public static String getRawSecondaryCpuAbi(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi(); + } + + @Deprecated + @NonNull + public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).toAppInfoWithoutState(); + } + + /** + * Replacement of unnecessary legacy getRealPackage. Only returns a value if the package was + * actually renamed. + */ + @Nullable + public static String getRealPackageOrNull(@NonNull AndroidPackage pkg, boolean isSystem) { + if (pkg.getOriginalPackages().isEmpty() || !isSystem) { + return null; + } + + return pkg.getManifestPackageName(); + } + + public static void fillVersionCodes(@NonNull AndroidPackage pkg, @NonNull PackageInfo info) { + info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode(); + info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor(); + } + + /** + * @deprecated Use {@link PackageState#isSystem} + */ + @Deprecated + public static boolean isSystem(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).isSystem(); + } + + /** + * @deprecated Use {@link PackageState#isSystemExt} + */ + @Deprecated + public static boolean isSystemExt(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).isSystemExt(); + } + + /** + * @deprecated Use {@link PackageState#isPrivileged} + */ + @Deprecated + public static boolean isPrivileged(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).isPrivileged(); + } + + /** + * @deprecated Use {@link PackageState#isOem} + */ + @Deprecated + public static boolean isOem(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).isOem(); + } + + /** + * @deprecated Use {@link PackageState#isVendor} + */ + @Deprecated + public static boolean isVendor(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).isVendor(); + } + + /** + * @deprecated Use {@link PackageState#isProduct} + */ + @Deprecated + public static boolean isProduct(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).isProduct(); + } + + /** + * @deprecated Use {@link PackageState#isOdm} + */ + @Deprecated + public static boolean isOdm(@NonNull AndroidPackage pkg) { + return ((AndroidPackageHidden) pkg).isOdm(); + } +} diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java new file mode 100644 index 000000000000..f7e1f7293ac6 --- /dev/null +++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java @@ -0,0 +1,3788 @@ +/* + * 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.internal.pm.parsing.pkg; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; + +import android.annotation.LongDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.SigningDetails; +import android.content.res.TypedArray; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.UserHandle; +import android.os.storage.StorageManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Pair; +import android.util.SparseArray; +import android.util.SparseIntArray; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.parsing.AppInfoUtils; +import com.android.internal.pm.pkg.AndroidPackageSplitImpl; +import com.android.internal.pm.pkg.SEInfoUtil; +import com.android.internal.pm.pkg.component.ComponentMutateUtils; +import com.android.internal.pm.pkg.component.ParsedActivity; +import com.android.internal.pm.pkg.component.ParsedActivityImpl; +import com.android.internal.pm.pkg.component.ParsedApexSystemService; +import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl; +import com.android.internal.pm.pkg.component.ParsedAttribution; +import com.android.internal.pm.pkg.component.ParsedAttributionImpl; +import com.android.internal.pm.pkg.component.ParsedComponent; +import com.android.internal.pm.pkg.component.ParsedInstrumentation; +import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl; +import com.android.internal.pm.pkg.component.ParsedIntentInfo; +import com.android.internal.pm.pkg.component.ParsedMainComponent; +import com.android.internal.pm.pkg.component.ParsedPermission; +import com.android.internal.pm.pkg.component.ParsedPermissionGroup; +import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl; +import com.android.internal.pm.pkg.component.ParsedPermissionImpl; +import com.android.internal.pm.pkg.component.ParsedProcess; +import com.android.internal.pm.pkg.component.ParsedProcessImpl; +import com.android.internal.pm.pkg.component.ParsedProvider; +import com.android.internal.pm.pkg.component.ParsedProviderImpl; +import com.android.internal.pm.pkg.component.ParsedService; +import com.android.internal.pm.pkg.component.ParsedServiceImpl; +import com.android.internal.pm.pkg.component.ParsedUsesPermission; +import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageHidden; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingUtils; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; +import com.android.server.pm.pkg.AndroidPackage; +import com.android.server.pm.pkg.AndroidPackageSplit; + +import libcore.util.EmptyArray; + +import java.io.File; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * Extensions to {@link PackageImpl} including fields/state contained in the system server + * and not exposed to the core SDK. + * + * @hide + */ +public class PackageImpl implements ParsedPackage, AndroidPackageInternal, + AndroidPackageHidden, ParsingPackage, ParsingPackageHidden, Parcelable { + + private static final SparseArray EMPTY_INT_ARRAY_SPARSE_ARRAY = new SparseArray<>(); + private static final Comparator ORDER_COMPARATOR = + (first, second) -> Integer.compare(second.getOrder(), first.getOrder()); + public static final Parcelling.BuiltIn.ForBoolean sForBoolean = Parcelling.Cache.getOrCreate( + Parcelling.BuiltIn.ForBoolean.class); + public static final ForInternedString sForInternedString = Parcelling.Cache.getOrCreate( + ForInternedString.class); + public static final Parcelling.BuiltIn.ForInternedStringArray sForInternedStringArray = + Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringArray.class); + public static final Parcelling.BuiltIn.ForInternedStringList sForInternedStringList = + Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringList.class); + public static final Parcelling.BuiltIn.ForInternedStringValueMap sForInternedStringValueMap = + Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringValueMap.class); + public static final Parcelling.BuiltIn.ForStringSet sForStringSet = + Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class); + public static final Parcelling.BuiltIn.ForInternedStringSet sForInternedStringSet = + Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringSet.class); + protected static final ParsingUtils.StringPairListParceler sForIntentInfoPairs = + new ParsingUtils.StringPairListParceler(); + protected int versionCode; + protected int versionCodeMajor; + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + protected String packageName; + @NonNull + protected String mBaseApkPath; + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + protected List usesLibraries = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + protected List usesOptionalLibraries = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + protected List usesNativeLibraries = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + protected List usesOptionalNativeLibraries = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + protected List originalPackages = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + protected List adoptPermissions = emptyList(); + /** + * @deprecated consider migrating to {@link #getUsesPermissions} which has + * more parsed details, such as flags + */ + @NonNull + @Deprecated + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) + protected Set requestedPermissions = emptySet(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + protected List protectedBroadcasts = emptyList(); + @NonNull + protected List activities = emptyList(); + @NonNull + protected List apexSystemServices = emptyList(); + @NonNull + protected List receivers = emptyList(); + @NonNull + protected List services = emptyList(); + @NonNull + protected List providers = emptyList(); + @NonNull + protected List permissions = emptyList(); + @NonNull + protected List permissionGroups = emptyList(); + @NonNull + protected List instrumentations = emptyList(); + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String volumeUuid; + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + protected String mPath; + @Nullable + protected String[] splitCodePaths; + @NonNull + protected UUID mStorageUuid; + // These are objects because null represents not explicitly set + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean supportsSmallScreens; + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean supportsNormalScreens; + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean supportsLargeScreens; + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean supportsExtraLargeScreens; + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean resizeable; + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean anyDensity; + private int baseRevisionCode; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String versionName; + private int compileSdkVersion; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String compileSdkVersionCodeName; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String restrictedAccountType; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String requiredAccountType; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String overlayTarget; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String overlayTargetOverlayableName; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String overlayCategory; + private int overlayPriority; + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringValueMap.class) + private Map overlayables = emptyMap(); + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String sdkLibraryName; + private int sdkLibVersionMajor; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String staticSharedLibraryName; + private long staticSharedLibVersion; + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + private List libraryNames = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + private List usesStaticLibraries = emptyList(); + @Nullable + private long[] usesStaticLibrariesVersions; + @Nullable + private String[][] usesStaticLibrariesCertDigests; + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + private List usesSdkLibraries = emptyList(); + @Nullable + private long[] usesSdkLibrariesVersionsMajor; + @Nullable + private String[][] usesSdkLibrariesCertDigests; + @Nullable + private boolean[] usesSdkLibrariesOptional; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String sharedUserId; + private int sharedUserLabel; + @NonNull + private List configPreferences = emptyList(); + @NonNull + private List reqFeatures = emptyList(); + @NonNull + private List featureGroups = emptyList(); + @Nullable + private byte[] restrictUpdateHash; + @NonNull + private List usesPermissions = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) + private Set implicitPermissions = emptySet(); + @NonNull + private Set upgradeKeySets = emptySet(); + @NonNull + private Map> keySetMapping = emptyMap(); + @NonNull + private List attributions = emptyList(); + @NonNull +// @DataClass.ParcelWith(ParsingUtils.StringPairListParceler.class) + private List> preferredActivityFilters = emptyList(); + /** + * Map from a process name to a {@link ParsedProcess}. + */ + @NonNull + private Map processes = emptyMap(); + @Nullable + private Bundle metaData; + @NonNull + private Map mProperties = emptyMap(); + @NonNull + private SigningDetails signingDetails = SigningDetails.UNKNOWN; + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + private List queriesIntents = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) + private List queriesPackages = emptyList(); + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) + private Set queriesProviders = emptySet(); + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringArray.class) + private String[] splitClassLoaderNames; + @Nullable + private SparseArray splitDependencies; + @Nullable + private int[] splitFlags; + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringArray.class) + private String[] splitNames; + @Nullable + private int[] splitRevisionCodes; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String appComponentFactory; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String backupAgentName; + private int banner; + private int category = ApplicationInfo.CATEGORY_UNDEFINED; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String classLoaderName; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String className; + private int compatibleWidthLimitDp; + private int descriptionRes; + private int fullBackupContent; + private int dataExtractionRules; + private int iconRes; + private int installLocation = ParsingPackageUtils.PARSE_DEFAULT_INSTALL_LOCATION; + private int labelRes; + private int largestWidthLimitDp; + private int logo; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String manageSpaceActivityName; + private float maxAspectRatio; + private float minAspectRatio; + @Nullable + private SparseIntArray minExtensionVersions; + private int minSdkVersion = ParsingUtils.DEFAULT_MIN_SDK_VERSION; + private int maxSdkVersion = ParsingUtils.DEFAULT_MAX_SDK_VERSION; + private int networkSecurityConfigRes; + @Nullable + private CharSequence nonLocalizedLabel; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String permission; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String processName; + private int requiresSmallestWidthDp; + private int roundIconRes; + private int targetSandboxVersion; + private int targetSdkVersion = ParsingUtils.DEFAULT_TARGET_SDK_VERSION; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String taskAffinity; + private int theme; + private int uiOptions; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String zygotePreloadName; + /** + * @see AndroidPackage#getResizeableActivity() + */ + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean resizeableActivity; + private int autoRevokePermissions; + @ApplicationInfo.GwpAsanMode + private int gwpAsanMode; + @ApplicationInfo.MemtagMode + private int memtagMode; + @ApplicationInfo.NativeHeapZeroInitialized + private int nativeHeapZeroInitialized; + @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) + private Boolean requestRawExternalStorageAccess; + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) + private Set mimeGroups = emptySet(); + // Usually there's code to set enabled to true during parsing, but it's possible to install + // an APK targeting tag. That code would be skipped + // and never assign this, so initialize this to true for those cases. + private long mBooleans = Booleans.ENABLED; + private long mBooleans2 = Booleans2.UPDATABLE_SYSTEM; + @NonNull + private Set mKnownActivityEmbeddingCerts = emptySet(); + // Derived fields + private long mLongVersionCode; + private int mLocaleConfigRes; + + private List mSplits; + + @NonNull + private String[] mUsesLibrariesSorted; + @NonNull + private String[] mUsesOptionalLibrariesSorted; + @NonNull + private String[] mUsesSdkLibrariesSorted; + @NonNull + private String[] mUsesStaticLibrariesSorted; + + @NonNull + public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath, + @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp, + @Nullable ParsingPackageUtils.Callback callback) { + return new PackageImpl( + packageName, baseCodePath, codePath, manifestArray, isCoreApp, callback); + } + + /** + * Mock an unavailable {@link AndroidPackage} to use when + * removing + * a package from the system. + * This can occur if the package was installed on a storage device that has since been removed. + * Since the infrastructure uses {@link AndroidPackage}, but + * for + * this case only cares about + * volumeUuid, just fake it rather than having separate method paths. + */ + @NonNull + public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) { + return PackageImpl.forTesting(packageName) + .setVolumeUuid(volumeUuid) + .hideAsParsed() + .hideAsFinal(); + } + + @NonNull + @VisibleForTesting + public static ParsingPackage forTesting(String packageName) { + return forTesting(packageName, ""); + } + + @NonNull + @VisibleForTesting + public static ParsingPackage forTesting(String packageName, String baseCodePath) { + return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false, null); + } + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + private final String manifestPackageName; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String nativeLibraryDir; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String nativeLibraryRootDir; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String primaryCpuAbi; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String secondaryCpuAbi; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + protected String secondaryNativeLibraryDir; + + /** + * This is an appId, the uid if the userId is == USER_SYSTEM + */ + private int uid = -1; + + // This is kept around as a boolean to avoid flag calculation + // during ApplicationInfo generation. + private boolean nativeLibraryRootRequiresIsa; + + @Override + public PackageImpl addActivity(ParsedActivity parsedActivity) { + this.activities = CollectionUtils.add(this.activities, parsedActivity); + addMimeGroupsFromComponent(parsedActivity); + return this; + } + + @Override + public PackageImpl addAdoptPermission(String adoptPermission) { + this.adoptPermissions = CollectionUtils.add(this.adoptPermissions, + TextUtils.safeIntern(adoptPermission)); + return this; + } + + @Override + public final PackageImpl addApexSystemService( + ParsedApexSystemService parsedApexSystemService) { + this.apexSystemServices = CollectionUtils.add( + this.apexSystemServices, parsedApexSystemService); + return this; + } + + @Override + public PackageImpl addAttribution(ParsedAttribution attribution) { + this.attributions = CollectionUtils.add(this.attributions, attribution); + return this; + } + + @Override + public PackageImpl addConfigPreference(ConfigurationInfo configPreference) { + this.configPreferences = CollectionUtils.add(this.configPreferences, configPreference); + return this; + } + + @Override + public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) { + this.featureGroups = CollectionUtils.add(this.featureGroups, featureGroup); + return this; + } + + @Override + public PackageImpl addImplicitPermission(String permission) { + addUsesPermission(new ParsedUsesPermissionImpl(permission, 0 /*usesPermissionFlags*/)); + this.implicitPermissions = CollectionUtils.add(this.implicitPermissions, + TextUtils.safeIntern(permission)); + return this; + } + + @Override + public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) { + this.instrumentations = CollectionUtils.add(this.instrumentations, instrumentation); + return this; + } + + @Override + public PackageImpl addKeySet(String keySetName, PublicKey publicKey) { + ArraySet publicKeys = keySetMapping.get(keySetName); + if (publicKeys == null) { + publicKeys = new ArraySet<>(); + } + publicKeys.add(publicKey); + keySetMapping = CollectionUtils.add(this.keySetMapping, keySetName, publicKeys); + return this; + } + + @Override + public PackageImpl addLibraryName(String libraryName) { + this.libraryNames = CollectionUtils.add(this.libraryNames, + TextUtils.safeIntern(libraryName)); + return this; + } + + private void addMimeGroupsFromComponent(ParsedComponent component) { + for (int i = component.getIntents().size() - 1; i >= 0; i--) { + IntentFilter filter = component.getIntents().get(i).getIntentFilter(); + for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) { + if (mimeGroups != null && mimeGroups.size() > 500) { + throw new IllegalStateException("Max limit on number of MIME Groups reached"); + } + mimeGroups = CollectionUtils.add(mimeGroups, filter.getMimeGroup(groupIndex)); + } + } + } + + @Override + public PackageImpl addOriginalPackage(String originalPackage) { + this.originalPackages = CollectionUtils.add(this.originalPackages, originalPackage); + return this; + } + + @Override + public ParsingPackage addOverlayable(String overlayableName, String actorName) { + this.overlayables = CollectionUtils.add(this.overlayables, overlayableName, + TextUtils.safeIntern(actorName)); + return this; + } + + @Override + public PackageImpl addPermission(ParsedPermission permission) { + this.permissions = CollectionUtils.add(this.permissions, permission); + return this; + } + + @Override + public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) { + this.permissionGroups = CollectionUtils.add(this.permissionGroups, permissionGroup); + return this; + } + + @Override + public PackageImpl addPreferredActivityFilter(String className, + ParsedIntentInfo intentInfo) { + this.preferredActivityFilters = CollectionUtils.add(this.preferredActivityFilters, + Pair.create(className, intentInfo)); + return this; + } + + @Override + public PackageImpl addProperty(@Nullable PackageManager.Property property) { + if (property == null) { + return this; + } + this.mProperties = CollectionUtils.add(this.mProperties, property.getName(), property); + return this; + } + + @Override + public PackageImpl addProtectedBroadcast(String protectedBroadcast) { + if (!this.protectedBroadcasts.contains(protectedBroadcast)) { + this.protectedBroadcasts = CollectionUtils.add(this.protectedBroadcasts, + TextUtils.safeIntern(protectedBroadcast)); + } + return this; + } + + @Override + public PackageImpl addProvider(ParsedProvider parsedProvider) { + this.providers = CollectionUtils.add(this.providers, parsedProvider); + addMimeGroupsFromComponent(parsedProvider); + return this; + } + + @Override + public PackageImpl addQueriesIntent(Intent intent) { + this.queriesIntents = CollectionUtils.add(this.queriesIntents, intent); + return this; + } + + @Override + public PackageImpl addQueriesPackage(String packageName) { + this.queriesPackages = CollectionUtils.add(this.queriesPackages, + TextUtils.safeIntern(packageName)); + return this; + } + + @Override + public PackageImpl addQueriesProvider(String authority) { + this.queriesProviders = CollectionUtils.add(this.queriesProviders, authority); + return this; + } + + @Override + public PackageImpl addReceiver(ParsedActivity parsedReceiver) { + this.receivers = CollectionUtils.add(this.receivers, parsedReceiver); + addMimeGroupsFromComponent(parsedReceiver); + return this; + } + + @Override + public PackageImpl addReqFeature(FeatureInfo reqFeature) { + this.reqFeatures = CollectionUtils.add(this.reqFeatures, reqFeature); + return this; + } + + @Override + public PackageImpl addService(ParsedService parsedService) { + this.services = CollectionUtils.add(this.services, parsedService); + addMimeGroupsFromComponent(parsedService); + return this; + } + + @Override + public PackageImpl addUsesLibrary(String libraryName) { + libraryName = TextUtils.safeIntern(libraryName); + if (!ArrayUtils.contains(this.usesLibraries, libraryName)) { + this.usesLibraries = CollectionUtils.add(this.usesLibraries, libraryName); + } + return this; + } + + @Override + public final PackageImpl addUsesNativeLibrary(String libraryName) { + libraryName = TextUtils.safeIntern(libraryName); + if (!ArrayUtils.contains(this.usesNativeLibraries, libraryName)) { + this.usesNativeLibraries = CollectionUtils.add(this.usesNativeLibraries, libraryName); + } + return this; + } + + @Override + public PackageImpl addUsesOptionalLibrary(String libraryName) { + libraryName = TextUtils.safeIntern(libraryName); + if (!ArrayUtils.contains(this.usesOptionalLibraries, libraryName)) { + this.usesOptionalLibraries = CollectionUtils.add(this.usesOptionalLibraries, + libraryName); + } + return this; + } + + @Override + public final PackageImpl addUsesOptionalNativeLibrary(String libraryName) { + libraryName = TextUtils.safeIntern(libraryName); + if (!ArrayUtils.contains(this.usesOptionalNativeLibraries, libraryName)) { + this.usesOptionalNativeLibraries = CollectionUtils.add(this.usesOptionalNativeLibraries, + libraryName); + } + return this; + } + + @Override + public PackageImpl addUsesPermission(ParsedUsesPermission permission) { + this.usesPermissions = CollectionUtils.add(this.usesPermissions, permission); + + // Continue populating legacy data structures to avoid performance + // issues until all that code can be migrated + this.requestedPermissions = CollectionUtils.add(this.requestedPermissions, + permission.getName()); + + return this; + } + + @Override + public PackageImpl addUsesSdkLibrary(String libraryName, long versionMajor, + String[] certSha256Digests, boolean usesSdkLibrariesOptional) { + this.usesSdkLibraries = CollectionUtils.add(this.usesSdkLibraries, + TextUtils.safeIntern(libraryName)); + this.usesSdkLibrariesVersionsMajor = ArrayUtils.appendLong( + this.usesSdkLibrariesVersionsMajor, versionMajor, true); + this.usesSdkLibrariesCertDigests = ArrayUtils.appendElement(String[].class, + this.usesSdkLibrariesCertDigests, certSha256Digests, true); + this.usesSdkLibrariesOptional = appendBoolean(this.usesSdkLibrariesOptional, + usesSdkLibrariesOptional); + return this; + } + + /** + * Adds value to given array if not already present, providing set-like + * behavior. + */ + public static boolean[] appendBoolean(@Nullable boolean[] cur, boolean val) { + if (cur == null) { + return new boolean[] { val }; + } + final int N = cur.length; + boolean[] ret = new boolean[N + 1]; + System.arraycopy(cur, 0, ret, 0, N); + ret[N] = val; + return ret; + } + + @Override + public PackageImpl addUsesStaticLibrary(String libraryName, long version, + String[] certSha256Digests) { + this.usesStaticLibraries = CollectionUtils.add(this.usesStaticLibraries, + TextUtils.safeIntern(libraryName)); + this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions, + version, true); + this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, + this.usesStaticLibrariesCertDigests, certSha256Digests, true); + return this; + } + + @Override + public boolean isAttributionsUserVisible() { + return getBoolean(Booleans.ATTRIBUTIONS_ARE_USER_VISIBLE); + } + + @Override + public PackageImpl asSplit(String[] splitNames, String[] splitCodePaths, + int[] splitRevisionCodes, SparseArray splitDependencies) { + this.splitNames = splitNames; + this.splitCodePaths = splitCodePaths; + this.splitRevisionCodes = splitRevisionCodes; + this.splitDependencies = splitDependencies; + + int count = splitNames.length; + this.splitFlags = new int[count]; + this.splitClassLoaderNames = new String[count]; + return this; + } + + protected void assignDerivedFields() { + mStorageUuid = StorageManager.convert(volumeUuid); + mLongVersionCode = PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); + } + + /** + * Create a map from a process name to the custom application class for this process, + * which comes from . + * + * The original information is stored in {@link #processes}, but it's stored in + * a form of: [process name] -[1:N]-> [package name] -[1:N]-> [class name]. + * We scan it and collect the process names and their app class names, only for this package. + * + * The resulting map only contains processes with a custom application class set. + */ + @Nullable + private ArrayMap buildAppClassNamesByProcess() { + if (ArrayUtils.size(processes) == 0) { + return null; + } + final ArrayMap ret = new ArrayMap<>(4); + for (String processName : processes.keySet()) { + final ParsedProcess process = processes.get(processName); + final ArrayMap appClassesByPackage = + process.getAppClassNamesByPackage(); + + for (int i = 0; i < appClassesByPackage.size(); i++) { + final String packageName = appClassesByPackage.keyAt(i); + + if (this.packageName.equals(packageName)) { + final String appClassName = appClassesByPackage.valueAt(i); + if (!TextUtils.isEmpty(appClassName)) { + ret.put(processName, appClassName); + } + } + } + } + return ret; + } + + @Override + public List getSplits() { + if (mSplits == null) { + var splits = new ArrayList(); + splits.add(new AndroidPackageSplitImpl( + null, + getBaseApkPath(), + getBaseRevisionCode(), + isDeclaredHavingCode() ? ApplicationInfo.FLAG_HAS_CODE : 0, + getClassLoaderName() + )); + + if (splitNames != null) { + for (int index = 0; index < splitNames.length; index++) { + splits.add(new AndroidPackageSplitImpl( + splitNames[index], + splitCodePaths[index], + splitRevisionCodes[index], + splitFlags[index], + splitClassLoaderNames[index] + )); + } + } + + if (splitDependencies != null) { + for (int index = 0; index < splitDependencies.size(); index++) { + var splitIndex = splitDependencies.keyAt(index); + var dependenciesByIndex = splitDependencies.valueAt(index); + var dependencies = new ArrayList(); + for (int dependencyIndex : dependenciesByIndex) { + // Legacy holdover, base dependencies are an array of -1 rather than empty + if (dependencyIndex >= 0) { + dependencies.add(splits.get(dependencyIndex)); + } + } + ((AndroidPackageSplitImpl) splits.get(splitIndex)) + .fillDependencies(Collections.unmodifiableList(dependencies)); + } + } + + mSplits = Collections.unmodifiableList(splits); + } + return mSplits; + } + + @Override + public String toString() { + return "Package{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + packageName + "}"; + } + + @NonNull + @Override + public List getActivities() { + return activities; + } + + @NonNull + @Override + public List getAdoptPermissions() { + return adoptPermissions; + } + + @NonNull + @Override + public List getApexSystemServices() { + return apexSystemServices; + } + + @Nullable + @Override + public String getAppComponentFactory() { + return appComponentFactory; + } + + @NonNull + @Override + public List getAttributions() { + return attributions; + } + + @Override + public int getAutoRevokePermissions() { + return autoRevokePermissions; + } + + @Nullable + @Override + public String getBackupAgentName() { + return backupAgentName; + } + + @Override + public int getBannerResourceId() { + return banner; + } + + @NonNull + @Override + public String getBaseApkPath() { + return mBaseApkPath; + } + + @Override + public int getBaseRevisionCode() { + return baseRevisionCode; + } + + @Override + public int getCategory() { + return category; + } + + @Nullable + @Override + public String getClassLoaderName() { + return classLoaderName; + } + + @Nullable + @Override + public String getApplicationClassName() { + return className; + } + + @Override + public int getCompatibleWidthLimitDp() { + return compatibleWidthLimitDp; + } + + @Override + public int getCompileSdkVersion() { + return compileSdkVersion; + } + + @Nullable + @Override + public String getCompileSdkVersionCodeName() { + return compileSdkVersionCodeName; + } + + @NonNull + @Override + public List getConfigPreferences() { + return configPreferences; + } + + @Override + public int getDataExtractionRulesResourceId() { + return dataExtractionRules; + } + + @Override + public int getDescriptionResourceId() { + return descriptionRes; + } + + @NonNull + @Override + public List getFeatureGroups() { + return featureGroups; + } + + @Override + public int getFullBackupContentResourceId() { + return fullBackupContent; + } + + @ApplicationInfo.GwpAsanMode + @Override + public int getGwpAsanMode() { + return gwpAsanMode; + } + + @Override + public int getIconResourceId() { + return iconRes; + } + + @NonNull + @Override + public Set getImplicitPermissions() { + return implicitPermissions; + } + + @Override + public int getInstallLocation() { + return installLocation; + } + + @NonNull + @Override + public List getInstrumentations() { + return instrumentations; + } + + @NonNull + @Override + public Map> getKeySetMapping() { + return keySetMapping; + } + + @NonNull + @Override + public Set getKnownActivityEmbeddingCerts() { + return mKnownActivityEmbeddingCerts; + } + + @Override + public int getLabelResourceId() { + return labelRes; + } + + @Override + public int getLargestWidthLimitDp() { + return largestWidthLimitDp; + } + + @NonNull + @Override + public List getLibraryNames() { + return libraryNames; + } + + @Override + public int getLocaleConfigResourceId() { + return mLocaleConfigRes; + } + + @Override + public int getLogoResourceId() { + return logo; + } + + @Nullable + @Override + public String getManageSpaceActivityName() { + return manageSpaceActivityName; + } + + @Override + public float getMaxAspectRatio() { + return maxAspectRatio; + } + + @Override + public int getMaxSdkVersion() { + return maxSdkVersion; + } + + @ApplicationInfo.MemtagMode + @Override + public int getMemtagMode() { + return memtagMode; + } + + @Nullable + @Override + public Bundle getMetaData() { + return metaData; + } + + @Override + @Nullable + public Set getMimeGroups() { + return mimeGroups; + } + + @Override + public float getMinAspectRatio() { + return minAspectRatio; + } + + @Nullable + @Override + public SparseIntArray getMinExtensionVersions() { + return minExtensionVersions; + } + + @Override + public int getMinSdkVersion() { + return minSdkVersion; + } + + @ApplicationInfo.NativeHeapZeroInitialized + @Override + public int getNativeHeapZeroInitialized() { + return nativeHeapZeroInitialized; + } + + @Override + public int getNetworkSecurityConfigResourceId() { + return networkSecurityConfigRes; + } + + @Nullable + @Override + public CharSequence getNonLocalizedLabel() { + return nonLocalizedLabel; + } + + @NonNull + @Override + public List getOriginalPackages() { + return originalPackages; + } + + @Nullable + @Override + public String getOverlayCategory() { + return overlayCategory; + } + + @Override + public int getOverlayPriority() { + return overlayPriority; + } + + @Nullable + @Override + public String getOverlayTarget() { + return overlayTarget; + } + + @Nullable + @Override + public String getOverlayTargetOverlayableName() { + return overlayTargetOverlayableName; + } + + @NonNull + @Override + public Map getOverlayables() { + return overlayables; + } + + @NonNull + @Override + public String getPackageName() { + return packageName; + } + + @NonNull + @Override + public String getPath() { + return mPath; + } + + @Nullable + @Override + public String getPermission() { + return permission; + } + + @NonNull + @Override + public List getPermissionGroups() { + return permissionGroups; + } + + @NonNull + @Override + public List getPermissions() { + return permissions; + } + + @NonNull + @Override + public List> getPreferredActivityFilters() { + return preferredActivityFilters; + } + + @NonNull + @Override + public String getProcessName() { + return processName != null ? processName : packageName; + } + + @NonNull + @Override + public Map getProcesses() { + return processes; + } + + @NonNull + @Override + public Map getProperties() { + return mProperties; + } + + @NonNull + @Override + public List getProtectedBroadcasts() { + return protectedBroadcasts; + } + + @NonNull + @Override + public List getProviders() { + return providers; + } + + @NonNull + @Override + public List getQueriesIntents() { + return queriesIntents; + } + + @NonNull + @Override + public List getQueriesPackages() { + return queriesPackages; + } + + @NonNull + @Override + public Set getQueriesProviders() { + return queriesProviders; + } + + @NonNull + @Override + public List getReceivers() { + return receivers; + } + + @NonNull + @Override + public List getRequestedFeatures() { + return reqFeatures; + } + + /** + * @deprecated consider migrating to {@link #getUsesPermissions} which has + * more parsed details, such as flags + */ + @NonNull + @Override + @Deprecated + public Set getRequestedPermissions() { + return requestedPermissions; + } + + @Nullable + @Override + public String getRequiredAccountType() { + return requiredAccountType; + } + + @Override + public int getRequiresSmallestWidthDp() { + return requiresSmallestWidthDp; + } + + @Nullable + @Override + public Boolean getResizeableActivity() { + return resizeableActivity; + } + + @Nullable + @Override + public byte[] getRestrictUpdateHash() { + return restrictUpdateHash; + } + + @Nullable + @Override + public String getRestrictedAccountType() { + return restrictedAccountType; + } + + @Override + public int getRoundIconResourceId() { + return roundIconRes; + } + + @Nullable + @Override + public String getSdkLibraryName() { + return sdkLibraryName; + } + + @Override + public int getSdkLibVersionMajor() { + return sdkLibVersionMajor; + } + + @NonNull + @Override + public List getServices() { + return services; + } + + @Nullable + @Override + public String getSharedUserId() { + return sharedUserId; + } + + @Override + public int getSharedUserLabelResourceId() { + return sharedUserLabel; + } + + @NonNull + @Override + public SigningDetails getSigningDetails() { + return signingDetails; + } + + @NonNull + @Override + public String[] getSplitClassLoaderNames() { + return splitClassLoaderNames == null ? EmptyArray.STRING : splitClassLoaderNames; + } + + @NonNull + @Override + public String[] getSplitCodePaths() { + return splitCodePaths == null ? EmptyArray.STRING : splitCodePaths; + } + + @Nullable + @Override + public SparseArray getSplitDependencies() { + return splitDependencies == null ? EMPTY_INT_ARRAY_SPARSE_ARRAY : splitDependencies; + } + + @Nullable + @Override + public int[] getSplitFlags() { + return splitFlags; + } + + @NonNull + @Override + public String[] getSplitNames() { + return splitNames == null ? EmptyArray.STRING : splitNames; + } + + @NonNull + @Override + public int[] getSplitRevisionCodes() { + return splitRevisionCodes == null ? EmptyArray.INT : splitRevisionCodes; + } + + @Nullable + @Override + public String getStaticSharedLibraryName() { + return staticSharedLibraryName; + } + + @Override + public long getStaticSharedLibraryVersion() { + return staticSharedLibVersion; + } + + @Override + public UUID getStorageUuid() { + return mStorageUuid; + } + + @Override + public int getTargetSandboxVersion() { + return targetSandboxVersion; + } + + @Override + public int getTargetSdkVersion() { + return targetSdkVersion; + } + + @Nullable + @Override + public String getTaskAffinity() { + return taskAffinity; + } + + @Override + public int getThemeResourceId() { + return theme; + } + + @Override + public int getUiOptions() { + return uiOptions; + } + + @NonNull + @Override + public Set getUpgradeKeySets() { + return upgradeKeySets; + } + + @NonNull + @Override + public List getUsesLibraries() { + return usesLibraries; + } + + @NonNull + @Override + public String[] getUsesLibrariesSorted() { + if (mUsesLibrariesSorted == null) { + // Note lazy-sorting here doesn't break immutability because it always + // return the same content. In the case of multi-threading, data race in accessing + // mUsesLibrariesSorted might result in unnecessary creation of sorted copies + // which is OK because the case is quite rare. + mUsesLibrariesSorted = sortLibraries(usesLibraries); + } + return mUsesLibrariesSorted; + } + + @NonNull + @Override + public List getUsesNativeLibraries() { + return usesNativeLibraries; + } + + @NonNull + @Override + public List getUsesOptionalLibraries() { + return usesOptionalLibraries; + } + + @NonNull + @Override + public String[] getUsesOptionalLibrariesSorted() { + if (mUsesOptionalLibrariesSorted == null) { + mUsesOptionalLibrariesSorted = sortLibraries(usesOptionalLibraries); + } + return mUsesOptionalLibrariesSorted; + } + + @NonNull + @Override + public List getUsesOptionalNativeLibraries() { + return usesOptionalNativeLibraries; + } + + @NonNull + @Override + public List getUsesPermissions() { + return usesPermissions; + } + + @NonNull + @Override + public List getUsesSdkLibraries() { return usesSdkLibraries; } + + @NonNull + @Override + public String[] getUsesSdkLibrariesSorted() { + if (mUsesSdkLibrariesSorted == null) { + mUsesSdkLibrariesSorted = sortLibraries(usesSdkLibraries); + } + return mUsesSdkLibrariesSorted; + } + + @Nullable + @Override + public String[][] getUsesSdkLibrariesCertDigests() { return usesSdkLibrariesCertDigests; } + + @Nullable + @Override + public long[] getUsesSdkLibrariesVersionsMajor() { return usesSdkLibrariesVersionsMajor; } + + @Nullable + @Override + public boolean[] getUsesSdkLibrariesOptional() { + return usesSdkLibrariesOptional; + } + + @NonNull + @Override + public List getUsesStaticLibraries() { + return usesStaticLibraries; + } + + @NonNull + @Override + public String[] getUsesStaticLibrariesSorted() { + if (mUsesStaticLibrariesSorted == null) { + mUsesStaticLibrariesSorted = sortLibraries(usesStaticLibraries); + } + return mUsesStaticLibrariesSorted; + } + + @Nullable + @Override + public String[][] getUsesStaticLibrariesCertDigests() { + return usesStaticLibrariesCertDigests; + } + + @Nullable + @Override + public long[] getUsesStaticLibrariesVersions() { + return usesStaticLibrariesVersions; + } + + @Override + public int getVersionCode() { + return versionCode; + } + + @Override + public int getVersionCodeMajor() { + return versionCodeMajor; + } + + @Nullable + @Override + public String getVersionName() { + return versionName; + } + + @Nullable + @Override + public String getVolumeUuid() { + return volumeUuid; + } + + @Nullable + @Override + public String getZygotePreloadName() { + return zygotePreloadName; + } + + @Override + public boolean hasPreserveLegacyExternalStorage() { + return getBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE); + } + + @Override + public boolean hasRequestForegroundServiceExemption() { + return getBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION); + } + + @Nullable + @Override + public Boolean hasRequestRawExternalStorageAccess() { + return requestRawExternalStorageAccess; + } + + @Override + public boolean isAllowAudioPlaybackCapture() { + return getBoolean(Booleans.ALLOW_AUDIO_PLAYBACK_CAPTURE); + } + + @Override + public boolean isBackupAllowed() { + return getBoolean(Booleans.ALLOW_BACKUP); + } + + @Override + public boolean isClearUserDataAllowed() { + return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA); + } + + @Override + public boolean isClearUserDataOnFailedRestoreAllowed() { + return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE); + } + + @Override + public boolean isAllowNativeHeapPointerTagging() { + return getBoolean(Booleans.ALLOW_NATIVE_HEAP_POINTER_TAGGING); + } + + @Override + public boolean isTaskReparentingAllowed() { + return getBoolean(Booleans.ALLOW_TASK_REPARENTING); + } + + public boolean isAnyDensity() { + if (anyDensity == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return anyDensity; + } + + @Override + public boolean isBackupInForeground() { + return getBoolean(Booleans.BACKUP_IN_FOREGROUND); + } + + @Override + public boolean isHardwareAccelerated() { + return getBoolean(Booleans.HARDWARE_ACCELERATED); + } + + @Override + public boolean isSaveStateDisallowed() { + return getBoolean(Booleans.CANT_SAVE_STATE); + } + + @Override + public boolean isCrossProfile() { + return getBoolean(Booleans.CROSS_PROFILE); + } + + @Override + public boolean isDebuggable() { + return getBoolean(Booleans.DEBUGGABLE); + } + + @Override + public boolean isDefaultToDeviceProtectedStorage() { + return getBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE); + } + + @Override + public boolean isDirectBootAware() { + return getBoolean(Booleans.DIRECT_BOOT_AWARE); + } + + @Override + public boolean isEnabled() { + return getBoolean(Booleans.ENABLED); + } + + @Override + public boolean isExternalStorage() { + return getBoolean(Booleans.EXTERNAL_STORAGE); + } + + @Override + public boolean isExtractNativeLibrariesRequested() { + return getBoolean(Booleans.EXTRACT_NATIVE_LIBS); + } + + @Override + public boolean isForceQueryable() { + return getBoolean(Booleans.FORCE_QUERYABLE); + } + + @Override + public boolean isFullBackupOnly() { + return getBoolean(Booleans.FULL_BACKUP_ONLY); + } + + @Override + public boolean isGame() { + return getBoolean(Booleans.GAME); + } + + @Override + public boolean isDeclaredHavingCode() { + return getBoolean(Booleans.HAS_CODE); + } + + @Override + public boolean isHasDomainUrls() { + return getBoolean(Booleans.HAS_DOMAIN_URLS); + } + + @Override + public boolean isUserDataFragile() { + return getBoolean(Booleans.HAS_FRAGILE_USER_DATA); + } + + @Override + public boolean isIsolatedSplitLoading() { + return getBoolean(Booleans.ISOLATED_SPLIT_LOADING); + } + + @Override + public boolean isKillAfterRestoreAllowed() { + return getBoolean(Booleans.KILL_AFTER_RESTORE); + } + + @Override + public boolean isLargeHeap() { + return getBoolean(Booleans.LARGE_HEAP); + } + + @Override + public boolean isLeavingSharedUser() { + return getBoolean(Booleans.LEAVING_SHARED_UID); + } + + @Override + public boolean isMultiArch() { + return getBoolean(Booleans.MULTI_ARCH); + } + + @Override + public boolean isOnBackInvokedCallbackEnabled() { + return getBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK); + } + + @Override + public boolean isResourceOverlay() { + return getBoolean(Booleans.OVERLAY); + } + + @Override + public boolean isOverlayIsStatic() { + return getBoolean(Booleans.OVERLAY_IS_STATIC); + } + + @Override + public boolean isPartiallyDirectBootAware() { + return getBoolean(Booleans.PARTIALLY_DIRECT_BOOT_AWARE); + } + + @Override + public boolean isPersistent() { + return getBoolean(Booleans.PERSISTENT); + } + + @Override + public boolean isProfileable() { + return !getBoolean(Booleans.DISALLOW_PROFILING); + } + + @Override + public boolean isProfileableByShell() { + return isProfileable() && getBoolean(Booleans.PROFILEABLE_BY_SHELL); + } + + @Override + public boolean isRequestLegacyExternalStorage() { + return getBoolean(Booleans.REQUEST_LEGACY_EXTERNAL_STORAGE); + } + + @Override + public boolean isRequiredForAllUsers() { + return getBoolean(Booleans.REQUIRED_FOR_ALL_USERS); + } + + @Override + public boolean isResetEnabledSettingsOnAppDataCleared() { + return getBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED); + } + + public boolean isResizeable() { + if (resizeable == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return resizeable; + } + + @Override + public boolean isResizeableActivityViaSdkVersion() { + return getBoolean(Booleans.RESIZEABLE_ACTIVITY_VIA_SDK_VERSION); + } + + @Override + public boolean isRestoreAnyVersion() { + return getBoolean(Booleans.RESTORE_ANY_VERSION); + } + + @Override + public boolean isSdkLibrary() { + return getBoolean(Booleans.SDK_LIBRARY); + } + + @Override + public boolean isStaticSharedLibrary() { + return getBoolean(Booleans.STATIC_SHARED_LIBRARY); + } + + public boolean isExtraLargeScreensSupported() { + if (supportsExtraLargeScreens == null) { + return targetSdkVersion >= Build.VERSION_CODES.GINGERBREAD; + } + + return supportsExtraLargeScreens; + } + + public boolean isLargeScreensSupported() { + if (supportsLargeScreens == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return supportsLargeScreens; + } + + public boolean isNormalScreensSupported() { + return supportsNormalScreens == null || supportsNormalScreens; + } + + @Override + public boolean isRtlSupported() { + return getBoolean(Booleans.SUPPORTS_RTL); + } + + public boolean isSmallScreensSupported() { + if (supportsSmallScreens == null) { + return targetSdkVersion >= Build.VERSION_CODES.DONUT; + } + + return supportsSmallScreens; + } + + @Override + public boolean isTestOnly() { + return getBoolean(Booleans.TEST_ONLY); + } + + @Override + public boolean is32BitAbiPreferred() { + return getBoolean(Booleans.USE_32_BIT_ABI); + } + + @Override + public boolean isUseEmbeddedDex() { + return getBoolean(Booleans.USE_EMBEDDED_DEX); + } + + @Override + public boolean isCleartextTrafficAllowed() { + return getBoolean(Booleans.USES_CLEARTEXT_TRAFFIC); + } + + @Override + public boolean isNonSdkApiRequested() { + return getBoolean(Booleans.USES_NON_SDK_API); + } + + @Override + public boolean isVisibleToInstantApps() { + return getBoolean(Booleans.VISIBLE_TO_INSTANT_APPS); + } + + @Override + public boolean isVmSafeMode() { + return getBoolean(Booleans.VM_SAFE_MODE); + } + + @Override public PackageImpl removeUsesOptionalNativeLibrary(String libraryName) { + this.usesOptionalNativeLibraries = CollectionUtils.remove(this.usesOptionalNativeLibraries, + libraryName); + return this; + } + + @Override + public PackageImpl setAllowAudioPlaybackCapture(boolean value) { + return setBoolean(Booleans.ALLOW_AUDIO_PLAYBACK_CAPTURE, value); + } + + @Override + public PackageImpl setBackupAllowed(boolean value) { + return setBoolean(Booleans.ALLOW_BACKUP, value); + } + + @Override + public PackageImpl setClearUserDataAllowed(boolean value) { + return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA, value); + } + + @Override + public PackageImpl setClearUserDataOnFailedRestoreAllowed(boolean value) { + return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, value); + } + + @Override + public PackageImpl setAllowNativeHeapPointerTagging(boolean value) { + return setBoolean(Booleans.ALLOW_NATIVE_HEAP_POINTER_TAGGING, value); + } + + @Override + public PackageImpl setTaskReparentingAllowed(boolean value) { + return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value); + } + + @Override + public PackageImpl setAnyDensity(int anyDensity) { + if (anyDensity == 1) { + return this; + } + + this.anyDensity = anyDensity < 0; + return this; + } + + @Override + public PackageImpl setAppComponentFactory(@Nullable String appComponentFactory) { + this.appComponentFactory = appComponentFactory; + return this; + } + + @Override + public ParsingPackage setAttributionsAreUserVisible(boolean attributionsAreUserVisible) { + setBoolean(Booleans.ATTRIBUTIONS_ARE_USER_VISIBLE, attributionsAreUserVisible); + return this; + } + + @Override + public PackageImpl setAutoRevokePermissions(int value) { + autoRevokePermissions = value; + return this; + } + + @Override + public PackageImpl setBackupAgentName(@Nullable String backupAgentName) { + this.backupAgentName = backupAgentName; + return this; + } + + @Override + public PackageImpl setBackupInForeground(boolean value) { + return setBoolean(Booleans.BACKUP_IN_FOREGROUND, value); + } + + @Override + public PackageImpl setBannerResourceId(int value) { + banner = value; + return this; + } + + @Override + public PackageImpl setHardwareAccelerated(boolean value) { + return setBoolean(Booleans.HARDWARE_ACCELERATED, value); + } + + @Override + public PackageImpl setBaseRevisionCode(int value) { + baseRevisionCode = value; + return this; + } + + @Override + public PackageImpl setSaveStateDisallowed(boolean value) { + return setBoolean(Booleans.CANT_SAVE_STATE, value); + } + + @Override + public PackageImpl setCategory(int value) { + category = value; + return this; + } + + @Override + public PackageImpl setClassLoaderName(@Nullable String classLoaderName) { + this.classLoaderName = classLoaderName; + return this; + } + + @Override + public PackageImpl setApplicationClassName(@Nullable String className) { + this.className = className == null ? null : className.trim(); + return this; + } + + @Override + public PackageImpl setCompatibleWidthLimitDp(int value) { + compatibleWidthLimitDp = value; + return this; + } + + @Override + public PackageImpl setCompileSdkVersion(int value) { + compileSdkVersion = value; + return this; + } + + @Override + public ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName) { + this.compileSdkVersionCodeName = compileSdkVersionCodeName; + return this; + } + + @Override + public PackageImpl setCrossProfile(boolean value) { + return setBoolean(Booleans.CROSS_PROFILE, value); + } + + @Override + public PackageImpl setDataExtractionRulesResourceId(int value) { + dataExtractionRules = value; + return this; + } + + @Override + public PackageImpl setDebuggable(boolean value) { + return setBoolean(Booleans.DEBUGGABLE, value); + } + + @Override + public PackageImpl setDescriptionResourceId(int value) { + descriptionRes = value; + return this; + } + + @Override + public PackageImpl setEnabled(boolean value) { + return setBoolean(Booleans.ENABLED, value); + } + + @Override + public PackageImpl setExternalStorage(boolean value) { + return setBoolean(Booleans.EXTERNAL_STORAGE, value); + } + + @Override + public PackageImpl setExtractNativeLibrariesRequested(boolean value) { + return setBoolean(Booleans.EXTRACT_NATIVE_LIBS, value); + } + + @Override + public PackageImpl setForceQueryable(boolean value) { + return setBoolean(Booleans.FORCE_QUERYABLE, value); + } + + @Override + public PackageImpl setFullBackupContentResourceId(int value) { + fullBackupContent = value; + return this; + } + + @Override + public PackageImpl setFullBackupOnly(boolean value) { + return setBoolean(Booleans.FULL_BACKUP_ONLY, value); + } + + @Override + public PackageImpl setGame(boolean value) { + return setBoolean(Booleans.GAME, value); + } + + @Override + public PackageImpl setGwpAsanMode(@ApplicationInfo.GwpAsanMode int value) { + gwpAsanMode = value; + return this; + } + + @Override + public PackageImpl setDeclaredHavingCode(boolean value) { + return setBoolean(Booleans.HAS_CODE, value); + } + + @Override + public PackageImpl setHasDomainUrls(boolean value) { + return setBoolean(Booleans.HAS_DOMAIN_URLS, value); + } + + @Override + public PackageImpl setUserDataFragile(boolean value) { + return setBoolean(Booleans.HAS_FRAGILE_USER_DATA, value); + } + + @Override + public PackageImpl setIconResourceId(int value) { + iconRes = value; + return this; + } + + @Override + public PackageImpl setInstallLocation(int value) { + installLocation = value; + return this; + } + + @Override + public PackageImpl setIsolatedSplitLoading(boolean value) { + return setBoolean(Booleans.ISOLATED_SPLIT_LOADING, value); + } + + @Override + public PackageImpl setKillAfterRestoreAllowed(boolean value) { + return setBoolean(Booleans.KILL_AFTER_RESTORE, value); + } + + @Override + public ParsingPackage setKnownActivityEmbeddingCerts(@NonNull Set knownEmbeddingCerts) { + mKnownActivityEmbeddingCerts = knownEmbeddingCerts; + return this; + } + + @Override + public PackageImpl setLabelResourceId(int value) { + labelRes = value; + return this; + } + + @Override + public PackageImpl setLargeHeap(boolean value) { + return setBoolean(Booleans.LARGE_HEAP, value); + } + + @Override + public PackageImpl setLargestWidthLimitDp(int value) { + largestWidthLimitDp = value; + return this; + } + + @Override + public PackageImpl setLeavingSharedUser(boolean value) { + return setBoolean(Booleans.LEAVING_SHARED_UID, value); + } + + @Override + public PackageImpl setLocaleConfigResourceId(int value) { + mLocaleConfigRes = value; + return this; + } + + @Override + public PackageImpl setLogoResourceId(int value) { + logo = value; + return this; + } + + @Override + public PackageImpl setManageSpaceActivityName(@Nullable String manageSpaceActivityName) { + this.manageSpaceActivityName = manageSpaceActivityName; + return this; + } + + @Override + public PackageImpl setMaxAspectRatio(float value) { + maxAspectRatio = value; + return this; + } + + @Override + public PackageImpl setMaxSdkVersion(int value) { + maxSdkVersion = value; + return this; + } + + @Override + public PackageImpl setMemtagMode(@ApplicationInfo.MemtagMode int value) { + memtagMode = value; + return this; + } + + @Override + public PackageImpl setMetaData(@Nullable Bundle value) { + metaData = value; + return this; + } + + @Override + public PackageImpl setMinAspectRatio(float value) { + minAspectRatio = value; + return this; + } + + @Override + public PackageImpl setMinExtensionVersions(@Nullable SparseIntArray value) { + minExtensionVersions = value; + return this; + } + + @Override + public PackageImpl setMinSdkVersion(int value) { + minSdkVersion = value; + return this; + } + + @Override + public PackageImpl setMultiArch(boolean value) { + return setBoolean(Booleans.MULTI_ARCH, value); + } + + @Override + public PackageImpl setNativeHeapZeroInitialized( + @ApplicationInfo.NativeHeapZeroInitialized int value) { + nativeHeapZeroInitialized = value; + return this; + } + + @Override + public PackageImpl setNetworkSecurityConfigResourceId(int value) { + networkSecurityConfigRes = value; + return this; + } + + @Override + public PackageImpl setNonLocalizedLabel(@Nullable CharSequence value) { + nonLocalizedLabel = value == null ? null : value.toString().trim(); + return this; + } + + @Override + public ParsingPackage setOnBackInvokedCallbackEnabled(boolean value) { + setBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK, value); + return this; + } + + @Override + public PackageImpl setResourceOverlay(boolean value) { + return setBoolean(Booleans.OVERLAY, value); + } + + @Override + public PackageImpl setOverlayCategory(@Nullable String overlayCategory) { + this.overlayCategory = overlayCategory; + return this; + } + + @Override + public PackageImpl setOverlayIsStatic(boolean value) { + return setBoolean(Booleans.OVERLAY_IS_STATIC, value); + } + + @Override + public PackageImpl setOverlayPriority(int value) { + overlayPriority = value; + return this; + } + + @Override + public PackageImpl setOverlayTarget(@Nullable String overlayTarget) { + this.overlayTarget = TextUtils.safeIntern(overlayTarget); + return this; + } + + @Override + public PackageImpl setOverlayTargetOverlayableName( + @Nullable String overlayTargetOverlayableName) { + this.overlayTargetOverlayableName = overlayTargetOverlayableName; + return this; + } + + @Override + public PackageImpl setPartiallyDirectBootAware(boolean value) { + return setBoolean(Booleans.PARTIALLY_DIRECT_BOOT_AWARE, value); + } + + @Override + public PackageImpl setPermission(@Nullable String permission) { + this.permission = permission; + return this; + } + + @Override + public PackageImpl setPreserveLegacyExternalStorage(boolean value) { + return setBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE, value); + } + + @Override + public PackageImpl setProcessName(String processName) { + this.processName = processName; + return this; + } + + @Override + public PackageImpl setProcesses(@NonNull Map value) { + processes = value; + return this; + } + + @Override + public PackageImpl setProfileable(boolean value) { + return setBoolean(Booleans.DISALLOW_PROFILING, !value); + } + + @Override + public PackageImpl setProfileableByShell(boolean value) { + return setBoolean(Booleans.PROFILEABLE_BY_SHELL, value); + } + + @Override + public PackageImpl setRequestForegroundServiceExemption(boolean value) { + return setBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION, value); + } + + @Override + public PackageImpl setRequestLegacyExternalStorage(boolean value) { + return setBoolean(Booleans.REQUEST_LEGACY_EXTERNAL_STORAGE, value); + } + + @Override + public PackageImpl setRequestRawExternalStorageAccess(@Nullable Boolean value) { + requestRawExternalStorageAccess = value; + return this; + } + + @Override + public PackageImpl setRequiredAccountType(@Nullable String requiredAccountType) { + this.requiredAccountType = TextUtils.nullIfEmpty(requiredAccountType); + return this; + } + + @Override + public PackageImpl setRequiredForAllUsers(boolean value) { + return setBoolean(Booleans.REQUIRED_FOR_ALL_USERS, value); + } + + @Override + public PackageImpl setRequiresSmallestWidthDp(int value) { + requiresSmallestWidthDp = value; + return this; + } + + @Override + public ParsingPackage setResetEnabledSettingsOnAppDataCleared( + boolean resetEnabledSettingsOnAppDataCleared) { + setBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED, + resetEnabledSettingsOnAppDataCleared); + return this; + } + + @Override + public PackageImpl setResizeable(int resizeable) { + if (resizeable == 1) { + return this; + } + + this.resizeable = resizeable < 0; + return this; + } + + @Override + public PackageImpl setResizeableActivity(@Nullable Boolean value) { + resizeableActivity = value; + return this; + } + + @Override + public PackageImpl setResizeableActivityViaSdkVersion(boolean value) { + return setBoolean(Booleans.RESIZEABLE_ACTIVITY_VIA_SDK_VERSION, value); + } + + @Override + public PackageImpl setRestoreAnyVersion(boolean value) { + return setBoolean(Booleans.RESTORE_ANY_VERSION, value); + } + + @Override + public PackageImpl setRestrictedAccountType(@Nullable String restrictedAccountType) { + this.restrictedAccountType = restrictedAccountType; + return this; + } + + @Override + public PackageImpl setRoundIconResourceId(int value) { + roundIconRes = value; + return this; + } + + @Override + public PackageImpl setSdkLibraryName(String sdkLibraryName) { + this.sdkLibraryName = TextUtils.safeIntern(sdkLibraryName); + return this; + } + + @Override + public PackageImpl setSdkLibVersionMajor(int sdkLibVersionMajor) { + this.sdkLibVersionMajor = sdkLibVersionMajor; + return this; + } + + @Override + public PackageImpl setSdkLibrary(boolean value) { + return setBoolean(Booleans.SDK_LIBRARY, value); + } + + @Override + public PackageImpl setSharedUserId(String sharedUserId) { + this.sharedUserId = TextUtils.safeIntern(sharedUserId); + return this; + } + + @Override + public PackageImpl setSharedUserLabelResourceId(int value) { + sharedUserLabel = value; + return this; + } + + @Override + public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) { + this.splitClassLoaderNames[splitIndex] = classLoaderName; + return this; + } + + @Override + public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) { + this.splitFlags[splitIndex] = splitHasCode + ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE + : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE; + return this; + } + + @Override + public PackageImpl setStaticSharedLibraryName(String staticSharedLibraryName) { + this.staticSharedLibraryName = TextUtils.safeIntern(staticSharedLibraryName); + return this; + } + + @Override + public PackageImpl setStaticSharedLibraryVersion(long value) { + staticSharedLibVersion = value; + return this; + } + + @Override + public PackageImpl setStaticSharedLibrary(boolean value) { + return setBoolean(Booleans.STATIC_SHARED_LIBRARY, value); + } + + @Override + public PackageImpl setExtraLargeScreensSupported(int supportsExtraLargeScreens) { + if (supportsExtraLargeScreens == 1) { + return this; + } + + this.supportsExtraLargeScreens = supportsExtraLargeScreens < 0; + return this; + } + + @Override + public PackageImpl setLargeScreensSupported(int supportsLargeScreens) { + if (supportsLargeScreens == 1) { + return this; + } + + this.supportsLargeScreens = supportsLargeScreens < 0; + return this; + } + + @Override + public PackageImpl setNormalScreensSupported(int supportsNormalScreens) { + if (supportsNormalScreens == 1) { + return this; + } + + this.supportsNormalScreens = supportsNormalScreens < 0; + return this; + } + + @Override + public PackageImpl setRtlSupported(boolean value) { + return setBoolean(Booleans.SUPPORTS_RTL, value); + } + + @Override + public PackageImpl setSmallScreensSupported(int supportsSmallScreens) { + if (supportsSmallScreens == 1) { + return this; + } + + this.supportsSmallScreens = supportsSmallScreens < 0; + return this; + } + + @Override + public PackageImpl setTargetSandboxVersion(int value) { + targetSandboxVersion = value; + return this; + } + + @Override + public PackageImpl setTargetSdkVersion(int value) { + targetSdkVersion = value; + return this; + } + + @Override + public PackageImpl setTaskAffinity(@Nullable String taskAffinity) { + this.taskAffinity = taskAffinity; + return this; + } + + @Override + public PackageImpl setTestOnly(boolean value) { + return setBoolean(Booleans.TEST_ONLY, value); + } + + @Override + public PackageImpl setThemeResourceId(int value) { + theme = value; + return this; + } + + @Override + public PackageImpl setUiOptions(int value) { + uiOptions = value; + return this; + } + + @Override + public PackageImpl setUpgradeKeySets(@NonNull Set value) { + upgradeKeySets = value; + return this; + } + + @Override + public PackageImpl set32BitAbiPreferred(boolean value) { + return setBoolean(Booleans.USE_32_BIT_ABI, value); + } + + @Override + public PackageImpl setUseEmbeddedDex(boolean value) { + return setBoolean(Booleans.USE_EMBEDDED_DEX, value); + } + + @Override + public PackageImpl setCleartextTrafficAllowed(boolean value) { + return setBoolean(Booleans.USES_CLEARTEXT_TRAFFIC, value); + } + + @Override + public PackageImpl setNonSdkApiRequested(boolean value) { + return setBoolean(Booleans.USES_NON_SDK_API, value); + } + + @Override + public PackageImpl setVersionName(String versionName) { + this.versionName = versionName; + return this; + } + + @Override + public PackageImpl setVisibleToInstantApps(boolean value) { + return setBoolean(Booleans.VISIBLE_TO_INSTANT_APPS, value); + } + + @Override + public PackageImpl setVmSafeMode(boolean value) { + return setBoolean(Booleans.VM_SAFE_MODE, value); + } + + @Override + public PackageImpl setVolumeUuid(@Nullable String volumeUuid) { + this.volumeUuid = TextUtils.safeIntern(volumeUuid); + return this; + } + + @Override + public PackageImpl setZygotePreloadName(@Nullable String zygotePreloadName) { + this.zygotePreloadName = zygotePreloadName; + return this; + } + + @Override + public PackageImpl sortActivities() { + Collections.sort(this.activities, ORDER_COMPARATOR); + return this; + } + + @Override + public PackageImpl sortReceivers() { + Collections.sort(this.receivers, ORDER_COMPARATOR); + return this; + } + + @Override + public PackageImpl sortServices() { + Collections.sort(this.services, ORDER_COMPARATOR); + return this; + } + + public ApplicationInfo toAppInfoWithoutStateWithoutFlags() { + ApplicationInfo appInfo = new ApplicationInfo(); + + // Lines that are commented below are state related and should not be assigned here. + // They are left in as placeholders, since there is no good backwards compatible way to + // separate these. + appInfo.appComponentFactory = appComponentFactory; + appInfo.backupAgentName = backupAgentName; + appInfo.banner = banner; + appInfo.category = category; + appInfo.classLoaderName = classLoaderName; + appInfo.className = className; + appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp; + appInfo.compileSdkVersion = compileSdkVersion; + appInfo.compileSdkVersionCodename = compileSdkVersionCodeName; +// appInfo.credentialProtectedDataDir + appInfo.crossProfile = isCrossProfile(); +// appInfo.dataDir + appInfo.descriptionRes = descriptionRes; +// appInfo.deviceProtectedDataDir + appInfo.enabled = getBoolean(Booleans.ENABLED); +// appInfo.enabledSetting + appInfo.fullBackupContent = fullBackupContent; + appInfo.dataExtractionRulesRes = dataExtractionRules; + // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy +// appInfo.mHiddenApiPolicy +// appInfo.hiddenUntilInstalled + appInfo.icon = + (ParsingPackageUtils.sUseRoundIcon && roundIconRes != 0) ? roundIconRes : iconRes; + appInfo.iconRes = iconRes; + appInfo.roundIconRes = roundIconRes; + appInfo.installLocation = installLocation; + appInfo.labelRes = labelRes; + appInfo.largestWidthLimitDp = largestWidthLimitDp; + appInfo.logo = logo; + appInfo.manageSpaceActivityName = manageSpaceActivityName; + appInfo.maxAspectRatio = maxAspectRatio; + appInfo.metaData = metaData; + appInfo.minAspectRatio = minAspectRatio; + appInfo.minSdkVersion = minSdkVersion; + appInfo.name = className; +// appInfo.nativeLibraryDir +// appInfo.nativeLibraryRootDir +// appInfo.nativeLibraryRootRequiresIsa + appInfo.networkSecurityConfigRes = networkSecurityConfigRes; + appInfo.nonLocalizedLabel = nonLocalizedLabel; + appInfo.packageName = packageName; + appInfo.permission = permission; +// appInfo.primaryCpuAbi + appInfo.processName = getProcessName(); + appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp; +// appInfo.resourceDirs +// appInfo.secondaryCpuAbi +// appInfo.secondaryNativeLibraryDir +// appInfo.seInfo +// appInfo.seInfoUser +// appInfo.sharedLibraryFiles +// appInfo.sharedLibraryInfos +// appInfo.showUserIcon + appInfo.splitClassLoaderNames = splitClassLoaderNames; + appInfo.splitDependencies = (splitDependencies == null || splitDependencies.size() == 0) + ? null : splitDependencies; + appInfo.splitNames = splitNames; + appInfo.storageUuid = mStorageUuid; + appInfo.targetSandboxVersion = targetSandboxVersion; + appInfo.targetSdkVersion = targetSdkVersion; + appInfo.taskAffinity = taskAffinity; + appInfo.theme = theme; +// appInfo.uid + appInfo.uiOptions = uiOptions; + appInfo.volumeUuid = volumeUuid; + appInfo.zygotePreloadName = zygotePreloadName; + appInfo.setGwpAsanMode(gwpAsanMode); + appInfo.setMemtagMode(memtagMode); + appInfo.setNativeHeapZeroInitialized(nativeHeapZeroInitialized); + appInfo.setRequestRawExternalStorageAccess(requestRawExternalStorageAccess); + appInfo.setBaseCodePath(mBaseApkPath); + appInfo.setBaseResourcePath(mBaseApkPath); + appInfo.setCodePath(mPath); + appInfo.setResourcePath(mPath); + appInfo.setSplitCodePaths(ArrayUtils.size(splitCodePaths) == 0 ? null : splitCodePaths); + appInfo.setSplitResourcePaths(ArrayUtils.size(splitCodePaths) == 0 ? null : splitCodePaths); + appInfo.setVersionCode(mLongVersionCode); + appInfo.setAppClassNamesByProcess(buildAppClassNamesByProcess()); + appInfo.setLocaleConfigRes(mLocaleConfigRes); + if (!mKnownActivityEmbeddingCerts.isEmpty()) { + appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts); + } + + return appInfo; + } + + private PackageImpl setBoolean(@Booleans.Flags long flag, boolean value) { + if (value) { + mBooleans |= flag; + } else { + mBooleans &= ~flag; + } + return this; + } + + private boolean getBoolean(@Booleans.Flags long flag) { + return (mBooleans & flag) != 0; + } + + private PackageImpl setBoolean2(@Booleans2.Flags long flag, boolean value) { + if (value) { + mBooleans2 |= flag; + } else { + mBooleans2 &= ~flag; + } + return this; + } + + private boolean getBoolean2(@Booleans2.Flags long flag) { + return (mBooleans2 & flag) != 0; + } + + // Derived fields + private int mBaseAppInfoFlags; + private int mBaseAppInfoPrivateFlags; + private int mBaseAppInfoPrivateFlagsExt; + private String mBaseAppDataCredentialProtectedDirForSystemUser; + private String mBaseAppDataDeviceProtectedDirForSystemUser; + + ParsingPackageUtils.Callback mCallback; + + @VisibleForTesting + public PackageImpl(@NonNull String packageName, @NonNull String baseApkPath, + @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp, + @Nullable ParsingPackageUtils.Callback callback) { + this.packageName = TextUtils.safeIntern(packageName); + this.mBaseApkPath = baseApkPath; + this.mPath = path; + this.mCallback = callback; + + if (manifestArray != null) { + versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0); + versionCodeMajor = manifestArray.getInteger( + R.styleable.AndroidManifest_versionCodeMajor, 0); + setBaseRevisionCode( + manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, 0)); + setVersionName(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_versionName, 0)); + + setCompileSdkVersion(manifestArray.getInteger( + R.styleable.AndroidManifest_compileSdkVersion, 0)); + setCompileSdkVersionCodeName(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_compileSdkVersionCodename, 0)); + + setIsolatedSplitLoading(manifestArray.getBoolean( + R.styleable.AndroidManifest_isolatedSplits, false)); + + } + this.manifestPackageName = this.packageName; + setBoolean(Booleans.CORE_APP, isCoreApp); + } + + @Override + public PackageImpl hideAsParsed() { + assignDerivedFields(); + return this; + } + + @Override + public AndroidPackageInternal hideAsFinal() { + if (mStorageUuid == null) { + assignDerivedFields(); + } + assignDerivedFields2(); + makeImmutable(); + return this; + } + + private static String[] sortLibraries(List libraryNames) { + int size = libraryNames.size(); + if (size == 0) { + return EmptyArray.STRING; + } + var arr = libraryNames.toArray(EmptyArray.STRING); + Arrays.sort(arr); + return arr; + } + + private void assignDerivedFields2() { + mBaseAppInfoFlags = AppInfoUtils.appInfoFlags(this); + mBaseAppInfoPrivateFlags = AppInfoUtils.appInfoPrivateFlags(this); + mBaseAppInfoPrivateFlagsExt = AppInfoUtils.appInfoPrivateFlagsExt(this, + mCallback == null ? false : + mCallback.getHiddenApiWhitelistedApps().contains(this.packageName)); + String baseAppDataDir = Environment.getDataDirectoryPath(getVolumeUuid()) + File.separator; + String systemUserSuffix = File.separator + UserHandle.USER_SYSTEM + File.separator; + mBaseAppDataCredentialProtectedDirForSystemUser = TextUtils.safeIntern( + baseAppDataDir + Environment.DIR_USER_CE + systemUserSuffix); + mBaseAppDataDeviceProtectedDirForSystemUser = TextUtils.safeIntern( + baseAppDataDir + Environment.DIR_USER_DE + systemUserSuffix); + } + + private void makeImmutable() { + usesLibraries = Collections.unmodifiableList(usesLibraries); + usesOptionalLibraries = Collections.unmodifiableList(usesOptionalLibraries); + usesNativeLibraries = Collections.unmodifiableList(usesNativeLibraries); + usesOptionalNativeLibraries = Collections.unmodifiableList(usesOptionalNativeLibraries); + originalPackages = Collections.unmodifiableList(originalPackages); + adoptPermissions = Collections.unmodifiableList(adoptPermissions); + requestedPermissions = Collections.unmodifiableSet(requestedPermissions); + protectedBroadcasts = Collections.unmodifiableList(protectedBroadcasts); + apexSystemServices = Collections.unmodifiableList(apexSystemServices); + + activities = Collections.unmodifiableList(activities); + receivers = Collections.unmodifiableList(receivers); + services = Collections.unmodifiableList(services); + providers = Collections.unmodifiableList(providers); + permissions = Collections.unmodifiableList(permissions); + permissionGroups = Collections.unmodifiableList(permissionGroups); + instrumentations = Collections.unmodifiableList(instrumentations); + + overlayables = Collections.unmodifiableMap(overlayables); + libraryNames = Collections.unmodifiableList(libraryNames); + usesStaticLibraries = Collections.unmodifiableList(usesStaticLibraries); + usesSdkLibraries = Collections.unmodifiableList(usesSdkLibraries); + configPreferences = Collections.unmodifiableList(configPreferences); + reqFeatures = Collections.unmodifiableList(reqFeatures); + featureGroups = Collections.unmodifiableList(featureGroups); + usesPermissions = Collections.unmodifiableList(usesPermissions); + usesSdkLibraries = Collections.unmodifiableList(usesSdkLibraries); + implicitPermissions = Collections.unmodifiableSet(implicitPermissions); + upgradeKeySets = Collections.unmodifiableSet(upgradeKeySets); + keySetMapping = Collections.unmodifiableMap(keySetMapping); + attributions = Collections.unmodifiableList(attributions); + preferredActivityFilters = Collections.unmodifiableList(preferredActivityFilters); + processes = Collections.unmodifiableMap(processes); + mProperties = Collections.unmodifiableMap(mProperties); + queriesIntents = Collections.unmodifiableList(queriesIntents); + queriesPackages = Collections.unmodifiableList(queriesPackages); + queriesProviders = Collections.unmodifiableSet(queriesProviders); + mimeGroups = Collections.unmodifiableSet(mimeGroups); + mKnownActivityEmbeddingCerts = Collections.unmodifiableSet(mKnownActivityEmbeddingCerts); + } + + @Override + public long getLongVersionCode() { + return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); + } + + @Override + public PackageImpl removePermission(int index) { + this.permissions.remove(index); + return this; + } + + @Override + public PackageImpl addUsesOptionalLibrary(int index, String libraryName) { + this.usesOptionalLibraries = CollectionUtils.add(usesOptionalLibraries, index, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesLibrary(int index, String libraryName) { + this.usesLibraries = CollectionUtils.add(usesLibraries, index, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl removeUsesLibrary(String libraryName) { + this.usesLibraries = CollectionUtils.remove(this.usesLibraries, libraryName); + return this; + } + + @Override + public PackageImpl removeUsesOptionalLibrary(String libraryName) { + this.usesOptionalLibraries = CollectionUtils.remove(this.usesOptionalLibraries, + libraryName); + return this; + } + + @Override + public PackageImpl setSigningDetails(@NonNull SigningDetails value) { + signingDetails = value; + return this; + } + + @Override + public PackageImpl setRestrictUpdateHash(@Nullable byte... value) { + restrictUpdateHash = value; + return this; + } + + @Override + public PackageImpl setPersistent(boolean value) { + setBoolean(Booleans.PERSISTENT, value); + return this; + } + + @Override + public PackageImpl setDefaultToDeviceProtectedStorage(boolean value) { + setBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE, value); + return this; + } + + @Override + public PackageImpl setDirectBootAware(boolean value) { + setBoolean(Booleans.DIRECT_BOOT_AWARE, value); + return this; + } + + @Override + public PackageImpl clearProtectedBroadcasts() { + protectedBroadcasts.clear(); + return this; + } + + @Override + public PackageImpl clearOriginalPackages() { + originalPackages.clear(); + return this; + } + + @Override + public PackageImpl clearAdoptPermissions() { + adoptPermissions.clear(); + return this; + } + + @Override + public PackageImpl setPath(@NonNull String path) { + this.mPath = path; + return this; + } + + // TODO(b/135203078): Move PackageManagerService#renameStaticSharedLibraryPackage + // into initial package parsing + @Override + public PackageImpl setPackageName(@NonNull String packageName) { + this.packageName = TextUtils.safeIntern(packageName); + + int permissionsSize = permissions.size(); + for (int index = 0; index < permissionsSize; index++) { + ComponentMutateUtils.setPackageName(permissions.get(index), this.packageName); + } + + int permissionGroupsSize = permissionGroups.size(); + for (int index = 0; index < permissionGroupsSize; index++) { + ComponentMutateUtils.setPackageName(permissionGroups.get(index), this.packageName); + } + + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ComponentMutateUtils.setPackageName(activities.get(index), this.packageName); + } + + int receiversSize = receivers.size(); + for (int index = 0; index < receiversSize; index++) { + ComponentMutateUtils.setPackageName(receivers.get(index), this.packageName); + } + + int providersSize = providers.size(); + for (int index = 0; index < providersSize; index++) { + ComponentMutateUtils.setPackageName(providers.get(index), this.packageName); + } + + int servicesSize = services.size(); + for (int index = 0; index < servicesSize; index++) { + ComponentMutateUtils.setPackageName(services.get(index), this.packageName); + } + + int instrumentationsSize = instrumentations.size(); + for (int index = 0; index < instrumentationsSize; index++) { + ComponentMutateUtils.setPackageName(instrumentations.get(index), this.packageName); + } + + return this; + } + + @Override + public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) { + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ComponentMutateUtils.setDirectBootAware(activities.get(index), + allComponentsDirectBootAware); + } + + int receiversSize = receivers.size(); + for (int index = 0; index < receiversSize; index++) { + ComponentMutateUtils.setDirectBootAware(receivers.get(index), + allComponentsDirectBootAware); + } + + int providersSize = providers.size(); + for (int index = 0; index < providersSize; index++) { + ComponentMutateUtils.setDirectBootAware(providers.get(index), + allComponentsDirectBootAware); + } + + int servicesSize = services.size(); + for (int index = 0; index < servicesSize; index++) { + ComponentMutateUtils.setDirectBootAware(services.get(index), + allComponentsDirectBootAware); + } + + return this; + } + + @Override + public PackageImpl setBaseApkPath(@NonNull String baseApkPath) { + this.mBaseApkPath = TextUtils.safeIntern(baseApkPath); + return this; + } + + @Override + public PackageImpl setNativeLibraryDir(@Nullable String nativeLibraryDir) { + this.nativeLibraryDir = TextUtils.safeIntern(nativeLibraryDir); + return this; + } + + @Override + public PackageImpl setNativeLibraryRootDir(@Nullable String nativeLibraryRootDir) { + this.nativeLibraryRootDir = TextUtils.safeIntern(nativeLibraryRootDir); + return this; + } + + @Override + public PackageImpl setPrimaryCpuAbi(@Nullable String primaryCpuAbi) { + this.primaryCpuAbi = TextUtils.safeIntern(primaryCpuAbi); + return this; + } + + @Override + public PackageImpl setSecondaryCpuAbi(@Nullable String secondaryCpuAbi) { + this.secondaryCpuAbi = TextUtils.safeIntern(secondaryCpuAbi); + return this; + } + + @Override + public PackageImpl setSecondaryNativeLibraryDir(@Nullable String secondaryNativeLibraryDir) { + this.secondaryNativeLibraryDir = TextUtils.safeIntern(secondaryNativeLibraryDir); + return this; + } + + @Override + public PackageImpl setSplitCodePaths(@Nullable String[] splitCodePaths) { + this.splitCodePaths = splitCodePaths; + if (splitCodePaths != null) { + int size = splitCodePaths.length; + for (int index = 0; index < size; index++) { + this.splitCodePaths[index] = TextUtils.safeIntern(this.splitCodePaths[index]); + } + } + return this; + } + + @Override + public PackageImpl capPermissionPriorities() { + int size = permissionGroups.size(); + for (int index = size - 1; index >= 0; --index) { + // TODO(b/135203078): Builder/immutability + ComponentMutateUtils.setPriority(permissionGroups.get(index), 0); + } + return this; + } + + @Override + public PackageImpl markNotActivitiesAsNotExportedIfSingleUser() { + // ignore export request for single user receivers + int receiversSize = receivers.size(); + for (int index = 0; index < receiversSize; index++) { + ParsedActivity receiver = receivers.get(index); + if ((receiver.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { + ComponentMutateUtils.setExported(receiver, false); + } + } + + // ignore export request for single user services + int servicesSize = services.size(); + for (int index = 0; index < servicesSize; index++) { + ParsedService service = services.get(index); + if ((service.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { + ComponentMutateUtils.setExported(service, false); + } + } + + // ignore export request for single user providers + int providersSize = providers.size(); + for (int index = 0; index < providersSize; index++) { + ParsedProvider provider = providers.get(index); + if ((provider.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { + ComponentMutateUtils.setExported(provider, false); + } + } + + return this; + } + + @Override + public PackageImpl setCoreApp(boolean coreApp) { + return setBoolean(Booleans.CORE_APP, coreApp); + } + + @Override + public PackageImpl setVersionCode(int versionCode) { + this.versionCode = versionCode; + return this; + } + + @Override + public PackageImpl setVersionCodeMajor(int versionCodeMajor) { + this.versionCodeMajor = versionCodeMajor; + return this; + } + + @Override + public ApplicationInfo toAppInfoWithoutState() { + ApplicationInfo appInfo = toAppInfoWithoutStateWithoutFlags(); + appInfo.flags = mBaseAppInfoFlags; + appInfo.privateFlags = mBaseAppInfoPrivateFlags; + appInfo.privateFlagsExt = mBaseAppInfoPrivateFlagsExt; + appInfo.nativeLibraryDir = nativeLibraryDir; + appInfo.nativeLibraryRootDir = nativeLibraryRootDir; + appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; + appInfo.primaryCpuAbi = primaryCpuAbi; + appInfo.secondaryCpuAbi = secondaryCpuAbi; + appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + appInfo.seInfoUser = SEInfoUtil.COMPLETE_STR; + appInfo.uid = uid; + return appInfo; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + sForBoolean.parcel(this.supportsSmallScreens, dest, flags); + sForBoolean.parcel(this.supportsNormalScreens, dest, flags); + sForBoolean.parcel(this.supportsLargeScreens, dest, flags); + sForBoolean.parcel(this.supportsExtraLargeScreens, dest, flags); + sForBoolean.parcel(this.resizeable, dest, flags); + sForBoolean.parcel(this.anyDensity, dest, flags); + dest.writeInt(this.versionCode); + dest.writeInt(this.versionCodeMajor); + dest.writeInt(this.baseRevisionCode); + sForInternedString.parcel(this.versionName, dest, flags); + dest.writeInt(this.compileSdkVersion); + dest.writeString(this.compileSdkVersionCodeName); + sForInternedString.parcel(this.packageName, dest, flags); + dest.writeString(this.mBaseApkPath); + dest.writeString(this.restrictedAccountType); + dest.writeString(this.requiredAccountType); + sForInternedString.parcel(this.overlayTarget, dest, flags); + dest.writeString(this.overlayTargetOverlayableName); + dest.writeString(this.overlayCategory); + dest.writeInt(this.overlayPriority); + sForInternedStringValueMap.parcel(this.overlayables, dest, flags); + sForInternedString.parcel(this.sdkLibraryName, dest, flags); + dest.writeInt(this.sdkLibVersionMajor); + sForInternedString.parcel(this.staticSharedLibraryName, dest, flags); + dest.writeLong(this.staticSharedLibVersion); + sForInternedStringList.parcel(this.libraryNames, dest, flags); + sForInternedStringList.parcel(this.usesLibraries, dest, flags); + sForInternedStringList.parcel(this.usesOptionalLibraries, dest, flags); + sForInternedStringList.parcel(this.usesNativeLibraries, dest, flags); + sForInternedStringList.parcel(this.usesOptionalNativeLibraries, dest, flags); + + sForInternedStringList.parcel(this.usesStaticLibraries, dest, flags); + dest.writeLongArray(this.usesStaticLibrariesVersions); + if (this.usesStaticLibrariesCertDigests == null) { + dest.writeInt(-1); + } else { + dest.writeInt(this.usesStaticLibrariesCertDigests.length); + for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) { + dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]); + } + } + + sForInternedStringList.parcel(this.usesSdkLibraries, dest, flags); + dest.writeLongArray(this.usesSdkLibrariesVersionsMajor); + if (this.usesSdkLibrariesCertDigests == null) { + dest.writeInt(-1); + } else { + dest.writeInt(this.usesSdkLibrariesCertDigests.length); + for (int index = 0; index < this.usesSdkLibrariesCertDigests.length; index++) { + dest.writeStringArray(this.usesSdkLibrariesCertDigests[index]); + } + } + dest.writeBooleanArray(this.usesSdkLibrariesOptional); + + sForInternedString.parcel(this.sharedUserId, dest, flags); + dest.writeInt(this.sharedUserLabel); + dest.writeTypedList(this.configPreferences); + dest.writeTypedList(this.reqFeatures); + dest.writeTypedList(this.featureGroups); + dest.writeByteArray(this.restrictUpdateHash); + dest.writeStringList(this.originalPackages); + sForInternedStringList.parcel(this.adoptPermissions, dest, flags); + sForInternedStringSet.parcel(this.requestedPermissions, dest, flags); + ParsingUtils.writeParcelableList(dest, this.usesPermissions); + sForInternedStringSet.parcel(this.implicitPermissions, dest, flags); + sForStringSet.parcel(this.upgradeKeySets, dest, flags); + ParsingPackageUtils.writeKeySetMapping(dest, this.keySetMapping); + sForInternedStringList.parcel(this.protectedBroadcasts, dest, flags); + ParsingUtils.writeParcelableList(dest, this.activities); + ParsingUtils.writeParcelableList(dest, this.apexSystemServices); + ParsingUtils.writeParcelableList(dest, this.receivers); + ParsingUtils.writeParcelableList(dest, this.services); + ParsingUtils.writeParcelableList(dest, this.providers); + ParsingUtils.writeParcelableList(dest, this.attributions); + ParsingUtils.writeParcelableList(dest, this.permissions); + ParsingUtils.writeParcelableList(dest, this.permissionGroups); + ParsingUtils.writeParcelableList(dest, this.instrumentations); + sForIntentInfoPairs.parcel(this.preferredActivityFilters, dest, flags); + dest.writeMap(this.processes); + dest.writeBundle(this.metaData); + sForInternedString.parcel(this.volumeUuid, dest, flags); + dest.writeParcelable(this.signingDetails, flags); + dest.writeString(this.mPath); + dest.writeTypedList(this.queriesIntents, flags); + sForInternedStringList.parcel(this.queriesPackages, dest, flags); + sForInternedStringSet.parcel(this.queriesProviders, dest, flags); + dest.writeString(this.appComponentFactory); + dest.writeString(this.backupAgentName); + dest.writeInt(this.banner); + dest.writeInt(this.category); + dest.writeString(this.classLoaderName); + dest.writeString(this.className); + dest.writeInt(this.compatibleWidthLimitDp); + dest.writeInt(this.descriptionRes); + dest.writeInt(this.fullBackupContent); + dest.writeInt(this.dataExtractionRules); + dest.writeInt(this.iconRes); + dest.writeInt(this.installLocation); + dest.writeInt(this.labelRes); + dest.writeInt(this.largestWidthLimitDp); + dest.writeInt(this.logo); + dest.writeString(this.manageSpaceActivityName); + dest.writeFloat(this.maxAspectRatio); + dest.writeFloat(this.minAspectRatio); + dest.writeInt(this.minSdkVersion); + dest.writeInt(this.maxSdkVersion); + dest.writeInt(this.networkSecurityConfigRes); + dest.writeCharSequence(this.nonLocalizedLabel); + dest.writeString(this.permission); + dest.writeString(this.processName); + dest.writeInt(this.requiresSmallestWidthDp); + dest.writeInt(this.roundIconRes); + dest.writeInt(this.targetSandboxVersion); + dest.writeInt(this.targetSdkVersion); + dest.writeString(this.taskAffinity); + dest.writeInt(this.theme); + dest.writeInt(this.uiOptions); + dest.writeString(this.zygotePreloadName); + dest.writeStringArray(this.splitClassLoaderNames); + dest.writeStringArray(this.splitCodePaths); + dest.writeSparseArray(this.splitDependencies); + dest.writeIntArray(this.splitFlags); + dest.writeStringArray(this.splitNames); + dest.writeIntArray(this.splitRevisionCodes); + sForBoolean.parcel(this.resizeableActivity, dest, flags); + dest.writeInt(this.autoRevokePermissions); + sForInternedStringSet.parcel(this.mimeGroups, dest, flags); + dest.writeInt(this.gwpAsanMode); + dest.writeSparseIntArray(this.minExtensionVersions); + dest.writeMap(this.mProperties); + dest.writeInt(this.memtagMode); + dest.writeInt(this.nativeHeapZeroInitialized); + sForBoolean.parcel(this.requestRawExternalStorageAccess, dest, flags); + dest.writeInt(this.mLocaleConfigRes); + sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags); + sForInternedString.parcel(this.manifestPackageName, dest, flags); + dest.writeString(this.nativeLibraryDir); + dest.writeString(this.nativeLibraryRootDir); + dest.writeBoolean(this.nativeLibraryRootRequiresIsa); + sForInternedString.parcel(this.primaryCpuAbi, dest, flags); + sForInternedString.parcel(this.secondaryCpuAbi, dest, flags); + dest.writeString(this.secondaryNativeLibraryDir); + dest.writeInt(this.uid); + dest.writeLong(this.mBooleans); + dest.writeLong(this.mBooleans2); + } + + public PackageImpl(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.supportsSmallScreens = sForBoolean.unparcel(in); + this.supportsNormalScreens = sForBoolean.unparcel(in); + this.supportsLargeScreens = sForBoolean.unparcel(in); + this.supportsExtraLargeScreens = sForBoolean.unparcel(in); + this.resizeable = sForBoolean.unparcel(in); + this.anyDensity = sForBoolean.unparcel(in); + this.versionCode = in.readInt(); + this.versionCodeMajor = in.readInt(); + this.baseRevisionCode = in.readInt(); + this.versionName = sForInternedString.unparcel(in); + this.compileSdkVersion = in.readInt(); + this.compileSdkVersionCodeName = in.readString(); + this.packageName = sForInternedString.unparcel(in); + this.mBaseApkPath = in.readString(); + this.restrictedAccountType = in.readString(); + this.requiredAccountType = in.readString(); + this.overlayTarget = sForInternedString.unparcel(in); + this.overlayTargetOverlayableName = in.readString(); + this.overlayCategory = in.readString(); + this.overlayPriority = in.readInt(); + this.overlayables = sForInternedStringValueMap.unparcel(in); + this.sdkLibraryName = sForInternedString.unparcel(in); + this.sdkLibVersionMajor = in.readInt(); + this.staticSharedLibraryName = sForInternedString.unparcel(in); + this.staticSharedLibVersion = in.readLong(); + this.libraryNames = sForInternedStringList.unparcel(in); + this.usesLibraries = sForInternedStringList.unparcel(in); + this.usesOptionalLibraries = sForInternedStringList.unparcel(in); + this.usesNativeLibraries = sForInternedStringList.unparcel(in); + this.usesOptionalNativeLibraries = sForInternedStringList.unparcel(in); + + this.usesStaticLibraries = sForInternedStringList.unparcel(in); + this.usesStaticLibrariesVersions = in.createLongArray(); + { + int digestsSize = in.readInt(); + if (digestsSize >= 0) { + this.usesStaticLibrariesCertDigests = new String[digestsSize][]; + for (int index = 0; index < digestsSize; index++) { + this.usesStaticLibrariesCertDigests[index] = sForInternedStringArray.unparcel( + in); + } + } + } + + this.usesSdkLibraries = sForInternedStringList.unparcel(in); + this.usesSdkLibrariesVersionsMajor = in.createLongArray(); + { + int digestsSize = in.readInt(); + if (digestsSize >= 0) { + this.usesSdkLibrariesCertDigests = new String[digestsSize][]; + for (int index = 0; index < digestsSize; index++) { + this.usesSdkLibrariesCertDigests[index] = sForInternedStringArray.unparcel(in); + } + } + } + this.usesSdkLibrariesOptional = in.createBooleanArray(); + + this.sharedUserId = sForInternedString.unparcel(in); + this.sharedUserLabel = in.readInt(); + this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR); + this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR); + this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR); + this.restrictUpdateHash = in.createByteArray(); + this.originalPackages = in.createStringArrayList(); + this.adoptPermissions = sForInternedStringList.unparcel(in); + this.requestedPermissions = sForInternedStringSet.unparcel(in); + this.usesPermissions = ParsingUtils.createTypedInterfaceList(in, + ParsedUsesPermissionImpl.CREATOR); + this.implicitPermissions = sForInternedStringSet.unparcel(in); + this.upgradeKeySets = sForStringSet.unparcel(in); + this.keySetMapping = ParsingPackageUtils.readKeySetMapping(in); + this.protectedBroadcasts = sForInternedStringList.unparcel(in); + + this.activities = ParsingUtils.createTypedInterfaceList(in, ParsedActivityImpl.CREATOR); + this.apexSystemServices = ParsingUtils.createTypedInterfaceList(in, + ParsedApexSystemServiceImpl.CREATOR); + this.receivers = ParsingUtils.createTypedInterfaceList(in, ParsedActivityImpl.CREATOR); + this.services = ParsingUtils.createTypedInterfaceList(in, ParsedServiceImpl.CREATOR); + this.providers = ParsingUtils.createTypedInterfaceList(in, ParsedProviderImpl.CREATOR); + this.attributions = ParsingUtils.createTypedInterfaceList(in, + ParsedAttributionImpl.CREATOR); + this.permissions = ParsingUtils.createTypedInterfaceList(in, ParsedPermissionImpl.CREATOR); + this.permissionGroups = ParsingUtils.createTypedInterfaceList(in, + ParsedPermissionGroupImpl.CREATOR); + this.instrumentations = ParsingUtils.createTypedInterfaceList(in, + ParsedInstrumentationImpl.CREATOR); + this.preferredActivityFilters = sForIntentInfoPairs.unparcel(in); + this.processes = in.readHashMap(ParsedProcessImpl.class.getClassLoader()); + this.metaData = in.readBundle(boot); + this.volumeUuid = sForInternedString.unparcel(in); + this.signingDetails = in.readParcelable(boot, android.content.pm.SigningDetails.class); + this.mPath = in.readString(); + this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); + this.queriesPackages = sForInternedStringList.unparcel(in); + this.queriesProviders = sForInternedStringSet.unparcel(in); + this.appComponentFactory = in.readString(); + this.backupAgentName = in.readString(); + this.banner = in.readInt(); + this.category = in.readInt(); + this.classLoaderName = in.readString(); + this.className = in.readString(); + this.compatibleWidthLimitDp = in.readInt(); + this.descriptionRes = in.readInt(); + this.fullBackupContent = in.readInt(); + this.dataExtractionRules = in.readInt(); + this.iconRes = in.readInt(); + this.installLocation = in.readInt(); + this.labelRes = in.readInt(); + this.largestWidthLimitDp = in.readInt(); + this.logo = in.readInt(); + this.manageSpaceActivityName = in.readString(); + this.maxAspectRatio = in.readFloat(); + this.minAspectRatio = in.readFloat(); + this.minSdkVersion = in.readInt(); + this.maxSdkVersion = in.readInt(); + this.networkSecurityConfigRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.permission = in.readString(); + this.processName = in.readString(); + this.requiresSmallestWidthDp = in.readInt(); + this.roundIconRes = in.readInt(); + this.targetSandboxVersion = in.readInt(); + this.targetSdkVersion = in.readInt(); + this.taskAffinity = in.readString(); + this.theme = in.readInt(); + this.uiOptions = in.readInt(); + this.zygotePreloadName = in.readString(); + this.splitClassLoaderNames = in.createStringArray(); + this.splitCodePaths = in.createStringArray(); + this.splitDependencies = in.readSparseArray(boot); + this.splitFlags = in.createIntArray(); + this.splitNames = in.createStringArray(); + this.splitRevisionCodes = in.createIntArray(); + this.resizeableActivity = sForBoolean.unparcel(in); + + this.autoRevokePermissions = in.readInt(); + this.mimeGroups = sForInternedStringSet.unparcel(in); + this.gwpAsanMode = in.readInt(); + this.minExtensionVersions = in.readSparseIntArray(); + this.mProperties = in.readHashMap(boot); + this.memtagMode = in.readInt(); + this.nativeHeapZeroInitialized = in.readInt(); + this.requestRawExternalStorageAccess = sForBoolean.unparcel(in); + this.mLocaleConfigRes = in.readInt(); + this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in); + this.manifestPackageName = sForInternedString.unparcel(in); + this.nativeLibraryDir = in.readString(); + this.nativeLibraryRootDir = in.readString(); + this.nativeLibraryRootRequiresIsa = in.readBoolean(); + this.primaryCpuAbi = sForInternedString.unparcel(in); + this.secondaryCpuAbi = sForInternedString.unparcel(in); + this.secondaryNativeLibraryDir = in.readString(); + this.uid = in.readInt(); + this.mBooleans = in.readLong(); + this.mBooleans2 = in.readLong(); + + assignDerivedFields(); + assignDerivedFields2(); + + // Do not call makeImmutable here as cached parsing will need + // to mutate this instance before it's finalized. + } + + @NonNull + public static final Creator CREATOR = new Creator() { + @Override + public PackageImpl createFromParcel(Parcel source) { + return new PackageImpl(source); + } + + @Override + public PackageImpl[] newArray(int size) { + return new PackageImpl[size]; + } + }; + + @NonNull + @Override + public String getManifestPackageName() { + return manifestPackageName; + } + + public boolean isStub() { + return getBoolean2(Booleans2.STUB); + } + + @Nullable + @Override + public String getNativeLibraryDir() { + return nativeLibraryDir; + } + + @Nullable + @Override + public String getNativeLibraryRootDir() { + return nativeLibraryRootDir; + } + + @Override + public boolean isNativeLibraryRootRequiresIsa() { + return nativeLibraryRootRequiresIsa; + } + + @Nullable + @Override + public String getPrimaryCpuAbi() { + return primaryCpuAbi; + } + + @Nullable + @Override + public String getSecondaryCpuAbi() { + return secondaryCpuAbi; + } + + @Nullable + @Override + public String getSecondaryNativeLibraryDir() { + return secondaryNativeLibraryDir; + } + + @Override + public boolean isCoreApp() { + return getBoolean(Booleans.CORE_APP); + } + + @Override + public boolean isSystem() { + return getBoolean(Booleans.SYSTEM); + } + + @Override + public boolean isUpdatableSystem() { + return getBoolean2(Booleans2.UPDATABLE_SYSTEM); + } + + @Override + public boolean isFactoryTest() { + return getBoolean(Booleans.FACTORY_TEST); + } + + @Override + public boolean isApex() { + return getBoolean2(Booleans2.APEX); + } + + @Override + public boolean isSystemExt() { + return getBoolean(Booleans.SYSTEM_EXT); + } + + @Override + public boolean isPrivileged() { + return getBoolean(Booleans.PRIVILEGED); + } + + @Override + public boolean isOem() { + return getBoolean(Booleans.OEM); + } + + @Override + public boolean isVendor() { + return getBoolean(Booleans.VENDOR); + } + + @Override + public boolean isProduct() { + return getBoolean(Booleans.PRODUCT); + } + + @Override + public boolean isOdm() { + return getBoolean(Booleans.ODM); + } + + @Override + public boolean isSignedWithPlatformKey() { + return getBoolean(Booleans.SIGNED_WITH_PLATFORM_KEY); + } + + /** + * This is an appId, the uid if the userId is == USER_SYSTEM + */ + @Override + public int getUid() { + return uid; + } + + @Override + public PackageImpl setStub(boolean value) { + setBoolean2(Booleans2.STUB, value); + return this; + } + + @Override + public PackageImpl setNativeLibraryRootRequiresIsa(boolean value) { + nativeLibraryRootRequiresIsa = value; + return this; + } + + @Override + public PackageImpl setSystem(boolean value) { + setBoolean(Booleans.SYSTEM, value); + return this; + } + + @Override + public PackageImpl setUpdatableSystem(boolean value) { + return setBoolean2(Booleans2.UPDATABLE_SYSTEM, value); + } + + @Override + public PackageImpl setFactoryTest(boolean value) { + setBoolean(Booleans.FACTORY_TEST, value); + return this; + } + + @Override + public PackageImpl setApex(boolean isApex) { + setBoolean2(Booleans2.APEX, isApex); + return this; + } + + @Override + public PackageImpl setSystemExt(boolean value) { + setBoolean(Booleans.SYSTEM_EXT, value); + return this; + } + + @Override + public PackageImpl setPrivileged(boolean value) { + setBoolean(Booleans.PRIVILEGED, value); + return this; + } + + @Override + public PackageImpl setOem(boolean value) { + setBoolean(Booleans.OEM, value); + return this; + } + + @Override + public PackageImpl setVendor(boolean value) { + setBoolean(Booleans.VENDOR, value); + return this; + } + + @Override + public PackageImpl setProduct(boolean value) { + setBoolean(Booleans.PRODUCT, value); + return this; + } + + @Override + public PackageImpl setOdm(boolean value) { + setBoolean(Booleans.ODM, value); + return this; + } + + @Override + public PackageImpl setSignedWithPlatformKey(boolean value) { + setBoolean(Booleans.SIGNED_WITH_PLATFORM_KEY, value); + return this; + } + + @Override + public PackageImpl setUid(int value) { + uid = value; + return this; + } + + // The following methods are explicitly not inside any interface. These are hidden under + // PackageImpl which is only accessible to the system server. This is to prevent/discourage + // usage of these fields outside of the utility classes. + public String getBaseAppDataCredentialProtectedDirForSystemUser() { + return mBaseAppDataCredentialProtectedDirForSystemUser; + } + + public String getBaseAppDataDeviceProtectedDirForSystemUser() { + return mBaseAppDataDeviceProtectedDirForSystemUser; + } + + /** + * Flags used for a internal bitset. These flags should never be persisted or exposed outside + * of this class. It is expected that PackageCacher explicitly clears itself whenever the + * Parcelable implementation changes such that all these flags can be re-ordered or invalidated. + */ + private static class Booleans { + @LongDef({ + EXTERNAL_STORAGE, + HARDWARE_ACCELERATED, + ALLOW_BACKUP, + KILL_AFTER_RESTORE, + RESTORE_ANY_VERSION, + FULL_BACKUP_ONLY, + PERSISTENT, + DEBUGGABLE, + VM_SAFE_MODE, + HAS_CODE, + ALLOW_TASK_REPARENTING, + ALLOW_CLEAR_USER_DATA, + LARGE_HEAP, + USES_CLEARTEXT_TRAFFIC, + SUPPORTS_RTL, + TEST_ONLY, + MULTI_ARCH, + EXTRACT_NATIVE_LIBS, + GAME, + STATIC_SHARED_LIBRARY, + OVERLAY, + ISOLATED_SPLIT_LOADING, + HAS_DOMAIN_URLS, + PROFILEABLE_BY_SHELL, + BACKUP_IN_FOREGROUND, + USE_EMBEDDED_DEX, + DEFAULT_TO_DEVICE_PROTECTED_STORAGE, + DIRECT_BOOT_AWARE, + PARTIALLY_DIRECT_BOOT_AWARE, + RESIZEABLE_ACTIVITY_VIA_SDK_VERSION, + ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, + ALLOW_AUDIO_PLAYBACK_CAPTURE, + REQUEST_LEGACY_EXTERNAL_STORAGE, + USES_NON_SDK_API, + HAS_FRAGILE_USER_DATA, + CANT_SAVE_STATE, + ALLOW_NATIVE_HEAP_POINTER_TAGGING, + PRESERVE_LEGACY_EXTERNAL_STORAGE, + REQUIRED_FOR_ALL_USERS, + OVERLAY_IS_STATIC, + USE_32_BIT_ABI, + VISIBLE_TO_INSTANT_APPS, + FORCE_QUERYABLE, + CROSS_PROFILE, + ENABLED, + DISALLOW_PROFILING, + REQUEST_FOREGROUND_SERVICE_EXEMPTION, + ATTRIBUTIONS_ARE_USER_VISIBLE, + RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED, + SDK_LIBRARY, + CORE_APP, + SYSTEM, + FACTORY_TEST, + SYSTEM_EXT, + PRIVILEGED, + OEM, + VENDOR, + PRODUCT, + ODM, + SIGNED_WITH_PLATFORM_KEY, + NATIVE_LIBRARY_ROOT_REQUIRES_ISA, + }) + public @interface Flags {} + + private static final long EXTERNAL_STORAGE = 1L; + private static final long HARDWARE_ACCELERATED = 1L << 1; + private static final long ALLOW_BACKUP = 1L << 2; + private static final long KILL_AFTER_RESTORE = 1L << 3; + private static final long RESTORE_ANY_VERSION = 1L << 4; + private static final long FULL_BACKUP_ONLY = 1L << 5; + private static final long PERSISTENT = 1L << 6; + private static final long DEBUGGABLE = 1L << 7; + private static final long VM_SAFE_MODE = 1L << 8; + private static final long HAS_CODE = 1L << 9; + private static final long ALLOW_TASK_REPARENTING = 1L << 10; + private static final long ALLOW_CLEAR_USER_DATA = 1L << 11; + private static final long LARGE_HEAP = 1L << 12; + private static final long USES_CLEARTEXT_TRAFFIC = 1L << 13; + private static final long SUPPORTS_RTL = 1L << 14; + private static final long TEST_ONLY = 1L << 15; + private static final long MULTI_ARCH = 1L << 16; + private static final long EXTRACT_NATIVE_LIBS = 1L << 17; + private static final long GAME = 1L << 18; + private static final long STATIC_SHARED_LIBRARY = 1L << 19; + private static final long OVERLAY = 1L << 20; + private static final long ISOLATED_SPLIT_LOADING = 1L << 21; + private static final long HAS_DOMAIN_URLS = 1L << 22; + private static final long PROFILEABLE_BY_SHELL = 1L << 23; + private static final long BACKUP_IN_FOREGROUND = 1L << 24; + private static final long USE_EMBEDDED_DEX = 1L << 25; + private static final long DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1L << 26; + private static final long DIRECT_BOOT_AWARE = 1L << 27; + private static final long PARTIALLY_DIRECT_BOOT_AWARE = 1L << 28; + private static final long RESIZEABLE_ACTIVITY_VIA_SDK_VERSION = 1L << 29; + private static final long ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1L << 30; + private static final long ALLOW_AUDIO_PLAYBACK_CAPTURE = 1L << 31; + private static final long REQUEST_LEGACY_EXTERNAL_STORAGE = 1L << 32; + private static final long USES_NON_SDK_API = 1L << 33; + private static final long HAS_FRAGILE_USER_DATA = 1L << 34; + private static final long CANT_SAVE_STATE = 1L << 35; + private static final long ALLOW_NATIVE_HEAP_POINTER_TAGGING = 1L << 36; + private static final long PRESERVE_LEGACY_EXTERNAL_STORAGE = 1L << 37; + private static final long REQUIRED_FOR_ALL_USERS = 1L << 38; + private static final long OVERLAY_IS_STATIC = 1L << 39; + private static final long USE_32_BIT_ABI = 1L << 40; + private static final long VISIBLE_TO_INSTANT_APPS = 1L << 41; + private static final long FORCE_QUERYABLE = 1L << 42; + private static final long CROSS_PROFILE = 1L << 43; + private static final long ENABLED = 1L << 44; + private static final long DISALLOW_PROFILING = 1L << 45; + private static final long REQUEST_FOREGROUND_SERVICE_EXEMPTION = 1L << 46; + private static final long ATTRIBUTIONS_ARE_USER_VISIBLE = 1L << 47; + private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48; + private static final long SDK_LIBRARY = 1L << 49; + private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 50; + private static final long LEAVING_SHARED_UID = 1L << 51; + private static final long CORE_APP = 1L << 52; + private static final long SYSTEM = 1L << 53; + private static final long FACTORY_TEST = 1L << 54; + private static final long SYSTEM_EXT = 1L << 56; + private static final long PRIVILEGED = 1L << 57; + private static final long OEM = 1L << 58; + private static final long VENDOR = 1L << 59; + private static final long PRODUCT = 1L << 60; + private static final long ODM = 1L << 61; + private static final long SIGNED_WITH_PLATFORM_KEY = 1L << 62; + private static final long NATIVE_LIBRARY_ROOT_REQUIRES_ISA = 1L << 63; + } + + private static class Booleans2 { + @LongDef({ + STUB, + APEX, + UPDATABLE_SYSTEM, + }) + public @interface Flags {} + + private static final long STUB = 1L; + private static final long APEX = 1L << 1; + private static final long UPDATABLE_SYSTEM = 1L << 2; + } +} diff --git a/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java new file mode 100644 index 000000000000..a670c6d5aff4 --- /dev/null +++ b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2022 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.pm.permission; + +import android.Manifest; +import android.annotation.NonNull; + +import com.android.internal.util.DataClass; + +/** + * Implements compatibility support for permissions, and old applications + * will be automatically granted it. + * + * Compatibility permissions are permissions that are automatically granted to + * packages that target an SDK prior to when the permission was introduced. + * Sometimes the platform makes breaking behaviour changes and hides the legacy + * behaviour behind a permission. In these instances, we ensure applications + * targeting older platform versions are implicitly granted the correct set of + * permissions. + * + * @hide + */ +@DataClass(genGetters = true, genBuilder = false) +public class CompatibilityPermissionInfo { + + @NonNull + private final String mName; + private final int mSdkVersion; + + /** + * List of new permissions that have been added since 1.0. + * + * NOTE: These must be declared in SDK version order, with permissions + * added to newer SDKs appearing before those added to older SDKs. + * + * @hide + */ + public static final CompatibilityPermissionInfo[] COMPAT_PERMS = + new CompatibilityPermissionInfo[]{ + new CompatibilityPermissionInfo(Manifest.permission.POST_NOTIFICATIONS, + android.os.Build.VERSION_CODES.TIRAMISU), + new CompatibilityPermissionInfo(Manifest.permission.WRITE_EXTERNAL_STORAGE, + android.os.Build.VERSION_CODES.DONUT), + new CompatibilityPermissionInfo(Manifest.permission.READ_PHONE_STATE, + android.os.Build.VERSION_CODES.DONUT) + }; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public CompatibilityPermissionInfo( + @NonNull String name, + int sdkVersion) { + this.mName = name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mName); + this.mSdkVersion = sdkVersion; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull String getName() { + return mName; + } + + @DataClass.Generated.Member + public int getSdkVersion() { + return mSdkVersion; + } + + @DataClass.Generated( + time = 1701338392152L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java", + inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final com.android.internal.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/SEInfoUtil.java b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java new file mode 100644 index 000000000000..a6988829ca92 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.pm.pkg; + +/** + * Utility methods that need to be used in application space. + * @hide + */ +public final class SEInfoUtil { + + /** Append to existing seinfo label for instant apps @hide */ + public static final String INSTANT_APP_STR = ":ephemeralapp"; + + /** Append to existing seinfo when modifications are complete @hide */ + public static final String COMPLETE_STR = ":complete"; +} diff --git a/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java new file mode 100644 index 000000000000..fd5f0f079da9 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** + * Contains mutation methods so that code doesn't have to cast to the Impl. Meant to eventually + * be removed once all post-parsing mutation is moved to parsing. + * + * @hide + */ +public class ComponentMutateUtils { + + public static void setMaxAspectRatio(@NonNull ParsedActivity activity, int resizeMode, + float maxAspectRatio) { + ((ParsedActivityImpl) activity).setMaxAspectRatio(resizeMode, maxAspectRatio); + } + + public static void setMinAspectRatio(@NonNull ParsedActivity activity, int resizeMode, + float minAspectRatio) { + ((ParsedActivityImpl) activity).setMinAspectRatio(resizeMode, minAspectRatio); + } + + public static void setSupportsSizeChanges(@NonNull ParsedActivity activity, + boolean supportsSizeChanges) { + ((ParsedActivityImpl) activity).setSupportsSizeChanges(supportsSizeChanges); + } + + public static void setResizeMode(@NonNull ParsedActivity activity, int resizeMode) { + ((ParsedActivityImpl) activity).setResizeMode(resizeMode); + } + + public static void setExactFlags(ParsedComponent component, int exactFlags) { + ((ParsedComponentImpl) component).setFlags(exactFlags); + } + + public static void setEnabled(@NonNull ParsedMainComponent component, boolean enabled) { + ((ParsedMainComponentImpl) component).setEnabled(enabled); + } + + public static void setPackageName(@NonNull ParsedComponent component, + @NonNull String packageName) { + ((ParsedComponentImpl) component).setPackageName(packageName); + } + + public static void setDirectBootAware(@NonNull ParsedMainComponent component, + boolean directBootAware) { + ((ParsedMainComponentImpl) component).setDirectBootAware(directBootAware); + } + + public static void setExported(@NonNull ParsedMainComponent component, boolean exported) { + ((ParsedMainComponentImpl) component).setExported(exported); + } + + public static void setAuthority(@NonNull ParsedProvider provider, @Nullable String authority) { + ((ParsedProviderImpl) provider).setAuthority(authority); + } + + public static void setSyncable(@NonNull ParsedProvider provider, boolean syncable) { + ((ParsedProviderImpl) provider).setSyncable(syncable); + } + + public static void setProtectionLevel(@NonNull ParsedPermission permission, + int protectionLevel) { + ((ParsedPermissionImpl) permission).setProtectionLevel(protectionLevel); + } + + public static void setParsedPermissionGroup(@NonNull ParsedPermission permission, + @NonNull ParsedPermissionGroup permissionGroup) { + ((ParsedPermissionImpl) permission).setParsedPermissionGroup(permissionGroup); + } + + public static void setPriority(@NonNull ParsedPermissionGroup parsedPermissionGroup, + int priority) { + ((ParsedPermissionGroupImpl) parsedPermissionGroup).setPriority(priority); + } + + public static void addStateFrom(@NonNull ParsedProcess oldProcess, + @NonNull ParsedProcess newProcess) { + ((ParsedProcessImpl) oldProcess).addStateFrom(newProcess); + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java new file mode 100644 index 000000000000..db08005c833e --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.AttrRes; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.parsing.FrameworkParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.text.TextUtils; + +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** + * @hide + */ +public class ComponentParseUtils { + + public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) { + IntentFilter intentFilter = intentInfo.getIntentFilter(); + return intentFilter.hasCategory(Intent.CATEGORY_BROWSABLE) + || intentFilter.hasAction(Intent.ACTION_SEND) + || intentFilter.hasAction(Intent.ACTION_SENDTO) + || intentFilter.hasAction(Intent.ACTION_SEND_MULTIPLE); + } + + static ParseResult parseAllMetaData( + ParsingPackage pkg, Resources res, XmlResourceParser parser, String tag, + Component component, ParseInput input) throws XmlPullParserException, IOException { + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + if ("meta-data".equals(parser.getName())) { + result = ParsedComponentUtils.addMetaData(component, pkg, res, parser, input); + } else { + result = ParsingUtils.unknownTag(tag, pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + + return input.success(component); + } + + @NonNull + public static ParseResult buildProcessName(@NonNull String pkg, String defProc, + CharSequence procSeq, int flags, String[] separateProcesses, ParseInput input) { + if ((flags & ParsingPackageUtils.PARSE_IGNORE_PROCESSES) != 0 && !"system".contentEquals( + procSeq)) { + return input.success(defProc != null ? defProc : pkg); + } + if (separateProcesses != null) { + for (int i = separateProcesses.length - 1; i >= 0; i--) { + String sp = separateProcesses[i]; + if (sp.equals(pkg) || sp.equals(defProc) || sp.contentEquals(procSeq)) { + return input.success(pkg); + } + } + } + if (procSeq == null || procSeq.length() <= 0) { + return input.success(defProc); + } + + ParseResult nameResult = ComponentParseUtils.buildCompoundName(pkg, procSeq, + "process", input); + return input.success(TextUtils.safeIntern(nameResult.getResult())); + } + + @NonNull + public static ParseResult buildTaskAffinityName(String pkg, String defProc, + CharSequence procSeq, ParseInput input) { + if (procSeq == null) { + return input.success(defProc); + } + if (procSeq.length() <= 0) { + return input.success(null); + } + return buildCompoundName(pkg, procSeq, "taskAffinity", input); + } + + public static ParseResult buildCompoundName(String pkg, CharSequence procSeq, + String type, ParseInput input) { + String proc = procSeq.toString(); + char c = proc.charAt(0); + if (pkg != null && c == ':') { + if (proc.length() < 2) { + return input.error("Bad " + type + " name " + proc + " in package " + pkg + + ": must be at least two characters"); + } + String subName = proc.substring(1); + final ParseResult nameResult = FrameworkParsingPackageUtils.validateName(input, + subName, false, false); + if (nameResult.isError()) { + return input.error("Invalid " + type + " name " + proc + " in package " + pkg + + ": " + nameResult.getErrorMessage()); + } + return input.success(pkg + proc); + } + if (!"system".equals(proc)) { + final ParseResult nameResult = FrameworkParsingPackageUtils.validateName(input, proc, + true, false); + if (nameResult.isError()) { + return input.error("Invalid " + type + " name " + proc + " in package " + pkg + + ": " + nameResult.getErrorMessage()); + } + } + return input.success(proc); + } + + public static int flag(int flag, @AttrRes int attribute, TypedArray typedArray) { + return typedArray.getBoolean(attribute, false) ? flag : 0; + } + + public static int flag(int flag, @AttrRes int attribute, boolean defaultValue, + TypedArray typedArray) { + return typedArray.getBoolean(attribute, defaultValue) ? flag : 0; + } + + /** + * This is not state aware. Avoid and access through PackageInfoUtils in the system server. + */ + @Nullable + public static CharSequence getNonLocalizedLabel( + ParsedComponent component) { + return component.getNonLocalizedLabel(); + } + + /** + * This is not state aware. Avoid and access through PackageInfoUtils in the system server. + *

+ * This is a method of the utility class to discourage use. + */ + public static int getIcon(ParsedComponent component) { + return component.getIcon(); + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java new file mode 100644 index 000000000000..0b045919fb13 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + + +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.util.ArraySet; + +import com.android.internal.R; +import com.android.internal.pm.pkg.parsing.ParsingPackage; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Set; + +/** + * Utility methods for handling the tag {@code } + * + * @hide + */ +public class InstallConstraintsTagParser { + + private static final String TAG_FINGERPRINT_PREFIX = "fingerprint-prefix"; + + /** + * @hide + */ + public static ParseResult parseInstallConstraints( + ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, + Set allowlist) throws XmlPullParserException, IOException { + if (!allowlist.contains(pkg.getPackageName())) { + return input.skip("install-constraints cannot be used by this package"); + } + + ParseResult> prefixes = parseFingerprintPrefixes(input, res, parser); + if (prefixes.isSuccess()) { + if (validateFingerprintPrefixes(prefixes.getResult())) { + return input.success(pkg); + } else { + return input.skip( + "Install of this package is restricted on this device; device fingerprint" + + " does not start with one of the allowed prefixes"); + } + } + return input.skip(prefixes.getErrorMessage()); + } + + private static ParseResult> parseFingerprintPrefixes( + ParseInput input, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + Set prefixes = new ArraySet<>(); + int type; + while (true) { + // move to the tag that contains the next prefix + type = parser.next(); + if (type == XmlPullParser.END_TAG) { + if (prefixes.size() == 0) { + return input.error("install-constraints must contain at least one constraint"); + } + return input.success(prefixes); + } else if (type == XmlPullParser.START_TAG) { + if (parser.getName().equals(TAG_FINGERPRINT_PREFIX)) { + ParseResult parsedPrefix = + readFingerprintPrefixValue(input, res, parser); + if (parsedPrefix.isSuccess()) { + prefixes.add(parsedPrefix.getResult()); + } else { + return input.error(parsedPrefix.getErrorMessage()); + } + } else { + return input.error("Unexpected tag: " + parser.getName()); + } + + // consume the end tag of this attribute + type = parser.next(); + if (type != XmlPullParser.END_TAG) { + return input.error("Expected end tag; instead got " + type); + } + } + } + } + + private static ParseResult readFingerprintPrefixValue(ParseInput input, Resources res, + XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestInstallConstraintsFingerprintPrefix); + try { + String value = sa.getString( + R.styleable.AndroidManifestInstallConstraintsFingerprintPrefix_value); + if (value == null) { + return input.error("Failed to specify prefix value"); + } + return input.success(value); + } finally { + sa.recycle(); + } + } + + private static boolean validateFingerprintPrefixes(Set prefixes) { + String fingerprint = Build.FINGERPRINT; + for (String prefix : prefixes) { + if (fingerprint.startsWith(prefix)) { + return true; + } + } + return false; + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java new file mode 100644 index 000000000000..2f977eea127d --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java @@ -0,0 +1,709 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; + +import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString; +import static com.android.internal.pm.parsing.pkg.PackageImpl.sForStringSet; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityTaskManager; +import android.content.ComponentName; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; +import android.util.ArraySet; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +import java.util.Collections; +import java.util.Locale; +import java.util.Set; + +/** + * @hide + **/ +@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) +public class ParsedActivityImpl extends ParsedMainComponentImpl implements ParsedActivity, + Parcelable { + + private int theme; + private int uiOptions; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String targetActivity; + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String parentActivityName; + @Nullable + private String taskAffinity; + private int privateFlags; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String permission; + @Nullable + private Set mKnownActivityEmbeddingCerts; + + private int launchMode; + private int documentLaunchMode; + private int maxRecents; + private int configChanges; + private int softInputMode; + private int persistableMode; + private int lockTaskLaunchMode; + + private int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + private int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + + private float maxAspectRatio = ParsingUtils.NOT_SET; + private float minAspectRatio = ParsingUtils.NOT_SET; + + private boolean supportsSizeChanges; + + @Nullable + private String requestedVrComponent; + private int rotationAnimation = -1; + private int colorMode; + + @Nullable + private ActivityInfo.WindowLayout windowLayout; + + @Nullable + private String mRequiredDisplayCategory; + + public ParsedActivityImpl(ParsedActivityImpl other) { + super(other); + this.theme = other.theme; + this.uiOptions = other.uiOptions; + this.targetActivity = other.targetActivity; + this.parentActivityName = other.parentActivityName; + this.taskAffinity = other.taskAffinity; + this.privateFlags = other.privateFlags; + this.permission = other.permission; + this.launchMode = other.launchMode; + this.documentLaunchMode = other.documentLaunchMode; + this.maxRecents = other.maxRecents; + this.configChanges = other.configChanges; + this.softInputMode = other.softInputMode; + this.persistableMode = other.persistableMode; + this.lockTaskLaunchMode = other.lockTaskLaunchMode; + this.screenOrientation = other.screenOrientation; + this.resizeMode = other.resizeMode; + this.maxAspectRatio = other.maxAspectRatio; + this.minAspectRatio = other.minAspectRatio; + this.supportsSizeChanges = other.supportsSizeChanges; + this.requestedVrComponent = other.requestedVrComponent; + this.rotationAnimation = other.rotationAnimation; + this.colorMode = other.colorMode; + this.windowLayout = other.windowLayout; + this.mKnownActivityEmbeddingCerts = other.mKnownActivityEmbeddingCerts; + this.mRequiredDisplayCategory = other.mRequiredDisplayCategory; + } + + /** + * Generate activity object that forwards user to App Details page automatically. This activity + * should be invisible to user and user should not know or see it. + */ + @NonNull + public static ParsedActivityImpl makeAppDetailsActivity(String packageName, String processName, + int uiOptions, String taskAffinity, boolean hardwareAccelerated) { + ParsedActivityImpl activity = new ParsedActivityImpl(); + activity.setPackageName(packageName); + activity.theme = android.R.style.Theme_NoDisplay; + activity.setExported(true); + activity.setName(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME); + activity.setProcessName(processName); + activity.uiOptions = uiOptions; + activity.taskAffinity = taskAffinity; + activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE; + activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic(); + activity.configChanges = ParsedActivityUtils.getActivityConfigChanges(0, 0); + activity.softInputMode = 0; + activity.persistableMode = ActivityInfo.PERSIST_NEVER; + activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; + activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; + activity.lockTaskLaunchMode = 0; + activity.setDirectBootAware(false); + activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; + activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; + if (hardwareAccelerated) { + activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_HARDWARE_ACCELERATED); + } + return activity; + } + + @NonNull + static ParsedActivityImpl makeAlias(String targetActivityName, ParsedActivity target) { + ParsedActivityImpl alias = new ParsedActivityImpl(); + alias.setPackageName(target.getPackageName()); + alias.setTargetActivity(targetActivityName); + alias.configChanges = target.getConfigChanges(); + alias.setFlags(target.getFlags()); + alias.privateFlags = target.getPrivateFlags(); + alias.setIcon(target.getIcon()); + alias.setLogo(target.getLogo()); + alias.setBanner(target.getBanner()); + alias.setLabelRes(target.getLabelRes()); + alias.setNonLocalizedLabel(target.getNonLocalizedLabel()); + alias.launchMode = target.getLaunchMode(); + alias.lockTaskLaunchMode = target.getLockTaskLaunchMode(); + alias.documentLaunchMode = target.getDocumentLaunchMode(); + alias.setDescriptionRes(target.getDescriptionRes()); + alias.screenOrientation = target.getScreenOrientation(); + alias.taskAffinity = target.getTaskAffinity(); + alias.theme = target.getTheme(); + alias.softInputMode = target.getSoftInputMode(); + alias.uiOptions = target.getUiOptions(); + alias.parentActivityName = target.getParentActivityName(); + alias.maxRecents = target.getMaxRecents(); + alias.windowLayout = target.getWindowLayout(); + alias.resizeMode = target.getResizeMode(); + alias.maxAspectRatio = target.getMaxAspectRatio(); + alias.minAspectRatio = target.getMinAspectRatio(); + alias.supportsSizeChanges = target.isSupportsSizeChanges(); + alias.requestedVrComponent = target.getRequestedVrComponent(); + alias.setDirectBootAware(target.isDirectBootAware()); + alias.setProcessName(target.getProcessName()); + alias.setRequiredDisplayCategory(target.getRequiredDisplayCategory()); + return alias; + + // Not all attributes from the target ParsedActivity are copied to the alias. + // Careful when adding an attribute and determine whether or not it should be copied. +// alias.enabled = target.enabled; +// alias.exported = target.exported; +// alias.permission = target.permission; +// alias.splitName = target.splitName; +// alias.persistableMode = target.persistableMode; +// alias.rotationAnimation = target.rotationAnimation; +// alias.colorMode = target.colorMode; +// alias.intents.addAll(target.intents); +// alias.order = target.order; +// alias.metaData = target.metaData; + } + + public ParsedActivityImpl setMaxAspectRatio(int resizeMode, float maxAspectRatio) { + if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE + || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return this; + } + + if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return this; + } + + this.maxAspectRatio = maxAspectRatio; + return this; + } + + public ParsedActivityImpl setMinAspectRatio(int resizeMode, float minAspectRatio) { + if (resizeMode == RESIZE_MODE_RESIZEABLE + || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return this; + } + + if (minAspectRatio < 1.0f && minAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return this; + } + + this.minAspectRatio = minAspectRatio; + return this; + } + + public ParsedActivityImpl setTargetActivity(String targetActivity) { + this.targetActivity = TextUtils.safeIntern(targetActivity); + return this; + } + + public ParsedActivityImpl setPermission(String permission) { + // Empty string must be converted to null + this.permission = TextUtils.isEmpty(permission) ? null : permission.intern(); + return this; + } + + @NonNull + @Override + public Set getKnownActivityEmbeddingCerts() { + return mKnownActivityEmbeddingCerts == null ? Collections.emptySet() + : mKnownActivityEmbeddingCerts; + } + + /** + * Sets the trusted host certificates of apps that are allowed to embed this activity. + */ + public void setKnownActivityEmbeddingCerts(@NonNull Set knownActivityEmbeddingCerts) { + // Convert the provided digest to upper case for consistent Set membership + // checks when verifying the signing certificate digests of requesting apps. + this.mKnownActivityEmbeddingCerts = new ArraySet<>(); + for (String knownCert : knownActivityEmbeddingCerts) { + this.mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US)); + } + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Activity{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.theme); + dest.writeInt(this.uiOptions); + dest.writeString(this.targetActivity); + dest.writeString(this.parentActivityName); + dest.writeString(this.taskAffinity); + dest.writeInt(this.privateFlags); + sForInternedString.parcel(this.permission, dest, flags); + dest.writeInt(this.launchMode); + dest.writeInt(this.documentLaunchMode); + dest.writeInt(this.maxRecents); + dest.writeInt(this.configChanges); + dest.writeInt(this.softInputMode); + dest.writeInt(this.persistableMode); + dest.writeInt(this.lockTaskLaunchMode); + dest.writeInt(this.screenOrientation); + dest.writeInt(this.resizeMode); + dest.writeValue(this.maxAspectRatio); + dest.writeValue(this.minAspectRatio); + dest.writeBoolean(this.supportsSizeChanges); + dest.writeString(this.requestedVrComponent); + dest.writeInt(this.rotationAnimation); + dest.writeInt(this.colorMode); + dest.writeBundle(this.getMetaData()); + + if (windowLayout != null) { + dest.writeInt(1); + windowLayout.writeToParcel(dest); + } else { + dest.writeBoolean(false); + } + sForStringSet.parcel(this.mKnownActivityEmbeddingCerts, dest, flags); + dest.writeString8(this.mRequiredDisplayCategory); + } + + public ParsedActivityImpl() { + } + + protected ParsedActivityImpl(Parcel in) { + super(in); + this.theme = in.readInt(); + this.uiOptions = in.readInt(); + this.targetActivity = in.readString(); + this.parentActivityName = in.readString(); + this.taskAffinity = in.readString(); + this.privateFlags = in.readInt(); + this.permission = sForInternedString.unparcel(in); + this.launchMode = in.readInt(); + this.documentLaunchMode = in.readInt(); + this.maxRecents = in.readInt(); + this.configChanges = in.readInt(); + this.softInputMode = in.readInt(); + this.persistableMode = in.readInt(); + this.lockTaskLaunchMode = in.readInt(); + this.screenOrientation = in.readInt(); + this.resizeMode = in.readInt(); + this.maxAspectRatio = (Float) in.readValue(Float.class.getClassLoader()); + this.minAspectRatio = (Float) in.readValue(Float.class.getClassLoader()); + this.supportsSizeChanges = in.readBoolean(); + this.requestedVrComponent = in.readString(); + this.rotationAnimation = in.readInt(); + this.colorMode = in.readInt(); + this.setMetaData(in.readBundle()); + if (in.readBoolean()) { + windowLayout = new ActivityInfo.WindowLayout(in); + } + this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in); + this.mRequiredDisplayCategory = in.readString8(); + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public ParsedActivityImpl createFromParcel(Parcel source) { + return new ParsedActivityImpl(source); + } + + @Override + public ParsedActivityImpl[] newArray(int size) { + return new ParsedActivityImpl[size]; + } + }; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedActivityImpl( + int theme, + int uiOptions, + @Nullable String targetActivity, + @Nullable String parentActivityName, + @Nullable String taskAffinity, + int privateFlags, + @Nullable String permission, + @Nullable Set knownActivityEmbeddingCerts, + int launchMode, + int documentLaunchMode, + int maxRecents, + int configChanges, + int softInputMode, + int persistableMode, + int lockTaskLaunchMode, + int screenOrientation, + int resizeMode, + float maxAspectRatio, + float minAspectRatio, + boolean supportsSizeChanges, + @Nullable String requestedVrComponent, + int rotationAnimation, + int colorMode, + @Nullable ActivityInfo.WindowLayout windowLayout, + @Nullable String requiredDisplayCategory) { + this.theme = theme; + this.uiOptions = uiOptions; + this.targetActivity = targetActivity; + this.parentActivityName = parentActivityName; + this.taskAffinity = taskAffinity; + this.privateFlags = privateFlags; + this.permission = permission; + this.mKnownActivityEmbeddingCerts = knownActivityEmbeddingCerts; + this.launchMode = launchMode; + this.documentLaunchMode = documentLaunchMode; + this.maxRecents = maxRecents; + this.configChanges = configChanges; + this.softInputMode = softInputMode; + this.persistableMode = persistableMode; + this.lockTaskLaunchMode = lockTaskLaunchMode; + this.screenOrientation = screenOrientation; + this.resizeMode = resizeMode; + this.maxAspectRatio = maxAspectRatio; + this.minAspectRatio = minAspectRatio; + this.supportsSizeChanges = supportsSizeChanges; + this.requestedVrComponent = requestedVrComponent; + this.rotationAnimation = rotationAnimation; + this.colorMode = colorMode; + this.windowLayout = windowLayout; + this.mRequiredDisplayCategory = requiredDisplayCategory; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public int getTheme() { + return theme; + } + + @DataClass.Generated.Member + public int getUiOptions() { + return uiOptions; + } + + @DataClass.Generated.Member + public @Nullable String getTargetActivity() { + return targetActivity; + } + + @DataClass.Generated.Member + public @Nullable String getParentActivityName() { + return parentActivityName; + } + + @DataClass.Generated.Member + public @Nullable String getTaskAffinity() { + return taskAffinity; + } + + @DataClass.Generated.Member + public int getPrivateFlags() { + return privateFlags; + } + + @DataClass.Generated.Member + public @Nullable String getPermission() { + return permission; + } + + @DataClass.Generated.Member + public int getLaunchMode() { + return launchMode; + } + + @DataClass.Generated.Member + public int getDocumentLaunchMode() { + return documentLaunchMode; + } + + @DataClass.Generated.Member + public int getMaxRecents() { + return maxRecents; + } + + @DataClass.Generated.Member + public int getConfigChanges() { + return configChanges; + } + + @DataClass.Generated.Member + public int getSoftInputMode() { + return softInputMode; + } + + @DataClass.Generated.Member + public int getPersistableMode() { + return persistableMode; + } + + @DataClass.Generated.Member + public int getLockTaskLaunchMode() { + return lockTaskLaunchMode; + } + + @DataClass.Generated.Member + public int getScreenOrientation() { + return screenOrientation; + } + + @DataClass.Generated.Member + public int getResizeMode() { + return resizeMode; + } + + @DataClass.Generated.Member + public float getMaxAspectRatio() { + return maxAspectRatio; + } + + @DataClass.Generated.Member + public float getMinAspectRatio() { + return minAspectRatio; + } + + @DataClass.Generated.Member + public boolean isSupportsSizeChanges() { + return supportsSizeChanges; + } + + @DataClass.Generated.Member + public @Nullable String getRequestedVrComponent() { + return requestedVrComponent; + } + + @DataClass.Generated.Member + public int getRotationAnimation() { + return rotationAnimation; + } + + @DataClass.Generated.Member + public int getColorMode() { + return colorMode; + } + + @DataClass.Generated.Member + public @Nullable ActivityInfo.WindowLayout getWindowLayout() { + return windowLayout; + } + + @DataClass.Generated.Member + public @Nullable String getRequiredDisplayCategory() { + return mRequiredDisplayCategory; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setTheme( int value) { + theme = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setUiOptions( int value) { + uiOptions = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setParentActivityName(@NonNull String value) { + parentActivityName = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setTaskAffinity(@NonNull String value) { + taskAffinity = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setPrivateFlags( int value) { + privateFlags = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setLaunchMode( int value) { + launchMode = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setDocumentLaunchMode( int value) { + documentLaunchMode = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setMaxRecents( int value) { + maxRecents = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setConfigChanges( int value) { + configChanges = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setSoftInputMode( int value) { + softInputMode = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setPersistableMode( int value) { + persistableMode = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setLockTaskLaunchMode( int value) { + lockTaskLaunchMode = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setScreenOrientation( int value) { + screenOrientation = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setResizeMode( int value) { + resizeMode = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setMaxAspectRatio( float value) { + maxAspectRatio = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setMinAspectRatio( float value) { + minAspectRatio = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setSupportsSizeChanges( boolean value) { + supportsSizeChanges = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setRequestedVrComponent(@NonNull String value) { + requestedVrComponent = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setRotationAnimation( int value) { + rotationAnimation = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setColorMode( int value) { + colorMode = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setWindowLayout(@NonNull ActivityInfo.WindowLayout value) { + windowLayout = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedActivityImpl setRequiredDisplayCategory(@NonNull String value) { + mRequiredDisplayCategory = value; + return this; + } + + @DataClass.Generated( + time = 1701338377709L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java", + inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic static @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java new file mode 100644 index 000000000000..c3f7dab3c46a --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java @@ -0,0 +1,648 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + +import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag; +import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET; +import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityTaskManager; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.parsing.FrameworkParsingPackageUtils; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseInput.DeferredError; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.util.ArraySet; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.WindowManager; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingUtils; +import com.android.internal.util.ArrayUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * @hide + */ +public class ParsedActivityUtils { + + private static final String TAG = ParsingUtils.TAG; + + public static final boolean LOG_UNSAFE_BROADCASTS = false; + + // Set of broadcast actions that are safe for manifest receivers + public static final Set SAFE_BROADCASTS = new ArraySet<>(); + static { + SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED); + } + + /** + * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. + */ + private static final int RECREATE_ON_CONFIG_CHANGES_MASK = + ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; + + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public static ParseResult parseActivityOrReceiver(String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + boolean useRoundIcon, @Nullable String defaultSplitName, ParseInput input) + throws XmlPullParserException, IOException { + final String packageName = pkg.getPackageName(); + final ParsedActivityImpl activity = new ParsedActivityImpl(); + + boolean receiver = "receiver".equals(parser.getName()); + String tag = "<" + parser.getName() + ">"; + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); + try { + ParseResult result = + ParsedMainComponentUtils.parseMainComponent(activity, tag, separateProcesses, + pkg, sa, flags, useRoundIcon, defaultSplitName, input, + R.styleable.AndroidManifestActivity_banner, + R.styleable.AndroidManifestActivity_description, + R.styleable.AndroidManifestActivity_directBootAware, + R.styleable.AndroidManifestActivity_enabled, + R.styleable.AndroidManifestActivity_icon, + R.styleable.AndroidManifestActivity_label, + R.styleable.AndroidManifestActivity_logo, + R.styleable.AndroidManifestActivity_name, + R.styleable.AndroidManifestActivity_process, + R.styleable.AndroidManifestActivity_roundIcon, + R.styleable.AndroidManifestActivity_splitName, + R.styleable.AndroidManifestActivity_attributionTags); + if (result.isError()) { + return input.error(result); + } + + if (receiver && pkg.isSaveStateDisallowed()) { + // A heavy-weight application can not have receivers in its main process + if (Objects.equals(activity.getProcessName(), packageName)) { + return input.error("Heavy-weight applications can not have receivers " + + "in main process"); + } + } + + // The following section has formatting off to make it easier to read the flags. + // Multi-lining them to fit within the column restriction makes it hard to tell what + // field is assigned where. + // @formatter:off + activity.setTheme(sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0)) + .setUiOptions(sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions())); + + activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isTaskReparentingAllowed(), sa) + | flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa) + | flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa) + | flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa) + | flag(ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS, R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, sa) + | flag(ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH, R.styleable.AndroidManifestActivity_finishOnTaskLaunch, sa) + | flag(ActivityInfo.FLAG_IMMERSIVE, R.styleable.AndroidManifestActivity_immersive, sa) + | flag(ActivityInfo.FLAG_MULTIPROCESS, R.styleable.AndroidManifestActivity_multiprocess, sa) + | flag(ActivityInfo.FLAG_NO_HISTORY, R.styleable.AndroidManifestActivity_noHistory, sa) + | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showForAllUsers, sa) + | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showOnLockScreen, sa) + | flag(ActivityInfo.FLAG_STATE_NOT_NEEDED, R.styleable.AndroidManifestActivity_stateNotNeeded, sa) + | flag(ActivityInfo.FLAG_SYSTEM_USER_ONLY, R.styleable.AndroidManifestActivity_systemUserOnly, sa))); + + if (!receiver) { + activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_HARDWARE_ACCELERATED, R.styleable.AndroidManifestActivity_hardwareAccelerated, pkg.isHardwareAccelerated(), sa) + | flag(ActivityInfo.FLAG_ALLOW_EMBEDDED, R.styleable.AndroidManifestActivity_allowEmbedded, sa) + | flag(ActivityInfo.FLAG_ALWAYS_FOCUSABLE, R.styleable.AndroidManifestActivity_alwaysFocusable, sa) + | flag(ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS, R.styleable.AndroidManifestActivity_autoRemoveFromRecents, sa) + | flag(ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY, R.styleable.AndroidManifestActivity_relinquishTaskIdentity, sa) + | flag(ActivityInfo.FLAG_RESUME_WHILE_PAUSING, R.styleable.AndroidManifestActivity_resumeWhilePausing, sa) + | flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa) + | flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa) + | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa) + | flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa)) + | flag(ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING, R.styleable.AndroidManifestActivity_allowUntrustedActivityEmbedding, sa)); + + activity.setPrivateFlags(activity.getPrivateFlags() | (flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED, + R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa) + | flag(ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND, + R.styleable.AndroidManifestActivity_playHomeTransitionSound, true, sa))); + + activity.setColorMode(sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT)) + .setDocumentLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE)) + .setLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE)) + .setLockTaskLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0)) + .setMaxRecents(sa.getInt(R.styleable.AndroidManifestActivity_maxRecents, ActivityTaskManager.getDefaultAppRecentsLimitStatic())) + .setPersistableMode(sa.getInteger(R.styleable.AndroidManifestActivity_persistableMode, ActivityInfo.PERSIST_ROOT_ONLY)) + .setRequestedVrComponent(sa.getString(R.styleable.AndroidManifestActivity_enableVrMode)) + .setRotationAnimation(sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED)) + .setSoftInputMode(sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0)) + .setConfigChanges(getActivityConfigChanges( + sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), + sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)) + ); + + int screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED); + int resizeMode = getActivityResizeMode(pkg, sa, screenOrientation); + activity.setScreenOrientation(screenOrientation) + .setResizeMode(resizeMode); + + if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio) + == TypedValue.TYPE_FLOAT) { + activity.setMaxAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio, + 0 /*default*/)); + } + + if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio) + == TypedValue.TYPE_FLOAT) { + activity.setMinAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio, + 0 /*default*/)); + } + + if (sa.hasValue(R.styleable.AndroidManifestActivity_enableOnBackInvokedCallback)) { + boolean enable = sa.getBoolean( + R.styleable.AndroidManifestActivity_enableOnBackInvokedCallback, + false); + activity.setPrivateFlags(activity.getPrivateFlags() + | (enable ? ActivityInfo.PRIVATE_FLAG_ENABLE_ON_BACK_INVOKED_CALLBACK + : ActivityInfo.PRIVATE_FLAG_DISABLE_ON_BACK_INVOKED_CALLBACK)); + } + } else { + activity.setLaunchMode(ActivityInfo.LAUNCH_MULTIPLE) + .setConfigChanges(0) + .setFlags(activity.getFlags()|flag(ActivityInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestActivity_singleUser, sa)); + } + // @formatter:on + + String taskAffinity = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivity_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + + ParseResult affinityNameResult = ComponentParseUtils.buildTaskAffinityName( + packageName, pkg.getTaskAffinity(), taskAffinity, input); + if (affinityNameResult.isError()) { + return input.error(affinityNameResult); + } + + activity.setTaskAffinity(affinityNameResult.getResult()); + + boolean visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false); + if (visibleToEphemeral) { + activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP); + pkg.setVisibleToInstantApps(true); + } + + String requiredDisplayCategory = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivity_requiredDisplayCategory, 0); + + if (requiredDisplayCategory != null + && FrameworkParsingPackageUtils.validateName(requiredDisplayCategory, + false /* requireSeparator */, false /* requireFilename */) != null) { + return input.error("requiredDisplayCategory attribute can only consist " + + "of alphanumeric characters, '_', and '.'"); + } + + activity.setRequiredDisplayCategory(requiredDisplayCategory); + + return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver, + false /*isAlias*/, visibleToEphemeral, input, + R.styleable.AndroidManifestActivity_parentActivityName, + R.styleable.AndroidManifestActivity_permission, + R.styleable.AndroidManifestActivity_exported + ); + } finally { + sa.recycle(); + } + } + + @NonNull + public static ParseResult parseActivityAlias(ParsingPackage pkg, Resources res, + XmlResourceParser parser, boolean useRoundIcon, @Nullable String defaultSplitName, + @NonNull ParseInput input) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivityAlias); + try { + String targetActivity = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_targetActivity, + Configuration.NATIVE_CONFIG_VERSION); + if (targetActivity == null) { + return input.error(" does not specify android:targetActivity"); + } + + String packageName = pkg.getPackageName(); + targetActivity = ParsingUtils.buildClassName(packageName, targetActivity); + if (targetActivity == null) { + return input.error("Empty class name in package " + packageName); + } + + ParsedActivity target = null; + + List activities = pkg.getActivities(); + final int activitiesSize = ArrayUtils.size(activities); + for (int i = 0; i < activitiesSize; i++) { + ParsedActivity t = activities.get(i); + if (targetActivity.equals(t.getName())) { + target = t; + break; + } + } + + if (target == null) { + return input.error(" target activity " + targetActivity + + " not found in manifest with activities = " + + pkg.getActivities() + + ", parsedActivities = " + activities); + } + + ParsedActivityImpl activity = ParsedActivityImpl.makeAlias(targetActivity, target); + String tag = "<" + parser.getName() + ">"; + + ParseResult result = ParsedMainComponentUtils.parseMainComponent( + activity, tag, null, pkg, sa, 0, useRoundIcon, defaultSplitName, input, + R.styleable.AndroidManifestActivityAlias_banner, + R.styleable.AndroidManifestActivityAlias_description, + NOT_SET /*directBootAwareAttr*/, + R.styleable.AndroidManifestActivityAlias_enabled, + R.styleable.AndroidManifestActivityAlias_icon, + R.styleable.AndroidManifestActivityAlias_label, + R.styleable.AndroidManifestActivityAlias_logo, + R.styleable.AndroidManifestActivityAlias_name, + NOT_SET /*processAttr*/, + R.styleable.AndroidManifestActivityAlias_roundIcon, + NOT_SET /*splitNameAttr*/, + R.styleable.AndroidManifestActivityAlias_attributionTags); + if (result.isError()) { + return input.error(result); + } + + // TODO add visibleToInstantApps attribute to activity alias + final boolean visibleToEphemeral = + ((activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0); + + return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, false /*isReceiver*/, true /*isAlias*/, + visibleToEphemeral, input, + R.styleable.AndroidManifestActivityAlias_parentActivityName, + R.styleable.AndroidManifestActivityAlias_permission, + R.styleable.AndroidManifestActivityAlias_exported); + } finally { + sa.recycle(); + } + } + + /** + * This method shares parsing logic between Activity/Receiver/alias instances, but requires + * passing in booleans for isReceiver/isAlias, since there's no indicator in the other + * parameters. + * + * They're used to filter the parsed tags and their behavior. This makes the method rather + * messy, but it's more maintainable than writing 3 separate methods for essentially the same + * type of logic. + */ + @NonNull + private static ParseResult parseActivityOrAlias(ParsedActivityImpl activity, + ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources, + TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral, + ParseInput input, int parentActivityNameAttr, int permissionAttr, + int exportedAttr) throws IOException, XmlPullParserException { + String parentActivityName = array.getNonConfigurationString(parentActivityNameAttr, Configuration.NATIVE_CONFIG_VERSION); + if (parentActivityName != null) { + String packageName = pkg.getPackageName(); + String parentClassName = ParsingUtils.buildClassName(packageName, parentActivityName); + if (parentClassName == null) { + Log.e(TAG, "Activity " + activity.getName() + + " specified invalid parentActivityName " + parentActivityName); + } else { + activity.setParentActivityName(parentClassName); + } + } + + String permission = array.getNonConfigurationString(permissionAttr, 0); + if (isAlias) { + // An alias will override permissions to allow referencing an Activity through its alias + // without needing the original permission. If an alias needs the same permission, + // it must be re-declared. + activity.setPermission(permission); + } else { + activity.setPermission(permission != null ? permission : pkg.getPermission()); + } + + final ParseResult> knownActivityEmbeddingCertsResult = + parseKnownActivityEmbeddingCerts(array, resources, isAlias + ? R.styleable.AndroidManifestActivityAlias_knownActivityEmbeddingCerts + : R.styleable.AndroidManifestActivity_knownActivityEmbeddingCerts, input); + if (knownActivityEmbeddingCertsResult.isError()) { + return input.error(knownActivityEmbeddingCertsResult); + } else { + final Set knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult + .getResult(); + if (knownActivityEmbeddingCerts != null) { + activity.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts); + } + } + + final boolean setExported = array.hasValue(exportedAttr); + if (setExported) { + activity.setExported(array.getBoolean(exportedAttr, false)); + } + + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + if (parser.getName().equals("intent-filter")) { + ParseResult intentResult = parseIntentFilter(pkg, activity, + !isReceiver, visibleToEphemeral, resources, parser, input); + if (intentResult.isSuccess()) { + ParsedIntentInfoImpl intentInfo = intentResult.getResult(); + if (intentInfo != null) { + IntentFilter intentFilter = intentInfo.getIntentFilter(); + activity.setOrder(Math.max(intentFilter.getOrder(), activity.getOrder())); + activity.addIntent(intentInfo); + if (LOG_UNSAFE_BROADCASTS && isReceiver + && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) { + int actionCount = intentFilter.countActions(); + for (int i = 0; i < actionCount; i++) { + final String action = intentFilter.getAction(i); + if (action == null || !action.startsWith("android.")) { + continue; + } + + if (!SAFE_BROADCASTS.contains(action)) { + Slog.w(TAG, + "Broadcast " + action + " may never be delivered to " + + pkg.getPackageName() + " as requested at: " + + parser.getPositionDescription()); + } + } + } + } + } + result = intentResult; + } else if (parser.getName().equals("meta-data")) { + result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input); + } else if (parser.getName().equals("property")) { + result = ParsedComponentUtils.addProperty(activity, pkg, resources, parser, input); + } else if (!isReceiver && !isAlias && parser.getName().equals("preferred")) { + ParseResult intentResult = parseIntentFilter(pkg, activity, + true /*allowImplicitEphemeralVisibility*/, visibleToEphemeral, + resources, parser, input); + if (intentResult.isSuccess()) { + ParsedIntentInfoImpl intent = intentResult.getResult(); + if (intent != null) { + pkg.addPreferredActivityFilter(activity.getClassName(), intent); + } + } + result = intentResult; + } else if (!isReceiver && !isAlias && parser.getName().equals("layout")) { + ParseResult layoutResult = + parseActivityWindowLayout(resources, parser, input); + if (layoutResult.isSuccess()) { + activity.setWindowLayout(layoutResult.getResult()); + } + result = layoutResult; + } else { + result = ParsingUtils.unknownTag(tag, pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + + if (!isAlias && activity.getLaunchMode() != LAUNCH_SINGLE_INSTANCE_PER_TASK + && activity.getMetaData().containsKey( + ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE)) { + final String launchMode = activity.getMetaData().getString( + ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE); + if (launchMode != null && launchMode.equals("singleInstancePerTask")) { + activity.setLaunchMode(LAUNCH_SINGLE_INSTANCE_PER_TASK); + } + } + + if (!isAlias) { + // Default allow the activity to be displayed on a remote device unless it explicitly + // set to false. + boolean canDisplayOnRemoteDevices = array.getBoolean( + R.styleable.AndroidManifestActivity_canDisplayOnRemoteDevices, true); + if (!activity.getMetaData().getBoolean( + ParsingPackageUtils.METADATA_CAN_DISPLAY_ON_REMOTE_DEVICES, true)) { + canDisplayOnRemoteDevices = false; + } + if (canDisplayOnRemoteDevices) { + activity.setFlags(activity.getFlags() + | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES); + } + } + + ParseResult layoutResult = + resolveActivityWindowLayout(activity, input); + if (layoutResult.isError()) { + return input.error(layoutResult); + } + activity.setWindowLayout(layoutResult.getResult()); + + if (!setExported) { + boolean hasIntentFilters = activity.getIntents().size() > 0; + if (hasIntentFilters) { + final ParseResult exportedCheckResult = input.deferError( + activity.getName() + ": Targeting S+ (version " + Build.VERSION_CODES.S + + " and above) requires that an explicit value for android:exported be" + + " defined when intent filters are present", + DeferredError.MISSING_EXPORTED_FLAG); + if (exportedCheckResult.isError()) { + return input.error(exportedCheckResult); + } + } + activity.setExported(hasIntentFilters); + } + + return input.success(activity); + } + + @NonNull + private static ParseResult parseIntentFilter(ParsingPackage pkg, + ParsedActivityImpl activity, boolean allowImplicitEphemeralVisibility, + boolean visibleToEphemeral, Resources resources, XmlResourceParser parser, + ParseInput input) throws IOException, XmlPullParserException { + ParseResult result = ParsedMainComponentUtils.parseIntentFilter(activity, + pkg, resources, parser, visibleToEphemeral, true /*allowGlobs*/, + true /*allowAutoVerify*/, allowImplicitEphemeralVisibility, + true /*failOnNoActions*/, input); + if (result.isError()) { + return input.error(result); + } + + ParsedIntentInfoImpl intent = result.getResult(); + if (intent != null) { + final IntentFilter intentFilter = intent.getIntentFilter(); + if (intentFilter.isVisibleToInstantApp()) { + activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP); + } + if (intentFilter.isImplicitlyVisibleToInstantApp()) { + activity.setFlags( + activity.getFlags() | ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP); + } + } + + return input.success(intent); + } + + private static int getActivityResizeMode(ParsingPackage pkg, TypedArray sa, + int screenOrientation) { + Boolean resizeableActivity = pkg.getResizeableActivity(); + + if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) + || resizeableActivity != null) { + // Activity or app explicitly set if it is resizeable or not; + if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, + resizeableActivity != null && resizeableActivity)) { + return ActivityInfo.RESIZE_MODE_RESIZEABLE; + } else { + return ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + } + } + + if (pkg.isResizeableActivityViaSdkVersion()) { + // The activity or app didn't explicitly set the resizing option, however we want to + // make it resize due to the sdk version it is targeting. + return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; + } + + // resize preference isn't set and target sdk version doesn't support resizing apps by + // default. For the app to be resizeable if it isn't fixed orientation or immersive. + if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; + } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; + } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; + } else { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; + } + } + + @NonNull + private static ParseResult parseActivityWindowLayout(Resources res, + AttributeSet attrs, ParseInput input) { + TypedArray sw = res.obtainAttributes(attrs, R.styleable.AndroidManifestLayout); + try { + int width = -1; + float widthFraction = -1f; + int height = -1; + float heightFraction = -1f; + final int widthType = sw.getType(R.styleable.AndroidManifestLayout_defaultWidth); + if (widthType == TypedValue.TYPE_FRACTION) { + widthFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultWidth, 1, 1, + -1); + } else if (widthType == TypedValue.TYPE_DIMENSION) { + width = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultWidth, + -1); + } + final int heightType = sw.getType(R.styleable.AndroidManifestLayout_defaultHeight); + if (heightType == TypedValue.TYPE_FRACTION) { + heightFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultHeight, 1, + 1, -1); + } else if (heightType == TypedValue.TYPE_DIMENSION) { + height = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultHeight, + -1); + } + int gravity = sw.getInt(R.styleable.AndroidManifestLayout_gravity, Gravity.CENTER); + int minWidth = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minWidth, -1); + int minHeight = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minHeight, + -1); + String windowLayoutAffinity = + sw.getNonConfigurationString( + R.styleable.AndroidManifestLayout_windowLayoutAffinity, 0); + final ActivityInfo.WindowLayout windowLayout = new ActivityInfo.WindowLayout(width, + widthFraction, height, heightFraction, gravity, minWidth, minHeight, + windowLayoutAffinity); + return input.success(windowLayout); + } finally { + sw.recycle(); + } + } + + /** + * Resolves values in {@link ActivityInfo.WindowLayout}. + * + *

{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in + * Android R and some variants of pre-R. + */ + private static ParseResult resolveActivityWindowLayout( + ParsedActivity activity, ParseInput input) { + // There isn't a metadata for us to fall back. Whatever is in layout is correct. + if (!activity.getMetaData().containsKey( + ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) { + return input.success(activity.getWindowLayout()); + } + + // Layout already specifies a value. We should just use that one. + if (activity.getWindowLayout() != null && activity.getWindowLayout().windowLayoutAffinity != null) { + return input.success(activity.getWindowLayout()); + } + + String windowLayoutAffinity = activity.getMetaData().getString( + ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY); + ActivityInfo.WindowLayout layout = activity.getWindowLayout(); + if (layout == null) { + layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */, + -1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY, + -1 /* minWidth */, -1 /* minHeight */, windowLayoutAffinity); + } else { + layout.windowLayoutAffinity = windowLayoutAffinity; + } + return input.success(layout); + } + + /** + * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml. + * @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from + * AndroidManifest.xml. + * @hide + */ + public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) { + return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK); + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java new file mode 100644 index 000000000000..27f7eee1a308 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; + +/** + * @hide + **/ +@DataClass(genGetters = true, genAidl = false, genSetters = true, genParcelable = true) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedApexSystemServiceImpl implements ParsedApexSystemService, Parcelable { + + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) + @NonNull + private String name; + + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) + @Nullable + private String jarPath; + + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) + @Nullable + private String minSdkVersion; + + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) + @Nullable + private String maxSdkVersion; + + private int initOrder; + + public ParsedApexSystemServiceImpl() { + } + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedApexSystemServiceImpl( + @NonNull String name, + @Nullable String jarPath, + @Nullable String minSdkVersion, + @Nullable String maxSdkVersion, + int initOrder) { + this.name = name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.jarPath = jarPath; + this.minSdkVersion = minSdkVersion; + this.maxSdkVersion = maxSdkVersion; + this.initOrder = initOrder; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull String getName() { + return name; + } + + @DataClass.Generated.Member + public @Nullable String getJarPath() { + return jarPath; + } + + @DataClass.Generated.Member + public @Nullable String getMinSdkVersion() { + return minSdkVersion; + } + + @DataClass.Generated.Member + public @Nullable String getMaxSdkVersion() { + return maxSdkVersion; + } + + @DataClass.Generated.Member + public int getInitOrder() { + return initOrder; + } + + @DataClass.Generated.Member + public @NonNull ParsedApexSystemServiceImpl setName(@NonNull String value) { + name = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedApexSystemServiceImpl setJarPath(@NonNull String value) { + jarPath = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedApexSystemServiceImpl setMinSdkVersion(@NonNull String value) { + minSdkVersion = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedApexSystemServiceImpl setMaxSdkVersion(@NonNull String value) { + maxSdkVersion = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedApexSystemServiceImpl setInitOrder( int value) { + initOrder = value; + return this; + } + + @DataClass.Generated.Member + static Parcelling sParcellingForName = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedString.class); + static { + if (sParcellingForName == null) { + sParcellingForName = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedString()); + } + } + + @DataClass.Generated.Member + static Parcelling sParcellingForJarPath = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedString.class); + static { + if (sParcellingForJarPath == null) { + sParcellingForJarPath = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedString()); + } + } + + @DataClass.Generated.Member + static Parcelling sParcellingForMinSdkVersion = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedString.class); + static { + if (sParcellingForMinSdkVersion == null) { + sParcellingForMinSdkVersion = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedString()); + } + } + + @DataClass.Generated.Member + static Parcelling sParcellingForMaxSdkVersion = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedString.class); + static { + if (sParcellingForMaxSdkVersion == null) { + sParcellingForMaxSdkVersion = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedString()); + } + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (jarPath != null) flg |= 0x2; + if (minSdkVersion != null) flg |= 0x4; + if (maxSdkVersion != null) flg |= 0x8; + dest.writeByte(flg); + sParcellingForName.parcel(name, dest, flags); + sParcellingForJarPath.parcel(jarPath, dest, flags); + sParcellingForMinSdkVersion.parcel(minSdkVersion, dest, flags); + sParcellingForMaxSdkVersion.parcel(maxSdkVersion, dest, flags); + dest.writeInt(initOrder); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParsedApexSystemServiceImpl(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + String _name = sParcellingForName.unparcel(in); + String _jarPath = sParcellingForJarPath.unparcel(in); + String _minSdkVersion = sParcellingForMinSdkVersion.unparcel(in); + String _maxSdkVersion = sParcellingForMaxSdkVersion.unparcel(in); + int _initOrder = in.readInt(); + + this.name = _name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.jarPath = _jarPath; + this.minSdkVersion = _minSdkVersion; + this.maxSdkVersion = _maxSdkVersion; + this.initOrder = _initOrder; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public ParsedApexSystemServiceImpl[] newArray(int size) { + return new ParsedApexSystemServiceImpl[size]; + } + + @Override + public ParsedApexSystemServiceImpl createFromParcel(@NonNull android.os.Parcel in) { + return new ParsedApexSystemServiceImpl(in); + } + }; + + @DataClass.Generated( + time = 1701710844088L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java", + inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedApexSystemService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java new file mode 100644 index 000000000000..c69213f11f85 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.R; +import android.annotation.NonNull; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.text.TextUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +public class ParsedApexSystemServiceUtils { + + @NonNull + public static ParseResult parseApexSystemService( + Resources res, XmlResourceParser parser, ParseInput input) + throws XmlPullParserException, IOException { + final ParsedApexSystemServiceImpl systemService = + new ParsedApexSystemServiceImpl(); + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestApexSystemService); + try { + String className = sa.getString( + R.styleable.AndroidManifestApexSystemService_name); + if (TextUtils.isEmpty(className)) { + return input.error(" does not have name attribute"); + } + + String jarPath = sa.getString( + R.styleable.AndroidManifestApexSystemService_path); + String minSdkVersion = sa.getString( + R.styleable.AndroidManifestApexSystemService_minSdkVersion); + String maxSdkVersion = sa.getString( + R.styleable.AndroidManifestApexSystemService_maxSdkVersion); + int initOrder = sa.getInt(R.styleable.AndroidManifestApexSystemService_initOrder, 0); + + systemService.setName(className) + .setMinSdkVersion(minSdkVersion) + .setMaxSdkVersion(maxSdkVersion) + .setInitOrder(initOrder); + + if (!TextUtils.isEmpty(jarPath)) { + systemService.setJarPath(jarPath); + } + + return input.success(systemService); + } finally { + sa.recycle(); + } + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java new file mode 100644 index 000000000000..e3bfb38802db --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.annotation.StringRes; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link android.R.styleable#AndroidManifestAttribution <attribution>} tag parsed from the + * manifest. + * + * @hide + */ +@DataClass(genAidl = false, genSetters = true, genBuilder = false, genParcelable = true) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedAttributionImpl implements ParsedAttribution, Parcelable { + + /** Maximum amount of attributions per package */ + static final int MAX_NUM_ATTRIBUTIONS = 10000; + + /** Tag of the attribution */ + private @NonNull String tag; + + /** User visible label fo the attribution */ + private @StringRes int label; + + /** Ids of previously declared attributions this attribution inherits from */ + private @NonNull List inheritFrom; + + public ParsedAttributionImpl() {} + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new ParsedAttributionImpl. + * + * @param tag + * Tag of the attribution + * @param label + * User visible label fo the attribution + * @param inheritFrom + * Ids of previously declared attributions this attribution inherits from + */ + @DataClass.Generated.Member + public ParsedAttributionImpl( + @NonNull String tag, + @StringRes int label, + @NonNull List inheritFrom) { + this.tag = tag; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, tag); + this.label = label; + com.android.internal.util.AnnotationValidations.validate( + StringRes.class, null, label); + this.inheritFrom = inheritFrom; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, inheritFrom); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * Tag of the attribution + */ + @DataClass.Generated.Member + public @NonNull String getTag() { + return tag; + } + + /** + * User visible label fo the attribution + */ + @DataClass.Generated.Member + public @StringRes int getLabel() { + return label; + } + + /** + * Ids of previously declared attributions this attribution inherits from + */ + @DataClass.Generated.Member + public @NonNull List getInheritFrom() { + return inheritFrom; + } + + /** + * Tag of the attribution + */ + @DataClass.Generated.Member + public @NonNull ParsedAttributionImpl setTag(@NonNull String value) { + tag = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, tag); + return this; + } + + /** + * User visible label fo the attribution + */ + @DataClass.Generated.Member + public @NonNull ParsedAttributionImpl setLabel(@StringRes int value) { + label = value; + com.android.internal.util.AnnotationValidations.validate( + StringRes.class, null, label); + return this; + } + + /** + * Ids of previously declared attributions this attribution inherits from + */ + @DataClass.Generated.Member + public @NonNull ParsedAttributionImpl setInheritFrom(@NonNull List value) { + inheritFrom = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, inheritFrom); + return this; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeString(tag); + dest.writeInt(label); + dest.writeStringList(inheritFrom); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParsedAttributionImpl(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String _tag = in.readString(); + int _label = in.readInt(); + List _inheritFrom = new ArrayList<>(); + in.readStringList(_inheritFrom); + + this.tag = _tag; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, tag); + this.label = _label; + com.android.internal.util.AnnotationValidations.validate( + StringRes.class, null, label); + this.inheritFrom = _inheritFrom; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, inheritFrom); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public ParsedAttributionImpl[] newArray(int size) { + return new ParsedAttributionImpl[size]; + } + + @Override + public ParsedAttributionImpl createFromParcel(@NonNull Parcel in) { + return new ParsedAttributionImpl(in); + } + }; + + @DataClass.Generated( + time = 1701338881658L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java", + inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java new file mode 100644 index 000000000000..ee5c3204ccd1 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.util.ArraySet; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** @hide */ +public class ParsedAttributionUtils { + + @NonNull + public static ParseResult parseAttribution(Resources res, + XmlResourceParser parser, ParseInput input) + throws IOException, XmlPullParserException { + String attributionTag; + int label; + List inheritFrom = null; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAttribution); + if (sa == null) { + return input.error(" could not be parsed"); + } + + try { + attributionTag = sa.getNonConfigurationString( + R.styleable.AndroidManifestAttribution_tag, 0); + if (attributionTag == null) { + return input.error(" does not specify android:tag"); + } + if (attributionTag.length() > ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN) { + return input.error("android:tag is too long. Max length is " + + ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN); + } + + label = sa.getResourceId(R.styleable.AndroidManifestAttribution_label, 0); + if (label == Resources.ID_NULL) { + return input.error(" does not specify android:label"); + } + } finally { + sa.recycle(); + } + + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("inherit-from")) { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestAttributionInheritFrom); + if (sa == null) { + return input.error(" could not be parsed"); + } + + try { + String inheritFromId = sa.getNonConfigurationString( + R.styleable.AndroidManifestAttributionInheritFrom_tag, 0); + + if (inheritFrom == null) { + inheritFrom = new ArrayList<>(); + } + inheritFrom.add(inheritFromId); + } finally { + sa.recycle(); + } + } else { + return input.error("Bad element under : " + tagName); + } + } + + if (inheritFrom == null) { + inheritFrom = Collections.emptyList(); + } else { + ((ArrayList) inheritFrom).trimToSize(); + } + + return input.success(new ParsedAttributionImpl(attributionTag, label, inheritFrom)); + } + + /** + * @return Is this set of attributions a valid combination for a single package? + */ + public static boolean isCombinationValid(@Nullable List attributions) { + if (attributions == null) { + return true; + } + + ArraySet attributionTags = new ArraySet<>(attributions.size()); + ArraySet inheritFromAttributionTags = new ArraySet<>(); + + int numAttributions = attributions.size(); + if (numAttributions > ParsedAttributionImpl.MAX_NUM_ATTRIBUTIONS) { + return false; + } + + for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) { + boolean wasAdded = attributionTags.add(attributions.get(attributionNum).getTag()); + if (!wasAdded) { + // feature id is not unique + return false; + } + } + + for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) { + ParsedAttribution feature = attributions.get(attributionNum); + + final List inheritFromList = feature.getInheritFrom(); + int numInheritFrom = inheritFromList.size(); + for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) { + String inheritFrom = inheritFromList.get(inheritFromNum); + + if (attributionTags.contains(inheritFrom)) { + // Cannot inherit from a attribution that is still defined + return false; + } + + boolean wasAdded = inheritFromAttributionTags.add(inheritFrom); + if (!wasAdded) { + // inheritFrom is not unique + return false; + } + } + } + + return true; + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java new file mode 100644 index 000000000000..7ee22f30ace0 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString; + +import static java.util.Collections.emptyMap; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.pm.PackageManager.Property; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; +import android.util.ArrayMap; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.pkg.parsing.ParsingUtils; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @hide + */ +@DataClass(genGetters = true, genSetters = true, genConstructor = false, genBuilder = false, + genParcelable = false) +@DataClass.Suppress({"setComponentName", "setProperties", "setIntents"}) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable { + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + private String name; + private int icon; + private int labelRes; + @Nullable + private CharSequence nonLocalizedLabel; + private int logo; + private int banner; + private int descriptionRes; + + // TODO(b/135203078): Replace flags with individual booleans, scoped by subclass + private int flags; + + @NonNull + @DataClass.ParcelWith(ForInternedString.class) + private String packageName; + + @NonNull + @DataClass.PluralOf("intent") + private List intents = Collections.emptyList(); + + @Nullable + private ComponentName componentName; + + @Nullable + private Bundle metaData; + + @NonNull + private Map mProperties = emptyMap(); + + public ParsedComponentImpl() { + + } + + protected ParsedComponentImpl(ParsedComponent other) { + this.metaData = other.getMetaData(); + this.name = other.getName(); + this.icon = other.getIcon(); + this.labelRes = other.getLabelRes(); + this.nonLocalizedLabel = other.getNonLocalizedLabel(); + this.logo = other.getLogo(); + this.banner = other.getBanner(); + this.descriptionRes = other.getDescriptionRes(); + this.flags = other.getFlags(); + this.packageName = other.getPackageName(); + this.componentName = other.getComponentName(); + this.intents = new ArrayList<>(((ParsedComponentImpl) other).intents); + this.mProperties = new ArrayMap<>(); + this.mProperties.putAll(other.getProperties()); + } + + public void addIntent(ParsedIntentInfoImpl intent) { + this.intents = CollectionUtils.add(this.intents, intent); + } + + /** + * Add a property to the component + */ + public void addProperty(@NonNull Property property) { + this.mProperties = CollectionUtils.add(this.mProperties, property.getName(), property); + } + + public ParsedComponentImpl setName(String name) { + this.name = TextUtils.safeIntern(name); + return this; + } + + @CallSuper + public void setPackageName(@NonNull String packageName) { + this.packageName = TextUtils.safeIntern(packageName); + //noinspection ConstantConditions + this.componentName = null; + + // Note: this method does not edit name (which can point to a class), because this package + // name change is not changing the package in code, but the identifier used by the system. + } + + @Override + @NonNull + public ComponentName getComponentName() { + if (componentName == null) { + componentName = new ComponentName(getPackageName(), getName()); + } + return componentName; + } + + @NonNull + @Override + public Bundle getMetaData() { + return metaData == null ? Bundle.EMPTY : metaData; + } + + @NonNull + @Override + public List getIntents() { + return new ArrayList<>(intents); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.name); + dest.writeInt(this.getIcon()); + dest.writeInt(this.getLabelRes()); + dest.writeCharSequence(this.getNonLocalizedLabel()); + dest.writeInt(this.getLogo()); + dest.writeInt(this.getBanner()); + dest.writeInt(this.getDescriptionRes()); + dest.writeInt(this.getFlags()); + sForInternedString.parcel(this.packageName, dest, flags); + dest.writeTypedList(this.intents); + dest.writeBundle(this.metaData); + dest.writeMap(this.mProperties); + } + + protected ParsedComponentImpl(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + //noinspection ConstantConditions + this.name = in.readString(); + this.icon = in.readInt(); + this.labelRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.logo = in.readInt(); + this.banner = in.readInt(); + this.descriptionRes = in.readInt(); + this.flags = in.readInt(); + //noinspection ConstantConditions + this.packageName = sForInternedString.unparcel(in); + this.intents = ParsingUtils.createTypedInterfaceList(in, ParsedIntentInfoImpl.CREATOR); + this.metaData = in.readBundle(boot); + this.mProperties = in.readHashMap(boot); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public @NonNull String getName() { + return name; + } + + @DataClass.Generated.Member + public int getIcon() { + return icon; + } + + @DataClass.Generated.Member + public int getLabelRes() { + return labelRes; + } + + @DataClass.Generated.Member + public @Nullable CharSequence getNonLocalizedLabel() { + return nonLocalizedLabel; + } + + @DataClass.Generated.Member + public int getLogo() { + return logo; + } + + @DataClass.Generated.Member + public int getBanner() { + return banner; + } + + @DataClass.Generated.Member + public int getDescriptionRes() { + return descriptionRes; + } + + @DataClass.Generated.Member + public int getFlags() { + return flags; + } + + @DataClass.Generated.Member + public @NonNull String getPackageName() { + return packageName; + } + + @DataClass.Generated.Member + public @NonNull Map getProperties() { + return mProperties; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setIcon( int value) { + icon = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setLabelRes( int value) { + labelRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setNonLocalizedLabel(@NonNull CharSequence value) { + nonLocalizedLabel = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setLogo( int value) { + logo = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setBanner( int value) { + banner = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setDescriptionRes( int value) { + descriptionRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setFlags( int value) { + flags = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedComponentImpl setMetaData(@NonNull Bundle value) { + metaData = value; + return this; + } + + @DataClass.Generated( + time = 1701445673589L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java", + inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map mProperties\npublic void addIntent(com.android.internal.pm.pkg.component.ParsedIntentInfoImpl)\npublic void addProperty(android.content.pm.PackageManager.Property)\npublic com.android.internal.pm.pkg.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java new file mode 100644 index 000000000000..9e2548b3bce3 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET; + +import android.annotation.NonNull; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.Property; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.TypedValue; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +/** @hide */ +class ParsedComponentUtils { + + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + static ParseResult parseComponent( + Component component, String tag, ParsingPackage pkg, TypedArray array, + boolean useRoundIcon, ParseInput input, int bannerAttr, int descriptionAttr, + int iconAttr, int labelAttr, int logoAttr, int nameAttr, int roundIconAttr) { + String name = array.getNonConfigurationString(nameAttr, 0); + if (TextUtils.isEmpty(name)) { + return input.error(tag + " does not specify android:name"); + } + + String packageName = pkg.getPackageName(); + String className = ParsingUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + return input.error(tag + " invalid android:name"); + } + + //noinspection ConstantConditions; null check done above with isEmpty + component.setName(className) + .setPackageName(packageName); + + int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0; + if (roundIconVal != 0) { + component.setIcon(roundIconVal) + .setNonLocalizedLabel(null); + } else { + int iconVal = array.getResourceId(iconAttr, 0); + if (iconVal != 0) { + component.setIcon(iconVal); + component.setNonLocalizedLabel(null); + } + } + + int logoVal = array.getResourceId(logoAttr, 0); + if (logoVal != 0) { + component.setLogo(logoVal); + } + + int bannerVal = array.getResourceId(bannerAttr, 0); + if (bannerVal != 0) { + component.setBanner(bannerVal); + } + + if (descriptionAttr != NOT_SET) { + component.setDescriptionRes(array.getResourceId(descriptionAttr, 0)); + } + + TypedValue v = array.peekValue(labelAttr); + if (v != null) { + component.setLabelRes(v.resourceId); + if (v.resourceId == 0) { + component.setNonLocalizedLabel(v.coerceToString()); + } + } + + return input.success(component); + } + + static ParseResult addMetaData(ParsedComponentImpl component, ParsingPackage pkg, + Resources resources, XmlResourceParser parser, ParseInput input) { + ParseResult result = ParsingPackageUtils.parseMetaData(pkg, component, + resources, parser, "", input); + if (result.isError()) { + return input.error(result); + } + final Property property = result.getResult(); + if (property != null) { + component.setMetaData(property.toBundle(component.getMetaData())); + } + return input.success(component.getMetaData()); + } + + static ParseResult addProperty(ParsedComponentImpl component, ParsingPackage pkg, + Resources resources, XmlResourceParser parser, ParseInput input) { + ParseResult result = ParsingPackageUtils.parseMetaData(pkg, component, + resources, parser, "", input); + if (result.isError()) { + return input.error(result); + } + final Property property = result.getResult(); + if (property != null) { + component.addProperty(property); + } + return input.success(property); + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java new file mode 100644 index 000000000000..07322e9dd912 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide */ +@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedInstrumentationImpl extends ParsedComponentImpl implements + ParsedInstrumentation, Parcelable { + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String targetPackage; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String targetProcesses; + private boolean handleProfiling; + private boolean functionalTest; + + public ParsedInstrumentationImpl() { + } + + public ParsedInstrumentationImpl setTargetPackage(@Nullable String targetPackage) { + this.targetPackage = TextUtils.safeIntern(targetPackage); + return this; + } + + public ParsedInstrumentationImpl setTargetProcesses(@Nullable String targetProcesses) { + this.targetProcesses = TextUtils.safeIntern(targetProcesses); + return this; + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Instrumentation{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + sForInternedString.parcel(this.targetPackage, dest, flags); + sForInternedString.parcel(this.targetProcesses, dest, flags); + dest.writeBoolean(this.handleProfiling); + dest.writeBoolean(this.functionalTest); + } + + protected ParsedInstrumentationImpl(Parcel in) { + super(in); + this.targetPackage = sForInternedString.unparcel(in); + this.targetProcesses = sForInternedString.unparcel(in); + this.handleProfiling = in.readByte() != 0; + this.functionalTest = in.readByte() != 0; + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public ParsedInstrumentationImpl createFromParcel(Parcel source) { + return new ParsedInstrumentationImpl(source); + } + + @Override + public ParsedInstrumentationImpl[] newArray(int size) { + return new ParsedInstrumentationImpl[size]; + } + }; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedInstrumentationImpl( + @Nullable String targetPackage, + @Nullable String targetProcesses, + boolean handleProfiling, + boolean functionalTest) { + this.targetPackage = targetPackage; + this.targetProcesses = targetProcesses; + this.handleProfiling = handleProfiling; + this.functionalTest = functionalTest; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @Nullable String getTargetPackage() { + return targetPackage; + } + + @DataClass.Generated.Member + public @Nullable String getTargetProcesses() { + return targetProcesses; + } + + @DataClass.Generated.Member + public boolean isHandleProfiling() { + return handleProfiling; + } + + @DataClass.Generated.Member + public boolean isFunctionalTest() { + return functionalTest; + } + + @DataClass.Generated.Member + public @NonNull ParsedInstrumentationImpl setHandleProfiling( boolean value) { + handleProfiling = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedInstrumentationImpl setFunctionalTest( boolean value) { + functionalTest = value; + return this; + } + + @DataClass.Generated( + time = 1701445763455L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java", + inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java new file mode 100644 index 000000000000..661c8b421fb4 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET; + +import android.annotation.NonNull; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; + +import com.android.internal.R; +import com.android.internal.pm.pkg.parsing.ParsingPackage; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** + * @hide + */ +public class ParsedInstrumentationUtils { + + @NonNull + public static ParseResult parseInstrumentation(ParsingPackage pkg, + Resources res, XmlResourceParser parser, boolean useRoundIcon, + ParseInput input) throws IOException, XmlPullParserException { + ParsedInstrumentationImpl + instrumentation = new ParsedInstrumentationImpl(); + String tag = "<" + parser.getName() + ">"; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation); + try { + ParseResult result = ParsedComponentUtils.parseComponent( + instrumentation, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestInstrumentation_banner, + NOT_SET /*descriptionAttr*/, + R.styleable.AndroidManifestInstrumentation_icon, + R.styleable.AndroidManifestInstrumentation_label, + R.styleable.AndroidManifestInstrumentation_logo, + R.styleable.AndroidManifestInstrumentation_name, + R.styleable.AndroidManifestInstrumentation_roundIcon); + if (result.isError()) { + return input.error(result); + } + + // @formatter:off + // Note: don't allow this value to be a reference to a resource + // that may change. + instrumentation.setTargetPackage(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage)) + .setTargetProcesses(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetProcesses)) + .setHandleProfiling(sa.getBoolean(R.styleable.AndroidManifestInstrumentation_handleProfiling, false)) + .setFunctionalTest(sa.getBoolean(R.styleable.AndroidManifestInstrumentation_functionalTest, false)); + // @formatter:on + } finally { + sa.recycle(); + } + + ParseResult result = + ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, instrumentation, input); + + if (result.isError()) { + return input.error(result); + } + + return input.success(result.getResult()); + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java new file mode 100644 index 000000000000..adb49e9fde6d --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.IntentFilter; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; + +/** + * @hide + **/ +@DataClass(genGetters = true, genSetters = true, genParcelable = true, genAidl = false, + genBuilder = false, genConstructor = false) +@DataClass.Suppress({"setIntentFilter"}) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedIntentInfoImpl implements ParsedIntentInfo, Parcelable { + + private boolean mHasDefault; + private int mLabelRes; + @Nullable + private CharSequence mNonLocalizedLabel; + private int mIcon; + + @NonNull + private IntentFilter mIntentFilter = new IntentFilter(); + + public ParsedIntentInfoImpl() {} + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public boolean isHasDefault() { + return mHasDefault; + } + + @DataClass.Generated.Member + public int getLabelRes() { + return mLabelRes; + } + + @DataClass.Generated.Member + public @Nullable CharSequence getNonLocalizedLabel() { + return mNonLocalizedLabel; + } + + @DataClass.Generated.Member + public int getIcon() { + return mIcon; + } + + @DataClass.Generated.Member + public @NonNull IntentFilter getIntentFilter() { + return mIntentFilter; + } + + @DataClass.Generated.Member + public @NonNull ParsedIntentInfoImpl setHasDefault( boolean value) { + mHasDefault = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedIntentInfoImpl setLabelRes( int value) { + mLabelRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedIntentInfoImpl setNonLocalizedLabel(@NonNull CharSequence value) { + mNonLocalizedLabel = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedIntentInfoImpl setIcon( int value) { + mIcon = value; + return this; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mHasDefault) flg |= 0x1; + if (mNonLocalizedLabel != null) flg |= 0x4; + dest.writeByte(flg); + dest.writeInt(mLabelRes); + if (mNonLocalizedLabel != null) dest.writeCharSequence(mNonLocalizedLabel); + dest.writeInt(mIcon); + dest.writeTypedObject(mIntentFilter, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParsedIntentInfoImpl(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + boolean hasDefault = (flg & 0x1) != 0; + int labelRes = in.readInt(); + CharSequence nonLocalizedLabel = (flg & 0x4) == 0 ? null : (CharSequence) in.readCharSequence(); + int icon = in.readInt(); + IntentFilter intentFilter = (IntentFilter) in.readTypedObject(IntentFilter.CREATOR); + + this.mHasDefault = hasDefault; + this.mLabelRes = labelRes; + this.mNonLocalizedLabel = nonLocalizedLabel; + this.mIcon = icon; + this.mIntentFilter = intentFilter; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mIntentFilter); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public ParsedIntentInfoImpl[] newArray(int size) { + return new ParsedIntentInfoImpl[size]; + } + + @Override + public ParsedIntentInfoImpl createFromParcel(@NonNull Parcel in) { + return new ParsedIntentInfoImpl(in); + } + }; + + @DataClass.Generated( + time = 1701445800363L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java", + inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java new file mode 100644 index 000000000000..c6683cfc8331 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE; + +import android.annotation.NonNull; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.PatternMatcher; +import android.util.Slog; +import android.util.TypedValue; + +import com.android.internal.R; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Iterator; + +/** @hide */ +public class ParsedIntentInfoUtils { + + private static final String TAG = ParsingUtils.TAG; + + public static final boolean DEBUG = false; + + @NonNull + public static ParseResult parseIntentInfo(String className, + ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs, + boolean allowAutoVerify, ParseInput input) + throws XmlPullParserException, IOException { + ParsedIntentInfoImpl intentInfo = new ParsedIntentInfoImpl(); + IntentFilter intentFilter = intentInfo.getIntentFilter(); + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestIntentFilter); + try { + intentFilter.setPriority( + sa.getInt(R.styleable.AndroidManifestIntentFilter_priority, 0)); + intentFilter.setOrder(sa.getInt(R.styleable.AndroidManifestIntentFilter_order, 0)); + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestIntentFilter_label); + if (v != null) { + intentInfo.setLabelRes(v.resourceId); + if (v.resourceId == 0) { + intentInfo.setNonLocalizedLabel(v.coerceToString()); + } + } + + if (ParsingPackageUtils.sUseRoundIcon) { + intentInfo.setIcon(sa.getResourceId( + R.styleable.AndroidManifestIntentFilter_roundIcon, 0)); + } + + if (intentInfo.getIcon() == 0) { + intentInfo.setIcon( + sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0)); + } + + if (allowAutoVerify) { + intentFilter.setAutoVerify(sa.getBoolean( + R.styleable.AndroidManifestIntentFilter_autoVerify, + false)); + } + } finally { + sa.recycle(); + } + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + String nodeName = parser.getName(); + switch (nodeName) { + case "action": { + String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name"); + if (value == null) { + result = input.error("No value supplied for "); + } else if (value.isEmpty()) { + intentFilter.addAction(value); + // Prior to R, this was not a failure + result = input.deferError("No value supplied for ", + ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY); + } else { + intentFilter.addAction(value); + result = input.success(null); + } + break; + } + case "category": { + String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name"); + if (value == null) { + result = input.error("No value supplied for "); + } else if (value.isEmpty()) { + intentFilter.addCategory(value); + // Prior to R, this was not a failure + result = input.deferError("No value supplied for ", + ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY); + } else { + intentFilter.addCategory(value); + result = input.success(null); + } + break; + } + case "data": + result = parseData(intentInfo, res, parser, allowGlobs, input); + break; + default: + result = ParsingUtils.unknownTag("", pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + intentInfo.setHasDefault(intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)); + + if (DEBUG) { + final StringBuilder cats = new StringBuilder("Intent d="); + cats.append(intentInfo.isHasDefault()); + cats.append(", cat="); + + final Iterator it = intentFilter.categoriesIterator(); + if (it != null) { + while (it.hasNext()) { + cats.append(' '); + cats.append(it.next()); + } + } + Slog.d(TAG, cats.toString()); + } + + return input.success(intentInfo); + } + + @NonNull + private static ParseResult parseData(ParsedIntentInfo intentInfo, + Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) { + IntentFilter intentFilter = intentInfo.getIntentFilter(); + TypedArray sa = resources.obtainAttributes(parser, R.styleable.AndroidManifestData); + try { + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_mimeType, 0); + if (str != null) { + try { + intentFilter.addDataType(str); + } catch (IntentFilter.MalformedMimeTypeException e) { + return input.error(e.toString()); + } + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_mimeGroup, 0); + if (str != null) { + intentFilter.addMimeGroup(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_scheme, 0); + if (str != null) { + intentFilter.addDataScheme(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_ssp, 0); + if (str != null) { + intentFilter.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPrefix, 0); + if (str != null) { + intentFilter.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPattern, 0); + if (str != null) { + if (!allowGlobs) { + return input.error( + "sspPattern not allowed here; ssp must be literal"); + } + intentFilter.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspAdvancedPattern, 0); + if (str != null) { + if (!allowGlobs) { + return input.error( + "sspAdvancedPattern not allowed here; ssp must be literal"); + } + intentFilter.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_ADVANCED_GLOB); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspSuffix, 0); + if (str != null) { + intentFilter.addDataSchemeSpecificPart(str, + PatternMatcher.PATTERN_SUFFIX); + } + + + String host = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_host, 0); + String port = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_port, 0); + if (host != null) { + intentFilter.addDataAuthority(host, port); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_path, 0); + if (str != null) { + intentFilter.addDataPath(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPrefix, 0); + if (str != null) { + intentFilter.addDataPath(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPattern, 0); + if (str != null) { + if (!allowGlobs) { + return input.error( + "pathPattern not allowed here; path must be literal"); + } + intentFilter.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathAdvancedPattern, 0); + if (str != null) { + if (!allowGlobs) { + return input.error( + "pathAdvancedPattern not allowed here; path must be literal"); + } + intentFilter.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathSuffix, 0); + if (str != null) { + intentFilter.addDataPath(str, PatternMatcher.PATTERN_SUFFIX); + } + + + return input.success(null); + } finally { + sa.recycle(); + } + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java new file mode 100644 index 000000000000..bb8f565d2032 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +import libcore.util.EmptyArray; + +/** + * @hide + */ +@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedMainComponentImpl extends ParsedComponentImpl implements ParsedMainComponent, + Parcelable { + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String processName; + private boolean directBootAware; + private boolean enabled = true; + private boolean exported; + private int order; + + @Nullable + private String splitName; + @Nullable + private String[] attributionTags; + + public ParsedMainComponentImpl() { + } + + public ParsedMainComponentImpl(ParsedMainComponent other) { + super(other); + this.processName = other.getProcessName(); + this.directBootAware = other.isDirectBootAware(); + this.enabled = other.isEnabled(); + this.exported = other.isExported(); + this.order = other.getOrder(); + this.splitName = other.getSplitName(); + this.attributionTags = other.getAttributionTags(); + } + + public ParsedMainComponentImpl setProcessName(String processName) { + this.processName = TextUtils.safeIntern(processName); + return this; + } + + /** + * A main component's name is a class name. This makes code slightly more readable. + */ + public String getClassName() { + return getName(); + } + + @NonNull + @Override + public String[] getAttributionTags() { + return attributionTags == null ? EmptyArray.STRING : attributionTags; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + sForInternedString.parcel(this.processName, dest, flags); + dest.writeBoolean(this.directBootAware); + dest.writeBoolean(this.enabled); + dest.writeBoolean(this.exported); + dest.writeInt(this.order); + dest.writeString(this.splitName); + dest.writeString8Array(this.attributionTags); + } + + protected ParsedMainComponentImpl(Parcel in) { + super(in); + this.processName = sForInternedString.unparcel(in); + this.directBootAware = in.readBoolean(); + this.enabled = in.readBoolean(); + this.exported = in.readBoolean(); + this.order = in.readInt(); + this.splitName = in.readString(); + this.attributionTags = in.createString8Array(); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public ParsedMainComponentImpl createFromParcel(Parcel source) { + return new ParsedMainComponentImpl(source); + } + + @Override + public ParsedMainComponentImpl[] newArray(int size) { + return new ParsedMainComponentImpl[size]; + } + }; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedMainComponentImpl( + @Nullable String processName, + boolean directBootAware, + boolean enabled, + boolean exported, + int order, + @Nullable String splitName, + @Nullable String[] attributionTags) { + this.processName = processName; + this.directBootAware = directBootAware; + this.enabled = enabled; + this.exported = exported; + this.order = order; + this.splitName = splitName; + this.attributionTags = attributionTags; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @Nullable String getProcessName() { + return processName; + } + + @DataClass.Generated.Member + public boolean isDirectBootAware() { + return directBootAware; + } + + @DataClass.Generated.Member + public boolean isEnabled() { + return enabled; + } + + @DataClass.Generated.Member + public boolean isExported() { + return exported; + } + + @DataClass.Generated.Member + public int getOrder() { + return order; + } + + @DataClass.Generated.Member + public @Nullable String getSplitName() { + return splitName; + } + + @DataClass.Generated.Member + public @NonNull ParsedMainComponentImpl setDirectBootAware( boolean value) { + directBootAware = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedMainComponentImpl setEnabled( boolean value) { + enabled = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedMainComponentImpl setExported( boolean value) { + exported = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedMainComponentImpl setOrder( int value) { + order = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedMainComponentImpl setSplitName(@NonNull String value) { + splitName = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedMainComponentImpl setAttributionTags(@NonNull String... value) { + attributionTags = value; + return this; + } + + @DataClass.Generated( + time = 1701447884766L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java", + inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java new file mode 100644 index 000000000000..7e56180f72ce --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.IntentFilter; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +class ParsedMainComponentUtils { + + private static final String TAG = ParsingUtils.TAG; + + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + static ParseResult parseMainComponent( + Component component, String tag, String[] separateProcesses, ParsingPackage pkg, + TypedArray array, int flags, boolean useRoundIcon, @Nullable String defaultSplitName, + @NonNull ParseInput input, int bannerAttr, int descriptionAttr, int directBootAwareAttr, + int enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, + int processAttr, int roundIconAttr, int splitNameAttr, int attributionTagsAttr) { + ParseResult result = ParsedComponentUtils.parseComponent(component, tag, pkg, + array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr, + logoAttr, nameAttr, roundIconAttr); + if (result.isError()) { + return result; + } + + if (directBootAwareAttr != NOT_SET) { + component.setDirectBootAware(array.getBoolean(directBootAwareAttr, false)); + if (component.isDirectBootAware()) { + pkg.setPartiallyDirectBootAware(true); + } + } + + if (enabledAttr != NOT_SET) { + component.setEnabled(array.getBoolean(enabledAttr, true)); + } + + if (processAttr != NOT_SET) { + CharSequence processName; + if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + processName = array.getNonConfigurationString(processAttr, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + processName = array.getNonResourceString(processAttr); + } + + // Backwards-compat, ignore error + ParseResult processNameResult = ComponentParseUtils.buildProcessName( + pkg.getPackageName(), pkg.getProcessName(), processName, flags, + separateProcesses, input); + if (processNameResult.isError()) { + return input.error(processNameResult); + } + + component.setProcessName(processNameResult.getResult()); + } + + if (splitNameAttr != NOT_SET) { + component.setSplitName(array.getNonConfigurationString(splitNameAttr, 0)); + } + + if (defaultSplitName != null && component.getSplitName() == null) { + component.setSplitName(defaultSplitName); + } + + if (attributionTagsAttr != NOT_SET) { + final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0); + if (attributionTags != null) { + component.setAttributionTags(attributionTags.split("\\|")); + } + } + + return input.success(component); + } + + static ParseResult parseIntentFilter( + ParsedMainComponent mainComponent, + ParsingPackage pkg, Resources resources, XmlResourceParser parser, + boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify, + boolean allowImplicitEphemeralVisibility, boolean failOnNoActions, + ParseInput input) throws IOException, XmlPullParserException { + ParseResult intentResult = ParsedIntentInfoUtils.parseIntentInfo( + mainComponent.getName(), pkg, resources, parser, allowGlobs, + allowAutoVerify, input); + if (intentResult.isError()) { + return input.error(intentResult); + } + + ParsedIntentInfo intent = intentResult.getResult(); + IntentFilter intentFilter = intent.getIntentFilter(); + int actionCount = intentFilter.countActions(); + if (actionCount == 0 && failOnNoActions) { + Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseApkPath() + " " + + parser.getPositionDescription()); + // Backward-compat, do not actually fail + return input.success(null); + } + + int intentVisibility; + if (visibleToEphemeral) { + intentVisibility = IntentFilter.VISIBILITY_EXPLICIT; + } else if (allowImplicitEphemeralVisibility + && ComponentParseUtils.isImplicitlyExposedIntent(intent)){ + intentVisibility = IntentFilter.VISIBILITY_IMPLICIT; + } else { + intentVisibility = IntentFilter.VISIBILITY_NONE; + } + intentFilter.setVisibilityToInstantApp(intentVisibility); + + return input.success(intentResult.getResult()); + } + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java new file mode 100644 index 000000000000..3622019f36b9 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; + +/** + * @hide + */ +@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = true, + genAidl = false) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedPermissionGroupImpl extends ParsedComponentImpl implements + ParsedPermissionGroup, Parcelable { + + private int requestDetailRes; + private int backgroundRequestRes; + private int backgroundRequestDetailRes; + private int requestRes; + private int priority; + + public String toString() { + return "PermissionGroup{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + getName() + "}"; + } + + public ParsedPermissionGroupImpl() { + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(requestDetailRes); + dest.writeInt(backgroundRequestRes); + dest.writeInt(backgroundRequestDetailRes); + dest.writeInt(requestRes); + dest.writeInt(priority); + } + + protected ParsedPermissionGroupImpl(@NonNull Parcel in) { + super(in); + this.requestDetailRes = in.readInt(); + this.backgroundRequestRes = in.readInt(); + this.backgroundRequestDetailRes = in.readInt(); + this.requestRes = in.readInt(); + this.priority = in.readInt(); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedPermissionGroupImpl( + int requestDetailRes, + int backgroundRequestRes, + int backgroundRequestDetailRes, + int requestRes, + int priority) { + this.requestDetailRes = requestDetailRes; + this.backgroundRequestRes = backgroundRequestRes; + this.backgroundRequestDetailRes = backgroundRequestDetailRes; + this.requestRes = requestRes; + this.priority = priority; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public int getRequestDetailRes() { + return requestDetailRes; + } + + @DataClass.Generated.Member + public int getBackgroundRequestRes() { + return backgroundRequestRes; + } + + @DataClass.Generated.Member + public int getBackgroundRequestDetailRes() { + return backgroundRequestDetailRes; + } + + @DataClass.Generated.Member + public int getRequestRes() { + return requestRes; + } + + @DataClass.Generated.Member + public int getPriority() { + return priority; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionGroupImpl setRequestDetailRes( int value) { + requestDetailRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionGroupImpl setBackgroundRequestRes( int value) { + backgroundRequestRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionGroupImpl setBackgroundRequestDetailRes( int value) { + backgroundRequestDetailRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionGroupImpl setRequestRes( int value) { + requestRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionGroupImpl setPriority( int value) { + priority = value; + return this; + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public ParsedPermissionGroupImpl[] newArray(int size) { + return new ParsedPermissionGroupImpl[size]; + } + + @Override + public ParsedPermissionGroupImpl createFromParcel(@NonNull Parcel in) { + return new ParsedPermissionGroupImpl(in); + } + }; + + @DataClass.Generated( + time = 1701445837884L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java", + inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java new file mode 100644 index 000000000000..4dcce131168b --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; +import android.util.ArraySet; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; +import com.android.internal.util.Parcelling.BuiltIn.ForStringSet; + +import java.util.Collections; +import java.util.Locale; +import java.util.Set; + +/** + * @hide + */ +@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedPermission, + Parcelable { + + private static final ForStringSet sForStringSet = + Parcelling.Cache.getOrCreate(ForStringSet.class); + + @Nullable + private String backgroundPermission; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String group; + private int requestRes; + private int protectionLevel; + private boolean tree; + @Nullable + private ParsedPermissionGroup parsedPermissionGroup; + @Nullable + private Set knownCerts; + + @VisibleForTesting + public ParsedPermissionImpl() { + } + + public ParsedPermissionGroup getParsedPermissionGroup() { + return parsedPermissionGroup; + } + + public ParsedPermissionImpl setGroup(String group) { + this.group = TextUtils.safeIntern(group); + return this; + } + + protected void setKnownCert(String knownCert) { + // Convert the provided digest to upper case for consistent Set membership + // checks when verifying the signing certificate digests of requesting apps. + this.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); + } + + protected void setKnownCerts(String[] knownCerts) { + this.knownCerts = new ArraySet<>(); + for (String knownCert : knownCerts) { + this.knownCerts.add(knownCert.toUpperCase(Locale.US)); + } + } + + @NonNull + @Override + public Set getKnownCerts() { + return knownCerts == null ? Collections.emptySet() : knownCerts; + } + + public String toString() { + return "Permission{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + getName() + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.backgroundPermission); + dest.writeString(this.group); + dest.writeInt(this.requestRes); + dest.writeInt(this.protectionLevel); + dest.writeBoolean(this.tree); + dest.writeParcelable((ParsedPermissionGroupImpl) this.parsedPermissionGroup, flags); + sForStringSet.parcel(knownCerts, dest, flags); + } + + protected ParsedPermissionImpl(Parcel in) { + super(in); + this.backgroundPermission = in.readString(); + this.group = TextUtils.safeIntern(in.readString()); + this.requestRes = in.readInt(); + this.protectionLevel = in.readInt(); + this.tree = in.readBoolean(); + this.parsedPermissionGroup = in.readParcelable( + ParsedPermissionGroupImpl.class.getClassLoader(), ParsedPermissionGroupImpl.class); + this.knownCerts = sForStringSet.unparcel(in); + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public ParsedPermissionImpl createFromParcel(Parcel source) { + return new ParsedPermissionImpl(source); + } + + @Override + public ParsedPermissionImpl[] newArray(int size) { + return new ParsedPermissionImpl[size]; + } + }; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedPermissionImpl( + @Nullable String backgroundPermission, + @Nullable String group, + int requestRes, + int protectionLevel, + boolean tree, + @Nullable ParsedPermissionGroup parsedPermissionGroup, + @Nullable Set knownCerts) { + this.backgroundPermission = backgroundPermission; + this.group = group; + this.requestRes = requestRes; + this.protectionLevel = protectionLevel; + this.tree = tree; + this.parsedPermissionGroup = parsedPermissionGroup; + this.knownCerts = knownCerts; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @Nullable String getBackgroundPermission() { + return backgroundPermission; + } + + @DataClass.Generated.Member + public @Nullable String getGroup() { + return group; + } + + @DataClass.Generated.Member + public int getRequestRes() { + return requestRes; + } + + @DataClass.Generated.Member + public int getProtectionLevel() { + return protectionLevel; + } + + @DataClass.Generated.Member + public boolean isTree() { + return tree; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionImpl setBackgroundPermission(@NonNull String value) { + backgroundPermission = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionImpl setRequestRes( int value) { + requestRes = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionImpl setProtectionLevel( int value) { + protectionLevel = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionImpl setTree( boolean value) { + tree = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionImpl setParsedPermissionGroup(@NonNull ParsedPermissionGroup value) { + parsedPermissionGroup = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedPermissionImpl setKnownCerts(@NonNull Set value) { + knownCerts = value; + return this; + } + + @DataClass.Generated( + time = 1701445829812L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java", + inputSignatures = "private static final com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable com.android.internal.pm.pkg.component.ParsedPermissionGroup parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic com.android.internal.pm.pkg.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic com.android.internal.pm.pkg.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java new file mode 100644 index 000000000000..5651c1ca247f --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET; + +import android.annotation.NonNull; +import android.content.pm.PermissionInfo; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.util.ArrayMap; +import android.util.EventLog; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +/** + * @hide + */ +public class ParsedPermissionUtils { + + private static final String TAG = ParsingUtils.TAG; + + @NonNull + public static ParseResult parsePermission(ParsingPackage pkg, Resources res, + XmlResourceParser parser, boolean useRoundIcon, ParseInput input) + throws IOException, XmlPullParserException { + String packageName = pkg.getPackageName(); + ParsedPermissionImpl permission = new ParsedPermissionImpl(); + String tag = "<" + parser.getName() + ">"; + ParseResult result; + + try (TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission)) { + result = ParsedComponentUtils.parseComponent( + permission, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestPermission_banner, + R.styleable.AndroidManifestPermission_description, + R.styleable.AndroidManifestPermission_icon, + R.styleable.AndroidManifestPermission_label, + R.styleable.AndroidManifestPermission_logo, + R.styleable.AndroidManifestPermission_name, + R.styleable.AndroidManifestPermission_roundIcon); + if (result.isError()) { + return input.error(result); + } + + int maxSdkVersion = sa.getInt(R.styleable.AndroidManifestPermission_maxSdkVersion, -1); + if ((maxSdkVersion != -1) && (maxSdkVersion < Build.VERSION.SDK_INT)) { + return input.success(null); + } + + if (sa.hasValue( + R.styleable.AndroidManifestPermission_backgroundPermission)) { + if ("android".equals(packageName)) { + permission.setBackgroundPermission(sa.getNonResourceString( + R.styleable.AndroidManifestPermission_backgroundPermission)); + } else { + Slog.w(TAG, packageName + " defines a background permission. Only the " + + "'android' package can do that."); + } + } + + // Note: don't allow this value to be a reference to a resource + // that may change. + permission.setGroup(sa.getNonResourceString( + R.styleable.AndroidManifestPermission_permissionGroup)) + .setRequestRes(sa.getResourceId( + R.styleable.AndroidManifestPermission_request, 0)) + .setProtectionLevel(sa.getInt( + R.styleable.AndroidManifestPermission_protectionLevel, + PermissionInfo.PROTECTION_NORMAL)) + .setFlags(sa.getInt( + R.styleable.AndroidManifestPermission_permissionFlags, 0)); + + final int knownCertsResource = sa.getResourceId( + R.styleable.AndroidManifestPermission_knownCerts, 0); + if (knownCertsResource != 0) { + // The knownCerts attribute supports both a string array resource as well as a + // string resource for the case where the permission should only be granted to a + // single known signer. + final String resourceType = res.getResourceTypeName(knownCertsResource); + if (resourceType.equals("array")) { + final String[] knownCerts = res.getStringArray(knownCertsResource); + if (knownCerts != null) { + permission.setKnownCerts(knownCerts); + } + } else { + final String knownCert = res.getString(knownCertsResource); + if (knownCert != null) { + permission.setKnownCert(knownCert); + } + } + if (permission.getKnownCerts().isEmpty()) { + Slog.w(TAG, packageName + " defines a knownSigner permission but" + + " the provided knownCerts resource is null"); + } + } else { + // If the knownCerts resource ID is null check if the app specified a string + // value for the attribute representing a single trusted signer. + final String knownCert = sa.getString( + R.styleable.AndroidManifestPermission_knownCerts); + if (knownCert != null) { + permission.setKnownCert(knownCert); + } + } + + // For now only platform runtime permissions can be restricted + if (!isRuntime(permission) || !"android".equals(permission.getPackageName())) { + permission.setFlags(permission.getFlags() & ~PermissionInfo.FLAG_HARD_RESTRICTED); + permission.setFlags(permission.getFlags() & ~PermissionInfo.FLAG_SOFT_RESTRICTED); + } else { + // The platform does not get to specify conflicting permissions + if ((permission.getFlags() & PermissionInfo.FLAG_HARD_RESTRICTED) != 0 + && (permission.getFlags() & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) { + throw new IllegalStateException("Permission cannot be both soft and hard" + + " restricted: " + permission.getName()); + } + } + } + + permission.setProtectionLevel( + PermissionInfo.fixProtectionLevel(permission.getProtectionLevel())); + + final int otherProtectionFlags = getProtectionFlags(permission) + & ~(PermissionInfo.PROTECTION_FLAG_APPOP | PermissionInfo.PROTECTION_FLAG_INSTANT + | PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY); + if (otherProtectionFlags != 0 + && getProtection(permission) != PermissionInfo.PROTECTION_SIGNATURE + && getProtection(permission) != PermissionInfo.PROTECTION_INTERNAL) { + return input.error(" protectionLevel specifies a non-instant, non-appop," + + " non-runtimeOnly flag but is not based on signature or internal type"); + } + + result = ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, input); + if (result.isError()) { + return input.error(result); + } + + return input.success(result.getResult()); + } + + @NonNull + public static ParseResult parsePermissionTree(ParsingPackage pkg, Resources res, + XmlResourceParser parser, boolean useRoundIcon, ParseInput input) + throws IOException, XmlPullParserException { + ParsedPermissionImpl permission = new ParsedPermissionImpl(); + String tag = "<" + parser.getName() + ">"; + ParseResult result; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree); + try { + result = ParsedComponentUtils.parseComponent( + permission, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestPermissionTree_banner, + NOT_SET /*descriptionAttr*/, + R.styleable.AndroidManifestPermissionTree_icon, + R.styleable.AndroidManifestPermissionTree_label, + R.styleable.AndroidManifestPermissionTree_logo, + R.styleable.AndroidManifestPermissionTree_name, + R.styleable.AndroidManifestPermissionTree_roundIcon); + if (result.isError()) { + return input.error(result); + } + } finally { + sa.recycle(); + } + + int index = permission.getName().indexOf('.'); + if (index > 0) { + index = permission.getName().indexOf('.', index + 1); + } + if (index < 0) { + return input.error(" name has less than three segments: " + + permission.getName()); + } + + permission.setProtectionLevel(PermissionInfo.PROTECTION_NORMAL) + .setTree(true); + + result = ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, input); + if (result.isError()) { + return input.error(result); + } + + return input.success(result.getResult()); + } + + @NonNull + public static ParseResult parsePermissionGroup(ParsingPackage pkg, + Resources res, XmlResourceParser parser, boolean useRoundIcon, ParseInput input) + throws IOException, XmlPullParserException { + ParsedPermissionGroupImpl + permissionGroup = new ParsedPermissionGroupImpl(); + String tag = "<" + parser.getName() + ">"; + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup); + try { + ParseResult result = ParsedComponentUtils.parseComponent( + permissionGroup, tag, pkg, sa, useRoundIcon, input, + R.styleable.AndroidManifestPermissionGroup_banner, + R.styleable.AndroidManifestPermissionGroup_description, + R.styleable.AndroidManifestPermissionGroup_icon, + R.styleable.AndroidManifestPermissionGroup_label, + R.styleable.AndroidManifestPermissionGroup_logo, + R.styleable.AndroidManifestPermissionGroup_name, + R.styleable.AndroidManifestPermissionGroup_roundIcon); + if (result.isError()) { + return input.error(result); + } + + // @formatter:off + permissionGroup.setRequestDetailRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_requestDetail, 0)) + .setBackgroundRequestRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequest, 0)) + .setBackgroundRequestDetailRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequestDetail, 0)) + .setRequestRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_request, 0)) + .setPriority(sa.getInt(R.styleable.AndroidManifestPermissionGroup_priority, 0)) + .setFlags(sa.getInt(R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,0)); + // @formatter:on + } finally { + sa.recycle(); + } + + ParseResult result = ComponentParseUtils.parseAllMetaData(pkg, + res, parser, tag, permissionGroup, input); + if (result.isError()) { + return input.error(result); + } + + return input.success(result.getResult()); + } + + public static boolean isRuntime(@NonNull ParsedPermission permission) { + return getProtection(permission) == PermissionInfo.PROTECTION_DANGEROUS; + } + + public static boolean isAppOp(@NonNull ParsedPermission permission) { + return (permission.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; + } + + @PermissionInfo.Protection + public static int getProtection(@NonNull ParsedPermission permission) { + return permission.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE; + } + + public static int getProtectionFlags(@NonNull ParsedPermission permission) { + return permission.getProtectionLevel() & ~PermissionInfo.PROTECTION_MASK_BASE; + } + + public static int calculateFootprint(@NonNull ParsedPermission permission) { + int size = permission.getName().length(); + CharSequence nonLocalizedLabel = permission.getNonLocalizedLabel(); + if (nonLocalizedLabel != null) { + size += nonLocalizedLabel.length(); + } + return size; + } + + /** + * Determines if a duplicate permission is malformed .i.e. defines different protection level + * or group. + */ + private static boolean isMalformedDuplicate(ParsedPermission p1, ParsedPermission p2) { + // Since a permission tree is also added as a permission with normal protection + // level, we need to skip if the parsedPermission is a permission tree. + if (p1 == null || p2 == null || p1.isTree() || p2.isTree()) { + return false; + } + + if (p1.getProtectionLevel() != p2.getProtectionLevel()) { + return true; + } + if (!Objects.equals(p1.getGroup(), p2.getGroup())) { + return true; + } + + return false; + } + + /** + * @return {@code true} if the package declares malformed duplicate permissions. + */ + public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) { + final List permissions = pkg.getPermissions(); + final int size = permissions.size(); + if (size > 0) { + final ArrayMap checkDuplicatePerm = new ArrayMap<>(size); + for (int i = 0; i < size; i++) { + final ParsedPermission parsedPermission = permissions.get(i); + final String name = parsedPermission.getName(); + final ParsedPermission perm = checkDuplicatePerm.get(name); + if (isMalformedDuplicate(parsedPermission, perm)) { + // Fix for b/213323615 + EventLog.writeEvent(0x534e4554, "213323615"); + return true; + } + checkDuplicatePerm.put(name, parsedPermission); + } + } + return false; + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java new file mode 100644 index 000000000000..212fb867e7df --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static java.util.Collections.emptySet; + +import android.annotation.NonNull; +import android.content.pm.ApplicationInfo; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArrayMap; +import android.util.ArraySet; + +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; + +import java.util.Set; + +/** @hide */ +@DataClass(genGetters = true, genSetters = true, genParcelable = true, genAidl = false, + genBuilder = false) +public class ParsedProcessImpl implements ParsedProcess, Parcelable { + + @NonNull + private String name; + + /** @see ParsedProcess#getAppClassNamesByPackage() */ + @NonNull + private ArrayMap appClassNamesByPackage = ArrayMap.EMPTY; + + @NonNull + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) + private Set deniedPermissions = emptySet(); + + @ApplicationInfo.GwpAsanMode + private int gwpAsanMode = ApplicationInfo.GWP_ASAN_DEFAULT; + @ApplicationInfo.MemtagMode + private int memtagMode = ApplicationInfo.MEMTAG_DEFAULT; + @ApplicationInfo.NativeHeapZeroInitialized + private int nativeHeapZeroInitialized = ApplicationInfo.ZEROINIT_DEFAULT; + + public ParsedProcessImpl() { + } + + public ParsedProcessImpl(@NonNull ParsedProcess other) { + name = other.getName(); + appClassNamesByPackage = (other.getAppClassNamesByPackage().size() == 0) + ? ArrayMap.EMPTY : new ArrayMap<>(other.getAppClassNamesByPackage()); + deniedPermissions = new ArraySet<>(other.getDeniedPermissions()); + gwpAsanMode = other.getGwpAsanMode(); + memtagMode = other.getMemtagMode(); + nativeHeapZeroInitialized = other.getNativeHeapZeroInitialized(); + } + + public void addStateFrom(@NonNull ParsedProcess other) { + deniedPermissions = CollectionUtils.addAll(deniedPermissions, other.getDeniedPermissions()); + gwpAsanMode = other.getGwpAsanMode(); + memtagMode = other.getMemtagMode(); + nativeHeapZeroInitialized = other.getNativeHeapZeroInitialized(); + + final ArrayMap oacn = other.getAppClassNamesByPackage(); + for (int i = 0; i < oacn.size(); i++) { + appClassNamesByPackage.put(oacn.keyAt(i), oacn.valueAt(i)); + } + } + + /** + * Sets a custom application name used in this process for a given package. + */ + public void putAppClassNameForPackage(String packageName, String className) { + if (appClassNamesByPackage.size() == 0) { + appClassNamesByPackage = new ArrayMap<>(4); + } + appClassNamesByPackage.put(packageName, className); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new ParsedProcessImpl. + * + */ + @DataClass.Generated.Member + public ParsedProcessImpl( + @NonNull String name, + @NonNull ArrayMap appClassNamesByPackage, + @NonNull Set deniedPermissions, + @ApplicationInfo.GwpAsanMode int gwpAsanMode, + @ApplicationInfo.MemtagMode int memtagMode, + @ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized) { + this.name = name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.appClassNamesByPackage = appClassNamesByPackage; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, appClassNamesByPackage); + this.deniedPermissions = deniedPermissions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, deniedPermissions); + this.gwpAsanMode = gwpAsanMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); + this.memtagMode = memtagMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.MemtagMode.class, null, memtagMode); + this.nativeHeapZeroInitialized = nativeHeapZeroInitialized; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.NativeHeapZeroInitialized.class, null, nativeHeapZeroInitialized); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull String getName() { + return name; + } + + /** + * @see ParsedProcess#getAppClassNamesByPackage() + */ + @DataClass.Generated.Member + public @NonNull ArrayMap getAppClassNamesByPackage() { + return appClassNamesByPackage; + } + + @DataClass.Generated.Member + public @NonNull Set getDeniedPermissions() { + return deniedPermissions; + } + + @DataClass.Generated.Member + public @ApplicationInfo.GwpAsanMode int getGwpAsanMode() { + return gwpAsanMode; + } + + @DataClass.Generated.Member + public @ApplicationInfo.MemtagMode int getMemtagMode() { + return memtagMode; + } + + @DataClass.Generated.Member + public @ApplicationInfo.NativeHeapZeroInitialized int getNativeHeapZeroInitialized() { + return nativeHeapZeroInitialized; + } + + @DataClass.Generated.Member + public @NonNull ParsedProcessImpl setName(@NonNull String value) { + name = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + return this; + } + + /** + * @see ParsedProcess#getAppClassNamesByPackage() + */ + @DataClass.Generated.Member + public @NonNull ParsedProcessImpl setAppClassNamesByPackage(@NonNull ArrayMap value) { + appClassNamesByPackage = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, appClassNamesByPackage); + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProcessImpl setDeniedPermissions(@NonNull Set value) { + deniedPermissions = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, deniedPermissions); + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProcessImpl setGwpAsanMode(@ApplicationInfo.GwpAsanMode int value) { + gwpAsanMode = value; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProcessImpl setMemtagMode(@ApplicationInfo.MemtagMode int value) { + memtagMode = value; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.MemtagMode.class, null, memtagMode); + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProcessImpl setNativeHeapZeroInitialized(@ApplicationInfo.NativeHeapZeroInitialized int value) { + nativeHeapZeroInitialized = value; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.NativeHeapZeroInitialized.class, null, nativeHeapZeroInitialized); + return this; + } + + @DataClass.Generated.Member + static Parcelling> sParcellingForDeniedPermissions = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedStringSet.class); + static { + if (sParcellingForDeniedPermissions == null) { + sParcellingForDeniedPermissions = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedStringSet()); + } + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeString(name); + dest.writeMap(appClassNamesByPackage); + sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); + dest.writeInt(gwpAsanMode); + dest.writeInt(memtagMode); + dest.writeInt(nativeHeapZeroInitialized); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParsedProcessImpl(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String _name = in.readString(); + ArrayMap _appClassNamesByPackage = new ArrayMap(); + in.readMap(_appClassNamesByPackage, String.class.getClassLoader()); + Set _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); + int _gwpAsanMode = in.readInt(); + int _memtagMode = in.readInt(); + int _nativeHeapZeroInitialized = in.readInt(); + + this.name = _name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.appClassNamesByPackage = _appClassNamesByPackage; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, appClassNamesByPackage); + this.deniedPermissions = _deniedPermissions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, deniedPermissions); + this.gwpAsanMode = _gwpAsanMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); + this.memtagMode = _memtagMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.MemtagMode.class, null, memtagMode); + this.nativeHeapZeroInitialized = _nativeHeapZeroInitialized; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.NativeHeapZeroInitialized.class, null, nativeHeapZeroInitialized); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public ParsedProcessImpl[] newArray(int size) { + return new ParsedProcessImpl[size]; + } + + @Override + public ParsedProcessImpl createFromParcel(@NonNull Parcel in) { + return new ParsedProcessImpl(in); + } + }; + + @DataClass.Generated( + time = 1701445656489L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java", + inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(com.android.internal.pm.pkg.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java new file mode 100644 index 000000000000..3b2056e7892e --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.content.pm.ApplicationInfo; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.util.ArrayMap; +import android.util.ArraySet; + +import com.android.internal.R; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingUtils; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Set; + +/** @hide */ +public class ParsedProcessUtils { + + @NonNull + private static ParseResult> parseDenyPermission(Set perms, + Resources res, XmlResourceParser parser, ParseInput input) + throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission); + try { + String perm = sa.getNonConfigurationString( + R.styleable.AndroidManifestDenyPermission_name, 0); + if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { + perms = CollectionUtils.add(perms, perm); + } + } finally { + sa.recycle(); + } + XmlUtils.skipCurrentTag(parser); + return input.success(perms); + } + + @NonNull + private static ParseResult> parseAllowPermission(Set perms, Resources res, + XmlResourceParser parser, ParseInput input) + throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission); + try { + String perm = sa.getNonConfigurationString( + R.styleable.AndroidManifestAllowPermission_name, 0); + if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { + perms = CollectionUtils.remove(perms, perm); + } + } finally { + sa.recycle(); + } + XmlUtils.skipCurrentTag(parser); + return input.success(perms); + } + + @NonNull + private static ParseResult parseProcess(Set perms, String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + ParseInput input) throws IOException, XmlPullParserException { + ParsedProcessImpl proc = new ParsedProcessImpl(); + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess); + try { + if (perms != null) { + proc.setDeniedPermissions(new ArraySet<>(perms)); + } + + String processName = sa.getNonConfigurationString( + R.styleable.AndroidManifestProcess_process, 0); + ParseResult processNameResult = ComponentParseUtils.buildProcessName( + pkg.getPackageName(), pkg.getPackageName(), processName, flags, separateProcesses, + input); + if (processNameResult.isError()) { + return input.error(processNameResult); + } + + String packageName = pkg.getPackageName(); + String className = ParsingUtils.buildClassName(packageName, + sa.getNonConfigurationString(R.styleable.AndroidManifestProcess_name, 0)); + + proc.setName(processNameResult.getResult()); + proc.putAppClassNameForPackage(packageName, className); + proc.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1)); + proc.setMemtagMode(sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1)); + if (sa.hasValue(R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized)) { + final boolean v = sa.getBoolean( + R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized, false); + proc.setNativeHeapZeroInitialized( + v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED); + } + } finally { + sa.recycle(); + } + + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + ParseResult result; + + String tagName = parser.getName(); + switch (tagName) { + case "deny-permission": + ParseResult> denyResult = parseDenyPermission( + proc.getDeniedPermissions(), res, parser, input); + result = denyResult; + if (denyResult.isSuccess()) { + proc.setDeniedPermissions(denyResult.getResult()); + } + break; + case "allow-permission": + ParseResult> allowResult = parseAllowPermission( + proc.getDeniedPermissions(), res, parser, input); + result = allowResult; + if (allowResult.isSuccess()) { + proc.setDeniedPermissions(allowResult.getResult()); + } + break; + default: + result = ParsingUtils.unknownTag("", pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + return input.success(proc); + } + + @NonNull + public static ParseResult> parseProcesses( + String[] separateProcesses, ParsingPackage pkg, Resources res, + XmlResourceParser parser, int flags, ParseInput input) + throws IOException, XmlPullParserException { + Set deniedPerms = null; + ArrayMap processes = new ArrayMap<>(); + + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + ParseResult result; + + String tagName = parser.getName(); + switch (tagName) { + case "deny-permission": + ParseResult> denyResult = parseDenyPermission(deniedPerms, res, + parser, input); + result = denyResult; + if (denyResult.isSuccess()) { + deniedPerms = denyResult.getResult(); + } + break; + case "allow-permission": + ParseResult> allowResult = parseAllowPermission(deniedPerms, res, + parser, input); + result = allowResult; + if (allowResult.isSuccess()) { + deniedPerms = allowResult.getResult(); + } + break; + case "process": + ParseResult processResult = parseProcess(deniedPerms, + separateProcesses, pkg, res, parser, flags, input); + result = processResult; + if (processResult.isSuccess()) { + ParsedProcess process = processResult.getResult(); + if (processes.put(process.getName(), process) != null) { + result = input.error( + " specified existing name '" + process.getName() + "'"); + } + } + break; + default: + result = ParsingUtils.unknownTag("", pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + + } + + return input.success(processes); + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java new file mode 100644 index 000000000000..987fd4158418 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.pm.PathPermission; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.PatternMatcher; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @hide + **/ +@DataClass(genSetters = true, genGetters = true, genParcelable = false, genBuilder = false) +@DataClass.Suppress({"setUriPermissionPatterns", "setPathPermissions"}) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedProviderImpl extends ParsedMainComponentImpl implements ParsedProvider, + Parcelable { + + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String authority; + private boolean syncable; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String readPermission; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String writePermission; + private boolean grantUriPermissions; + private boolean forceUriPermissions; + private boolean multiProcess; + private int initOrder; + @NonNull + private List uriPermissionPatterns = Collections.emptyList(); + @NonNull + private List pathPermissions = Collections.emptyList(); + + public ParsedProviderImpl(ParsedProvider other) { + super(other); + + this.authority = other.getAuthority(); + this.syncable = other.isSyncable(); + this.readPermission = other.getReadPermission(); + this.writePermission = other.getWritePermission(); + this.grantUriPermissions = other.isGrantUriPermissions(); + this.forceUriPermissions = other.isForceUriPermissions(); + this.multiProcess = other.isMultiProcess(); + this.initOrder = other.getInitOrder(); + this.uriPermissionPatterns = new ArrayList<>(other.getUriPermissionPatterns()); + this.pathPermissions = new ArrayList<>(other.getPathPermissions()); + } + + public ParsedProviderImpl setReadPermission(String readPermission) { + // Empty string must be converted to null + this.readPermission = TextUtils.isEmpty(readPermission) + ? null : readPermission.intern(); + return this; + } + + public ParsedProviderImpl setWritePermission(String writePermission) { + // Empty string must be converted to null + this.writePermission = TextUtils.isEmpty(writePermission) + ? null : writePermission.intern(); + return this; + } + + @NonNull + public ParsedProviderImpl addUriPermissionPattern(@NonNull PatternMatcher value) { + uriPermissionPatterns = CollectionUtils.add(uriPermissionPatterns, value); + return this; + } + + @NonNull + public ParsedProviderImpl addPathPermission(@NonNull PathPermission value) { + pathPermissions = CollectionUtils.add(pathPermissions, value); + return this; + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Provider{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.authority); + dest.writeBoolean(this.syncable); + sForInternedString.parcel(this.readPermission, dest, flags); + sForInternedString.parcel(this.writePermission, dest, flags); + dest.writeBoolean(this.grantUriPermissions); + dest.writeBoolean(this.forceUriPermissions); + dest.writeBoolean(this.multiProcess); + dest.writeInt(this.initOrder); + dest.writeTypedList(this.uriPermissionPatterns, flags); + dest.writeTypedList(this.pathPermissions, flags); + } + + public ParsedProviderImpl() { + } + + protected ParsedProviderImpl(Parcel in) { + super(in); + this.authority = in.readString(); + this.syncable = in.readBoolean(); + this.readPermission = sForInternedString.unparcel(in); + this.writePermission = sForInternedString.unparcel(in); + this.grantUriPermissions = in.readBoolean(); + this.forceUriPermissions = in.readBoolean(); + this.multiProcess = in.readBoolean(); + this.initOrder = in.readInt(); + this.uriPermissionPatterns = in.createTypedArrayList(PatternMatcher.CREATOR); + this.pathPermissions = in.createTypedArrayList(PathPermission.CREATOR); + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public ParsedProviderImpl createFromParcel(Parcel source) { + return new ParsedProviderImpl(source); + } + + @Override + public ParsedProviderImpl[] newArray(int size) { + return new ParsedProviderImpl[size]; + } + }; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedProviderImpl( + @Nullable String authority, + boolean syncable, + @Nullable String readPermission, + @Nullable String writePermission, + boolean grantUriPermissions, + boolean forceUriPermissions, + boolean multiProcess, + int initOrder, + @NonNull List uriPermissionPatterns, + @NonNull List pathPermissions) { + this.authority = authority; + this.syncable = syncable; + this.readPermission = readPermission; + this.writePermission = writePermission; + this.grantUriPermissions = grantUriPermissions; + this.forceUriPermissions = forceUriPermissions; + this.multiProcess = multiProcess; + this.initOrder = initOrder; + this.uriPermissionPatterns = uriPermissionPatterns; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, uriPermissionPatterns); + this.pathPermissions = pathPermissions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, pathPermissions); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @Nullable String getAuthority() { + return authority; + } + + @DataClass.Generated.Member + public boolean isSyncable() { + return syncable; + } + + @DataClass.Generated.Member + public @Nullable String getReadPermission() { + return readPermission; + } + + @DataClass.Generated.Member + public @Nullable String getWritePermission() { + return writePermission; + } + + @DataClass.Generated.Member + public boolean isGrantUriPermissions() { + return grantUriPermissions; + } + + @DataClass.Generated.Member + public boolean isForceUriPermissions() { + return forceUriPermissions; + } + + @DataClass.Generated.Member + public boolean isMultiProcess() { + return multiProcess; + } + + @DataClass.Generated.Member + public int getInitOrder() { + return initOrder; + } + + @DataClass.Generated.Member + public @NonNull List getUriPermissionPatterns() { + return uriPermissionPatterns; + } + + @DataClass.Generated.Member + public @NonNull List getPathPermissions() { + return pathPermissions; + } + + @DataClass.Generated.Member + public @NonNull ParsedProviderImpl setAuthority(@NonNull String value) { + authority = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProviderImpl setSyncable( boolean value) { + syncable = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProviderImpl setGrantUriPermissions( boolean value) { + grantUriPermissions = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProviderImpl setForceUriPermissions( boolean value) { + forceUriPermissions = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProviderImpl setMultiProcess( boolean value) { + multiProcess = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedProviderImpl setInitOrder( int value) { + initOrder = value; + return this; + } + + @DataClass.Generated( + time = 1642560323360L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java", + inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java new file mode 100644 index 000000000000..5d82d0469d56 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag; +import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.IntentFilter; +import android.content.pm.PathPermission; +import android.content.pm.ProviderInfo; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.os.PatternMatcher; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Objects; + +/** @hide */ +public class ParsedProviderUtils { + + private static final String TAG = ParsingUtils.TAG; + + @NonNull + public static ParseResult parseProvider(String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + boolean useRoundIcon, @Nullable String defaultSplitName, @NonNull ParseInput input) + throws IOException, XmlPullParserException { + String authority; + boolean visibleToEphemeral; + + final int targetSdkVersion = pkg.getTargetSdkVersion(); + final String packageName = pkg.getPackageName(); + final ParsedProviderImpl provider = new ParsedProviderImpl(); + final String tag = parser.getName(); + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProvider); + try { + ParseResult result = + ParsedMainComponentUtils.parseMainComponent(provider, tag, separateProcesses, + pkg, sa, flags, useRoundIcon, defaultSplitName, input, + R.styleable.AndroidManifestProvider_banner, + R.styleable.AndroidManifestProvider_description, + R.styleable.AndroidManifestProvider_directBootAware, + R.styleable.AndroidManifestProvider_enabled, + R.styleable.AndroidManifestProvider_icon, + R.styleable.AndroidManifestProvider_label, + R.styleable.AndroidManifestProvider_logo, + R.styleable.AndroidManifestProvider_name, + R.styleable.AndroidManifestProvider_process, + R.styleable.AndroidManifestProvider_roundIcon, + R.styleable.AndroidManifestProvider_splitName, + R.styleable.AndroidManifestProvider_attributionTags); + if (result.isError()) { + return input.error(result); + } + + authority = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_authorities, 0); + + // For compatibility, applications targeting API level 16 or lower + // should have their content providers exported by default, unless they + // specify otherwise. + provider.setSyncable(sa.getBoolean( + R.styleable.AndroidManifestProvider_syncable, false)) + .setExported(sa.getBoolean(R.styleable.AndroidManifestProvider_exported, + targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1)); + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_permission, 0); + String readPermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_readPermission, 0); + if (readPermission == null) { + readPermission = permission; + } + if (readPermission == null) { + provider.setReadPermission(pkg.getPermission()); + } else { + provider.setReadPermission(readPermission); + } + String writePermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_writePermission, 0); + if (writePermission == null) { + writePermission = permission; + } + if (writePermission == null) { + provider.setWritePermission(pkg.getPermission()); + } else { + provider.setWritePermission(writePermission); + } + + provider.setGrantUriPermissions( + sa.getBoolean(R.styleable.AndroidManifestProvider_grantUriPermissions, false)) + .setForceUriPermissions( + sa.getBoolean(R.styleable.AndroidManifestProvider_forceUriPermissions, + false)) + .setMultiProcess( + sa.getBoolean(R.styleable.AndroidManifestProvider_multiprocess, false)) + .setInitOrder(sa.getInt(R.styleable.AndroidManifestProvider_initOrder, 0)) + .setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SINGLE_USER, + R.styleable.AndroidManifestProvider_singleUser, sa)); + + visibleToEphemeral = sa.getBoolean( + R.styleable.AndroidManifestProvider_visibleToInstantApps, false); + if (visibleToEphemeral) { + provider.setFlags(provider.getFlags() | ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP); + pkg.setVisibleToInstantApps(true); + } + } finally { + sa.recycle(); + } + + if (pkg.isSaveStateDisallowed()) { + // A heavy-weight application can not have providers in its main process + if (Objects.equals(provider.getProcessName(), packageName)) { + return input.error("Heavy-weight applications can not have providers" + + " in main process"); + } + } + + if (authority == null) { + return input.error(" does not include authorities attribute"); + } + if (authority.length() <= 0) { + return input.error(" has empty authorities attribute"); + } + provider.setAuthority(authority); + + return parseProviderTags(pkg, tag, res, parser, visibleToEphemeral, provider, input); + } + + @NonNull + private static ParseResult parseProviderTags(ParsingPackage pkg, String tag, + Resources res, XmlResourceParser parser, boolean visibleToEphemeral, + ParsedProviderImpl provider, ParseInput input) + throws XmlPullParserException, IOException { + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + final ParseResult result; + switch (name) { + case "intent-filter": + ParseResult intentResult = ParsedMainComponentUtils + .parseIntentFilter(provider, pkg, res, parser, visibleToEphemeral, + true /*allowGlobs*/, false /*allowAutoVerify*/, + false /*allowImplicitEphemeralVisibility*/, + false /*failOnNoActions*/, input); + result = intentResult; + if (intentResult.isSuccess()) { + ParsedIntentInfoImpl intent = intentResult.getResult(); + IntentFilter intentFilter = intent.getIntentFilter(); + provider.setOrder(Math.max(intentFilter.getOrder(), provider.getOrder())); + provider.addIntent(intent); + } + break; + case "meta-data": + result = ParsedComponentUtils.addMetaData(provider, pkg, res, parser, input); + break; + case "property": + result = ParsedComponentUtils.addProperty(provider, pkg, res, parser, input); + break; + case "grant-uri-permission": { + result = parseGrantUriPermission(provider, pkg, res, parser, input); + break; + } + case "path-permission": { + result = parsePathPermission(provider, pkg, res, parser, input); + break; + } + default: + result = ParsingUtils.unknownTag(tag, pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + return input.success(provider); + } + + @NonNull + private static ParseResult parseGrantUriPermission(ParsedProviderImpl provider, + ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) { + TypedArray sa = resources.obtainAttributes(parser, + R.styleable.AndroidManifestGrantUriPermission); + try { + String name = parser.getName(); + // Pattern has priority over pre/suffix over literal path + PatternMatcher pa = null; + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathAdvancedPattern, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_ADVANCED_GLOB); + } else { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } else { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); + } else { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathSuffix, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_SUFFIX); + } else { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_path, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); + } + } + } + } + } + + if (pa != null) { + provider.addUriPermissionPattern(pa); + provider.setGrantUriPermissions(true); + } else { + if (RIGID_PARSER) { + return input.error("No path, pathPrefix, or pathPattern for "); + } + + Slog.w(TAG, "Unknown element under : " + name + " at " + + pkg.getBaseApkPath() + " " + parser.getPositionDescription()); + } + + return input.success(provider); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parsePathPermission(ParsedProviderImpl provider, + ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) { + TypedArray sa = resources.obtainAttributes(parser, + R.styleable.AndroidManifestPathPermission); + try { + String name = parser.getName(); + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_permission, 0); + String readPermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_readPermission, 0); + if (readPermission == null) { + readPermission = permission; + } + String writePermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_writePermission, 0); + if (writePermission == null) { + writePermission = permission; + } + + boolean havePerm = false; + if (readPermission != null) { + readPermission = readPermission.intern(); + havePerm = true; + } + if (writePermission != null) { + writePermission = writePermission.intern(); + havePerm = true; + } + + if (!havePerm) { + if (RIGID_PARSER) { + return input.error( + "No readPermission or writePermission for "); + } + Slog.w(TAG, "No readPermission or writePermission for : " + + name + " at " + pkg.getBaseApkPath() + " " + + parser.getPositionDescription()); + return input.success(provider); + } + + // Advanced has priority over simply over prefix over literal + PathPermission pa = null; + String path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, + writePermission); + } else { + path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathPattern, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_SIMPLE_GLOB, + readPermission, writePermission); + } else { + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathPrefix, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_PREFIX, readPermission, + writePermission); + } else { + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathSuffix, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_SUFFIX, + readPermission, writePermission); + } else { + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_path, 0); + if (path != null) { + pa = new PathPermission(path, PatternMatcher.PATTERN_LITERAL, + readPermission, writePermission); + } + } + } + } + } + + if (pa != null) { + provider.addPathPermission(pa); + } else { + if (RIGID_PARSER) { + return input.error( + "No path, pathPrefix, or pathPattern for "); + } + + Slog.w(TAG, "No path, pathPrefix, or pathPattern for : " + + name + " at " + pkg.getBaseApkPath() + + " " + + parser.getPositionDescription()); + } + + return input.success(provider); + } finally { + sa.recycle(); + } + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java new file mode 100644 index 000000000000..f4662d803296 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; + +/** @hide **/ +@DataClass(genSetters = true, genGetters = true, genParcelable = false, genBuilder = false) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedServiceImpl extends ParsedMainComponentImpl implements ParsedService, + Parcelable { + + private int foregroundServiceType; + @Nullable + @DataClass.ParcelWith(ForInternedString.class) + private String permission; + + public ParsedServiceImpl(ParsedServiceImpl other) { + super(other); + this.foregroundServiceType = other.foregroundServiceType; + this.permission = other.permission; + } + + public ParsedMainComponent setPermission(String permission) { + // Empty string must be converted to null + this.permission = TextUtils.isEmpty(permission) ? null : permission.intern(); + return this; + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Service{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + ComponentName.appendShortString(sb, getPackageName(), getName()); + sb.append('}'); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.foregroundServiceType); + sForInternedString.parcel(this.permission, dest, flags); + } + + public ParsedServiceImpl() { + } + + protected ParsedServiceImpl(Parcel in) { + super(in); + this.foregroundServiceType = in.readInt(); + this.permission = sForInternedString.unparcel(in); + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public ParsedServiceImpl createFromParcel(Parcel source) { + return new ParsedServiceImpl(source); + } + + @Override + public ParsedServiceImpl[] newArray(int size) { + return new ParsedServiceImpl[size]; + } + }; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedServiceImpl( + int foregroundServiceType, + @Nullable String permission) { + this.foregroundServiceType = foregroundServiceType; + this.permission = permission; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public int getForegroundServiceType() { + return foregroundServiceType; + } + + @DataClass.Generated.Member + public @Nullable String getPermission() { + return permission; + } + + @DataClass.Generated.Member + public @NonNull ParsedServiceImpl setForegroundServiceType( int value) { + foregroundServiceType = value; + return this; + } + + @DataClass.Generated( + time = 1701445638370L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java", + inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java new file mode 100644 index 000000000000..a1dd19a3bc90 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseInput.DeferredError; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; + +import com.android.internal.R; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Objects; + +/** @hide */ +public class ParsedServiceUtils { + + @NonNull + public static ParseResult parseService(String[] separateProcesses, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + boolean useRoundIcon, @Nullable String defaultSplitName, @NonNull ParseInput input) + throws XmlPullParserException, IOException { + boolean visibleToEphemeral; + boolean setExported; + + final String packageName = pkg.getPackageName(); + final ParsedServiceImpl service = new ParsedServiceImpl(); + String tag = parser.getName(); + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestService); + try { + ParseResult result = ParsedMainComponentUtils.parseMainComponent( + service, tag, separateProcesses, pkg, sa, flags, useRoundIcon, defaultSplitName, + input, + R.styleable.AndroidManifestService_banner, + R.styleable.AndroidManifestService_description, + R.styleable.AndroidManifestService_directBootAware, + R.styleable.AndroidManifestService_enabled, + R.styleable.AndroidManifestService_icon, + R.styleable.AndroidManifestService_label, + R.styleable.AndroidManifestService_logo, + R.styleable.AndroidManifestService_name, + R.styleable.AndroidManifestService_process, + R.styleable.AndroidManifestService_roundIcon, + R.styleable.AndroidManifestService_splitName, + R.styleable.AndroidManifestService_attributionTags + ); + + if (result.isError()) { + return input.error(result); + } + + setExported = sa.hasValue(R.styleable.AndroidManifestService_exported); + if (setExported) { + service.setExported(sa.getBoolean(R.styleable.AndroidManifestService_exported, + false)); + } + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestService_permission, 0); + service.setPermission(permission != null ? permission : pkg.getPermission()); + + service.setForegroundServiceType(sa.getInt( + R.styleable.AndroidManifestService_foregroundServiceType, + ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE)) + .setFlags(service.getFlags() | (flag(ServiceInfo.FLAG_STOP_WITH_TASK, + R.styleable.AndroidManifestService_stopWithTask, sa) + | flag(ServiceInfo.FLAG_ISOLATED_PROCESS, + R.styleable.AndroidManifestService_isolatedProcess, sa) + | flag(ServiceInfo.FLAG_EXTERNAL_SERVICE, + R.styleable.AndroidManifestService_externalService, sa) + | flag(ServiceInfo.FLAG_USE_APP_ZYGOTE, + R.styleable.AndroidManifestService_useAppZygote, sa) + | flag(ServiceInfo.FLAG_ALLOW_SHARED_ISOLATED_PROCESS, + R.styleable.AndroidManifestService_allowSharedIsolatedProcess, sa) + | flag(ServiceInfo.FLAG_SINGLE_USER, + R.styleable.AndroidManifestService_singleUser, sa))); + + visibleToEphemeral = sa.getBoolean( + R.styleable.AndroidManifestService_visibleToInstantApps, false); + if (visibleToEphemeral) { + service.setFlags(service.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP); + pkg.setVisibleToInstantApps(true); + } + } finally { + sa.recycle(); + } + + if (pkg.isSaveStateDisallowed()) { + // A heavy-weight application can not have services in its main process + // We can do direct compare because we intern all strings. + if (Objects.equals(service.getProcessName(), packageName)) { + return input.error("Heavy-weight applications can not have services " + + "in main process"); + } + } + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult parseResult; + switch (parser.getName()) { + case "intent-filter": + ParseResult intentResult = ParsedMainComponentUtils + .parseIntentFilter(service, pkg, res, parser, visibleToEphemeral, + true /*allowGlobs*/, false /*allowAutoVerify*/, + false /*allowImplicitEphemeralVisibility*/, + false /*failOnNoActions*/, input); + parseResult = intentResult; + if (intentResult.isSuccess()) { + ParsedIntentInfoImpl intent = intentResult.getResult(); + IntentFilter intentFilter = intent.getIntentFilter(); + service.setOrder(Math.max(intentFilter.getOrder(), service.getOrder())); + service.addIntent(intent); + } + break; + case "meta-data": + parseResult = ParsedComponentUtils.addMetaData(service, pkg, res, parser, input); + break; + case "property": + parseResult = + ParsedComponentUtils.addProperty(service, pkg, res, parser, input); + break; + default: + parseResult = ParsingUtils.unknownTag(tag, pkg, parser, input); + break; + } + + if (parseResult.isError()) { + return input.error(parseResult); + } + } + + if (!setExported) { + boolean hasIntentFilters = service.getIntents().size() > 0; + if (hasIntentFilters) { + final ParseResult exportedCheckResult = input.deferError( + service.getName() + ": Targeting S+ (version " + Build.VERSION_CODES.S + + " and above) requires that an explicit value for android:exported be" + + " defined when intent filters are present", + DeferredError.MISSING_EXPORTED_FLAG); + if (exportedCheckResult.isError()) { + return input.error(exportedCheckResult); + } + } + service.setExported(hasIntentFilters); + } + + return input.success(service); + } +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java new file mode 100644 index 000000000000..fd131dfd00c7 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2022 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.pm.pkg.component; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; + +/** + * A {@link android.R.styleable#AndroidManifestUsesPermission + * <uses-permission>} tag parsed from the manifest. + * + * @hide + */ +@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = true, + genAidl = false) +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class ParsedUsesPermissionImpl implements ParsedUsesPermission, Parcelable { + + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) + @NonNull + private String name; + + @ParsedUsesPermission.UsesPermissionFlags + private int usesPermissionFlags; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public ParsedUsesPermissionImpl( + @NonNull String name, + @ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags) { + this.name = name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.usesPermissionFlags = usesPermissionFlags; + com.android.internal.util.AnnotationValidations.validate( + ParsedUsesPermission.UsesPermissionFlags.class, null, usesPermissionFlags); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull String getName() { + return name; + } + + @DataClass.Generated.Member + public @ParsedUsesPermission.UsesPermissionFlags int getUsesPermissionFlags() { + return usesPermissionFlags; + } + + @DataClass.Generated.Member + public @NonNull ParsedUsesPermissionImpl setName(@NonNull String value) { + name = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + return this; + } + + @DataClass.Generated.Member + public @NonNull ParsedUsesPermissionImpl setUsesPermissionFlags(@ParsedUsesPermission.UsesPermissionFlags int value) { + usesPermissionFlags = value; + com.android.internal.util.AnnotationValidations.validate( + ParsedUsesPermission.UsesPermissionFlags.class, null, usesPermissionFlags); + return this; + } + + @DataClass.Generated.Member + static Parcelling sParcellingForName = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedString.class); + static { + if (sParcellingForName == null) { + sParcellingForName = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedString()); + } + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + sParcellingForName.parcel(name, dest, flags); + dest.writeInt(usesPermissionFlags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParsedUsesPermissionImpl(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String _name = sParcellingForName.unparcel(in); + int _usesPermissionFlags = in.readInt(); + + this.name = _name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.usesPermissionFlags = _usesPermissionFlags; + com.android.internal.util.AnnotationValidations.validate( + ParsedUsesPermission.UsesPermissionFlags.class, null, usesPermissionFlags); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public ParsedUsesPermissionImpl[] newArray(int size) { + return new ParsedUsesPermissionImpl[size]; + } + + @Override + public ParsedUsesPermissionImpl createFromParcel(@NonNull Parcel in) { + return new ParsedUsesPermissionImpl(in); + } + }; + + @DataClass.Generated( + time = 1701445626268L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java", + inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.pm.pkg.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java new file mode 100644 index 000000000000..dbe4fba5dfdb --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -0,0 +1,3459 @@ +/* + * 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.internal.pm.pkg.parsing; + +import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.Flags.disallowSdkLibsToBeApps; +import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; +import static android.os.Build.VERSION_CODES.DONUT; +import static android.os.Build.VERSION_CODES.O; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + +import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts; + +import android.annotation.AnyRes; +import android.annotation.CheckResult; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StyleableRes; +import android.app.ActivityThread; +import android.app.ResourcesManager; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.Property; +import android.content.pm.Signature; +import android.content.pm.SigningDetails; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.FrameworkParsingPackageUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseInput.DeferredError; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.ApkAssets; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.os.Trace; +import android.os.UserHandle; +import android.os.ext.SdkExtensions; +import android.permission.PermissionManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Pair; +import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.util.TypedValue; +import android.util.apk.ApkSignatureVerifier; + +import com.android.internal.R; +import com.android.internal.os.ClassLoaderFactory; +import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.permission.CompatibilityPermissionInfo; +import com.android.internal.pm.pkg.component.ComponentMutateUtils; +import com.android.internal.pm.pkg.component.ComponentParseUtils; +import com.android.internal.pm.pkg.component.InstallConstraintsTagParser; +import com.android.internal.pm.pkg.component.ParsedActivity; +import com.android.internal.pm.pkg.component.ParsedActivityImpl; +import com.android.internal.pm.pkg.component.ParsedActivityUtils; +import com.android.internal.pm.pkg.component.ParsedApexSystemService; +import com.android.internal.pm.pkg.component.ParsedApexSystemServiceUtils; +import com.android.internal.pm.pkg.component.ParsedAttribution; +import com.android.internal.pm.pkg.component.ParsedAttributionUtils; +import com.android.internal.pm.pkg.component.ParsedComponent; +import com.android.internal.pm.pkg.component.ParsedInstrumentation; +import com.android.internal.pm.pkg.component.ParsedInstrumentationUtils; +import com.android.internal.pm.pkg.component.ParsedIntentInfo; +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl; +import com.android.internal.pm.pkg.component.ParsedIntentInfoUtils; +import com.android.internal.pm.pkg.component.ParsedMainComponent; +import com.android.internal.pm.pkg.component.ParsedPermission; +import com.android.internal.pm.pkg.component.ParsedPermissionGroup; +import com.android.internal.pm.pkg.component.ParsedPermissionUtils; +import com.android.internal.pm.pkg.component.ParsedProcess; +import com.android.internal.pm.pkg.component.ParsedProcessUtils; +import com.android.internal.pm.pkg.component.ParsedProvider; +import com.android.internal.pm.pkg.component.ParsedProviderUtils; +import com.android.internal.pm.pkg.component.ParsedService; +import com.android.internal.pm.pkg.component.ParsedServiceUtils; +import com.android.internal.pm.pkg.component.ParsedUsesPermission; +import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl; +import com.android.internal.pm.split.DefaultSplitAssetLoader; +import com.android.internal.pm.split.SplitAssetDependencyLoader; +import com.android.internal.pm.split.SplitAssetLoader; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.XmlUtils; + +import libcore.io.IoUtils; +import libcore.util.EmptyArray; +import libcore.util.HexEncoding; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * TODO(b/135203078): Differentiate between parse_ methods and some add_ method for whether it + * mutates the passed-in component or not. Or consolidate so all parse_ methods mutate. + * + * @hide + */ +public class ParsingPackageUtils { + + private static final String TAG = ParsingUtils.TAG; + + public static final boolean DEBUG_JAR = false; + public static final boolean DEBUG_BACKUP = false; + public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; + public static final float ASPECT_RATIO_NOT_SET = -1f; + + /** + * File name in an APK for the Android manifest. + */ + public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; + + /** + * Path prefix for apps on expanded storage + */ + public static final String MNT_EXPAND = "/mnt/expand/"; + + public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; + public static final String TAG_APPLICATION = "application"; + public static final String TAG_ATTRIBUTION = "attribution"; + public static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; + public static final String TAG_EAT_COMMENT = "eat-comment"; + public static final String TAG_FEATURE_GROUP = "feature-group"; + public static final String TAG_INSTALL_CONSTRAINTS = "install-constraints"; + public static final String TAG_INSTRUMENTATION = "instrumentation"; + public static final String TAG_KEY_SETS = "key-sets"; + public static final String TAG_MANIFEST = "manifest"; + public static final String TAG_ORIGINAL_PACKAGE = "original-package"; + public static final String TAG_OVERLAY = "overlay"; + public static final String TAG_PACKAGE = "package"; + public static final String TAG_PACKAGE_VERIFIER = "package-verifier"; + public static final String TAG_PERMISSION = "permission"; + public static final String TAG_PERMISSION_GROUP = "permission-group"; + public static final String TAG_PERMISSION_TREE = "permission-tree"; + public static final String TAG_PROFILEABLE = "profileable"; + public static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; + public static final String TAG_QUERIES = "queries"; + public static final String TAG_RECEIVER = "receiver"; + public static final String TAG_RESTRICT_UPDATE = "restrict-update"; + public static final String TAG_SUPPORTS_INPUT = "supports-input"; + public static final String TAG_SUPPORT_SCREENS = "supports-screens"; + public static final String TAG_USES_CONFIGURATION = "uses-configuration"; + public static final String TAG_USES_FEATURE = "uses-feature"; + public static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; + public static final String TAG_USES_PERMISSION = "uses-permission"; + public static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; + public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; + public static final String TAG_USES_SDK = "uses-sdk"; + public static final String TAG_USES_SPLIT = "uses-split"; + + public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; + public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes"; + public static final String METADATA_CAN_DISPLAY_ON_REMOTE_DEVICES = + "android.can_display_on_remote_devices"; + public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY = + "android.activity_window_layout_affinity"; + public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode"; + + public static final int SDK_VERSION = Build.VERSION.SDK_INT; + public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; + + public static boolean sCompatibilityModeEnabled = true; + public static boolean sUseRoundIcon = false; + + public static final int PARSE_DEFAULT_INSTALL_LOCATION = + PackageInfo.INSTALL_LOCATION_UNSPECIFIED; + public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; + + /** + * If set to true, we will only allow package files that exactly match the DTD. Otherwise, we + * try to get as much from the package as we can without failing. This should normally be set to + * false, to support extensions to the DTD in future versions. + */ + public static final boolean RIGID_PARSER = false; + + public static final int PARSE_MUST_BE_APK = 1 << 0; + public static final int PARSE_IGNORE_PROCESSES = 1 << 1; + public static final int PARSE_EXTERNAL_STORAGE = 1 << 3; + public static final int PARSE_IS_SYSTEM_DIR = 1 << 4; + public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5; + public static final int PARSE_ENFORCE_CODE = 1 << 6; + /** + * This flag is applied in the ApkLiteParser. Used by OverlayConfigParser to ignore the checks + * of required system property within the overlay tag. + */ + public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7; + public static final int PARSE_APK_IN_APEX = 1 << 9; + + public static final int PARSE_CHATTY = 1 << 31; + + /** The total maximum number of activities, services, providers and activity-aliases */ + private static final int MAX_NUM_COMPONENTS = 30000; + private static final String MAX_NUM_COMPONENTS_ERR_MSG = + "Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS; + + /** The maximum permission name length. */ + private static final int MAX_PERMISSION_NAME_LENGTH = 512; + + @IntDef(flag = true, prefix = { "PARSE_" }, value = { + PARSE_CHATTY, + PARSE_COLLECT_CERTIFICATES, + PARSE_ENFORCE_CODE, + PARSE_EXTERNAL_STORAGE, + PARSE_IGNORE_PROCESSES, + PARSE_IS_SYSTEM_DIR, + PARSE_MUST_BE_APK, + PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ParseFlags {} + + /** + * For cases outside of PackageManagerService when an APK needs to be parsed as a one-off + * request, without caching the input object and without querying the internal system state for + * feature support. + */ + @NonNull + public static ParseResult parseDefault(ParseInput input, File file, + @ParseFlags int parseFlags, + @NonNull List splitPermissions, + boolean collectCertificates, Callback callback) { + + ParsingPackageUtils parser = new ParsingPackageUtils(null /*separateProcesses*/, + null /*displayMetrics*/, splitPermissions, callback); + var parseResult = parser.parsePackage(input, file, parseFlags); + if (parseResult.isError()) { + return input.error(parseResult); + } + + var pkg = parseResult.getResult().hideAsParsed(); + + if (collectCertificates) { + final ParseResult ret = + ParsingPackageUtils.getSigningDetails(input, pkg, false /*skipVerify*/); + if (ret.isError()) { + return input.error(ret); + } + pkg.setSigningDetails(ret.getResult()); + } + + return input.success(pkg); + } + + private final String[] mSeparateProcesses; + private final DisplayMetrics mDisplayMetrics; + @NonNull + private final List mSplitPermissionInfos; + private final Callback mCallback; + + public ParsingPackageUtils(String[] separateProcesses, DisplayMetrics displayMetrics, + @NonNull List splitPermissions, + @NonNull Callback callback) { + mSeparateProcesses = separateProcesses; + mDisplayMetrics = displayMetrics; + mSplitPermissionInfos = splitPermissions; + mCallback = callback; + } + + /** + * Parse the package at the given location. Automatically detects if the package is a monolithic + * style (single APK file) or cluster style (directory of APKs). + *

+ * This performs validity checking on cluster style packages, such as requiring identical + * package name and version codes, a single base APK, and unique split names. + *

+ * Note that this does not perform signature verification; that must be done separately + * in {@link #getSigningDetails(ParseInput, ParsedPackage, boolean)}. + *

+ * If {@code useCaches} is true, the package parser might return a cached result from a previous + * parse of the same {@code packageFile} with the same {@code flags}. Note that this method does + * not check whether {@code packageFile} has changed since the last parse, it's up to callers to + * do so. + */ + public ParseResult parsePackage(ParseInput input, File packageFile, int flags) { + if (packageFile.isDirectory()) { + return parseClusterPackage(input, packageFile, flags); + } else { + return parseMonolithicPackage(input, packageFile, flags); + } + } + + /** + * Parse all APKs contained in the given directory, treating them as a + * single package. This also performs validity checking, such as requiring + * identical package name and version codes, a single base APK, and unique + * split names. + *

+ * Note that this does not perform signature verification; that must be done separately + * in {@link #getSigningDetails(ParseInput, ParsedPackage, boolean)}. + */ + private ParseResult parseClusterPackage(ParseInput input, File packageDir, + int flags) { + int liteParseFlags = 0; + if ((flags & PARSE_APK_IN_APEX) != 0) { + liteParseFlags |= PARSE_APK_IN_APEX; + } + final ParseResult liteResult = + ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags); + if (liteResult.isError()) { + return input.error(liteResult); + } + + final PackageLite lite = liteResult.getResult(); + // Build the split dependency tree. + SparseArray splitDependencies = null; + final SplitAssetLoader assetLoader; + if (lite.isIsolatedSplits() && !ArrayUtils.isEmpty(lite.getSplitNames())) { + try { + splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); + assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); + } catch (SplitAssetDependencyLoader.IllegalDependencyException e) { + return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage()); + } + } else { + assetLoader = new DefaultSplitAssetLoader(lite, flags); + } + + try { + final File baseApk = new File(lite.getBaseApkPath()); + boolean shouldSkipComponents = lite.isIsSdkLibrary() && disallowSdkLibsToBeApps(); + final ParseResult result = parseBaseApk(input, baseApk, + lite.getPath(), assetLoader, flags, shouldSkipComponents); + if (result.isError()) { + return input.error(result); + } + + ParsingPackage pkg = result.getResult(); + if (!ArrayUtils.isEmpty(lite.getSplitNames())) { + pkg.asSplit( + lite.getSplitNames(), + lite.getSplitApkPaths(), + lite.getSplitRevisionCodes(), + splitDependencies + ); + final int num = lite.getSplitNames().length; + + for (int i = 0; i < num; i++) { + final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); + final ParseResult split = + parseSplitApk(input, pkg, i, splitAssets, flags); + if (split.isError()) { + return input.error(split); + } + } + } + + pkg.set32BitAbiPreferred(lite.isUse32bitAbi()); + return input.success(pkg); + } catch (IllegalArgumentException e) { + return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK + : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + /** + * Parse the given APK file, treating it as as a single monolithic package. + *

+ * Note that this does not perform signature verification; that must be done separately + * in {@link #getSigningDetails(ParseInput, ParsedPackage, boolean)}. + */ + private ParseResult parseMonolithicPackage(ParseInput input, File apkFile, + int flags) { + final ParseResult liteResult = + ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags); + if (liteResult.isError()) { + return input.error(liteResult); + } + + final PackageLite lite = liteResult.getResult(); + final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); + try { + boolean shouldSkipComponents = lite.isIsSdkLibrary() && disallowSdkLibsToBeApps(); + final ParseResult result = parseBaseApk(input, + apkFile, + apkFile.getCanonicalPath(), + assetLoader, flags, shouldSkipComponents); + if (result.isError()) { + return input.error(result); + } + + return input.success(result.getResult() + .set32BitAbiPreferred(lite.isUse32bitAbi())); + } catch (IOException e) { + return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to get path: " + apkFile, e); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + /** + * Creates ParsingPackage using only PackageLite. + * Missing fields will contain reasonable defaults. + * Used for packageless (aka archived) package installation. + */ + public ParseResult parsePackageFromPackageLite(ParseInput input, + PackageLite lite, int flags) { + final String volumeUuid = getVolumeUuid(lite.getPath()); + final String pkgName = lite.getPackageName(); + + final TypedArray manifestArray = null; + final ParsingPackage pkg = mCallback.startParsingPackage(pkgName, + lite.getBaseApkPath(), lite.getPath(), manifestArray, lite.isCoreApp()); + + final int targetSdk = lite.getTargetSdk(); + final String versionName = null; + final int compileSdkVersion = 0; + final String compileSdkVersionCodeName = null; + final boolean isolatedSplitLoading = false; + + // Normally set from manifestArray. + pkg.setVersionCode(lite.getVersionCode()); + pkg.setVersionCodeMajor(lite.getVersionCodeMajor()); + pkg.setBaseRevisionCode(lite.getBaseRevisionCode()); + pkg.setVersionName(versionName); + pkg.setCompileSdkVersion(compileSdkVersion); + pkg.setCompileSdkVersionCodeName(compileSdkVersionCodeName); + pkg.setIsolatedSplitLoading(isolatedSplitLoading); + pkg.setTargetSdkVersion(targetSdk); + + // parseBaseApkTags + pkg.setInstallLocation(lite.getInstallLocation()) + .setTargetSandboxVersion(PARSE_DEFAULT_TARGET_SANDBOX) + /* Set the global "on SD card" flag */ + .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0); + + var archivedPackage = lite.getArchivedPackage(); + if (archivedPackage == null) { + return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "archivePackage is missing"); + } + + // parseBaseAppBasicFlags + pkg + // Default true + .setBackupAllowed(true) + .setClearUserDataAllowed(true) + .setClearUserDataOnFailedRestoreAllowed(true) + .setAllowNativeHeapPointerTagging(true) + .setEnabled(true) + .setExtractNativeLibrariesRequested(true) + // targetSdkVersion gated + .setAllowAudioPlaybackCapture(targetSdk >= Build.VERSION_CODES.Q) + .setHardwareAccelerated(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) + .setRequestLegacyExternalStorage( + XmlUtils.convertValueToBoolean(archivedPackage.requestLegacyExternalStorage, + targetSdk < Build.VERSION_CODES.Q)) + .setCleartextTrafficAllowed(targetSdk < Build.VERSION_CODES.P) + // Default false + .setDefaultToDeviceProtectedStorage(XmlUtils.convertValueToBoolean( + archivedPackage.defaultToDeviceProtectedStorage, false)) + .setUserDataFragile( + XmlUtils.convertValueToBoolean(archivedPackage.userDataFragile, false)) + // Ints + .setCategory(ApplicationInfo.CATEGORY_UNDEFINED) + // Floats Default 0f + .setMaxAspectRatio(0f) + .setMinAspectRatio(0f); + + // No APK - no code. + pkg.setDeclaredHavingCode(false); + + final String taskAffinity = null; + ParseResult taskAffinityResult = ComponentParseUtils.buildTaskAffinityName( + pkgName, pkgName, taskAffinity, input); + if (taskAffinityResult.isError()) { + return input.error(taskAffinityResult); + } + pkg.setTaskAffinity(taskAffinityResult.getResult()); + + final CharSequence pname = null; + ParseResult processNameResult = ComponentParseUtils.buildProcessName( + pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input); + if (processNameResult.isError()) { + return input.error(processNameResult); + } + pkg.setProcessName(processNameResult.getResult()); + + pkg.setGwpAsanMode(-1); + pkg.setMemtagMode(-1); + + afterParseBaseApplication(pkg); + + final ParseResult result = validateBaseApkTags(input, pkg); + if (result.isError()) { + return result; + } + + pkg.setVolumeUuid(volumeUuid); + + if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { + pkg.setSigningDetails(lite.getSigningDetails()); + } else { + pkg.setSigningDetails(SigningDetails.UNKNOWN); + } + + return input.success(pkg + .set32BitAbiPreferred(lite.isUse32bitAbi())); + } + + private static String getVolumeUuid(final String apkPath) { + String volumeUuid = null; + if (apkPath.startsWith(MNT_EXPAND)) { + final int end = apkPath.indexOf('/', MNT_EXPAND.length()); + volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); + } + return volumeUuid; + } + + private ParseResult parseBaseApk(ParseInput input, File apkFile, + String codePath, SplitAssetLoader assetLoader, int flags, + boolean shouldSkipComponents) { + final String apkPath = apkFile.getAbsolutePath(); + + final String volumeUuid = getVolumeUuid(apkPath); + + if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); + + final AssetManager assets; + try { + assets = assetLoader.getBaseAssetManager(); + } catch (IllegalArgumentException e) { + return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK + : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e); + } + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + + try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, + ANDROID_MANIFEST_FILENAME)) { + final Resources res = new Resources(assets, mDisplayMetrics, null); + + ParseResult result = parseBaseApk(input, apkPath, codePath, res, + parser, flags, shouldSkipComponents); + if (result.isError()) { + return input.error(result.getErrorCode(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + result.getErrorMessage()); + } + + final ParsingPackage pkg = result.getResult(); + if (assets.containsAllocatedTable()) { + final ParseResult deferResult = input.deferError( + "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires" + + " the resources.arsc of installed APKs to be stored uncompressed" + + " and aligned on a 4-byte boundary", + DeferredError.RESOURCES_ARSC_COMPRESSED); + if (deferResult.isError()) { + return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED, + deferResult.getErrorMessage()); + } + } + + ApkAssets apkAssets = assetLoader.getBaseApkAssets(); + boolean definesOverlayable = false; + try { + definesOverlayable = apkAssets.definesOverlayable(); + } catch (IOException ignored) { + // Will fail if there's no packages in the ApkAssets, which can be treated as false + } + + if (definesOverlayable) { + SparseArray packageNames = assets.getAssignedPackageIdentifiers(); + int size = packageNames.size(); + for (int index = 0; index < size; index++) { + String packageName = packageNames.valueAt(index); + Map overlayableToActor = assets.getOverlayableMap(packageName); + if (overlayableToActor != null && !overlayableToActor.isEmpty()) { + for (String overlayable : overlayableToActor.keySet()) { + pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable)); + } + } + } + } + + pkg.setVolumeUuid(volumeUuid); + + if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { + final ParseResult ret = + getSigningDetails(input, pkg, false /*skipVerify*/); + if (ret.isError()) { + return input.error(ret); + } + pkg.setSigningDetails(ret.getResult()); + } else { + pkg.setSigningDetails(SigningDetails.UNKNOWN); + } + + return input.success(pkg); + } catch (Exception e) { + return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } + } + + private ParseResult parseSplitApk(ParseInput input, + ParsingPackage pkg, int splitIndex, AssetManager assets, int flags) { + final String apkPath = pkg.getSplitCodePaths()[splitIndex]; + + if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); + + // This must always succeed, as the path has been added to the AssetManager before. + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, + ANDROID_MANIFEST_FILENAME)) { + Resources res = new Resources(assets, mDisplayMetrics, null); + ParseResult parseResult = parseSplitApk(input, pkg, res, + parser, flags, splitIndex); + if (parseResult.isError()) { + return input.error(parseResult.getErrorCode(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + parseResult.getErrorMessage()); + } + + return parseResult; + } catch (Exception e) { + return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } + } + + /** + * Parse the manifest of a base APK. When adding new features you need to consider + * whether they should be supported by split APKs and child packages. + * + * @param apkPath The package apk file path + * @param res The resources from which to resolve values + * @param parser The manifest parser + * @param flags Flags how to parse + * @param shouldSkipComponents If the package is a sdk-library + * @return Parsed package or null on error. + */ + private ParseResult parseBaseApk(ParseInput input, String apkPath, + String codePath, Resources res, XmlResourceParser parser, int flags, + boolean shouldSkipComponents) throws XmlPullParserException, IOException { + final String splitName; + final String pkgName; + + ParseResult> packageSplitResult = + ApkLiteParseUtils.parsePackageSplitNames(input, parser); + if (packageSplitResult.isError()) { + return input.error(packageSplitResult); + } + + Pair packageSplit = packageSplitResult.getResult(); + pkgName = packageSplit.first; + splitName = packageSplit.second; + + if (!TextUtils.isEmpty(splitName)) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, + "Expected base APK, but found split " + splitName + ); + } + + final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest); + try { + final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/, + "coreApp", false); + final ParsingPackage pkg = mCallback.startParsingPackage( + pkgName, apkPath, codePath, manifestArray, isCoreApp); + final ParseResult result = + parseBaseApkTags(input, pkg, manifestArray, res, parser, flags, + shouldSkipComponents); + if (result.isError()) { + return result; + } + + return input.success(pkg); + } finally { + manifestArray.recycle(); + } + } + + /** + * Parse the manifest of a split APK. + *

+ * Note that split APKs have many more restrictions on what they're capable of doing, so many + * valid features of a base APK have been carefully omitted here. + * + * @param pkg builder to fill + * @return false on failure + */ + private ParseResult parseSplitApk(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser, int flags, int splitIndex) + throws XmlPullParserException, IOException { + // We parsed manifest tag earlier; just skip past it + final ParseResult> packageSplitResult = + ApkLiteParseUtils.parsePackageSplitNames(input, parser); + if (packageSplitResult.isError()) { + return input.error(packageSplitResult); + } + + int type; + + boolean foundApp = false; + + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (outerDepth + 1 < parser.getDepth() || type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + String tagName = parser.getName(); + if (TAG_APPLICATION.equals(tagName)) { + if (foundApp) { + if (RIGID_PARSER) { + result = input.error(" has more than one "); + } else { + Slog.w(TAG, " has more than one "); + result = input.success(null); + } + } else { + foundApp = true; + result = parseSplitApplication(input, pkg, res, parser, flags, splitIndex); + } + } else { + result = ParsingUtils.unknownTag("", pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + + if (!foundApp) { + ParseResult deferResult = input.deferError( + " does not contain an ", DeferredError.MISSING_APP_TAG); + if (deferResult.isError()) { + return input.error(deferResult); + } + } + + return input.success(pkg); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * split APK manifest. + *

+ * Note that split APKs have many more restrictions on what they're capable of doing, so many + * valid features of a base APK have been carefully omitted here. + */ + private ParseResult parseSplitApplication(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); + try { + pkg.setSplitHasCode(splitIndex, sa.getBoolean( + R.styleable.AndroidManifestApplication_hasCode, true)); + + final String classLoaderName = sa.getString( + R.styleable.AndroidManifestApplication_classLoader); + if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName( + classLoaderName)) { + pkg.setSplitClassLoaderName(splitIndex, classLoaderName); + } else { + return input.error("Invalid class loader name: " + classLoaderName); + } + } finally { + sa.recycle(); + } + + // If the loaded component did not specify a split, inherit the split name + // based on the split it is defined in. + // This is used to later load the correct split when starting this + // component. + String defaultSplitName = pkg.getSplitNames()[splitIndex]; + + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + ParsedMainComponent mainComponent = null; + + final ParseResult result; + String tagName = parser.getName(); + boolean isActivity = false; + switch (tagName) { + case "activity": + isActivity = true; + // fall-through + case "receiver": + ParseResult activityResult = + ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, + res, parser, flags, sUseRoundIcon, defaultSplitName, input); + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + if (isActivity) { + pkg.addActivity(activity); + } else { + pkg.addReceiver(activity); + } + mainComponent = activity; + } + result = activityResult; + break; + case "service": + ParseResult serviceResult = ParsedServiceUtils.parseService( + mSeparateProcesses, pkg, res, parser, flags, sUseRoundIcon, + defaultSplitName, input); + if (serviceResult.isSuccess()) { + ParsedService service = serviceResult.getResult(); + pkg.addService(service); + mainComponent = service; + } + result = serviceResult; + break; + case "provider": + ParseResult providerResult = + ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, + flags, sUseRoundIcon, defaultSplitName, input); + if (providerResult.isSuccess()) { + ParsedProvider provider = providerResult.getResult(); + pkg.addProvider(provider); + mainComponent = provider; + } + result = providerResult; + break; + case "activity-alias": + activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, parser, + sUseRoundIcon, defaultSplitName, input); + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + pkg.addActivity(activity); + mainComponent = activity; + } + + result = activityResult; + break; + default: + result = parseSplitBaseAppChildTags(input, tagName, pkg, res, parser); + break; + } + + if (result.isError()) { + return input.error(result); + } + + if (hasTooManyComponents(pkg)) { + return input.error(MAX_NUM_COMPONENTS_ERR_MSG); + } + } + + return input.success(pkg); + } + + private static boolean hasTooManyComponents(ParsingPackage pkg) { + return (pkg.getActivities().size() + pkg.getServices().size() + pkg.getProviders().size() + + pkg.getReceivers().size()) > MAX_NUM_COMPONENTS; + } + + /** + * For parsing non-MainComponents. Main ones have an order and some special handling which is + * done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources, + * XmlResourceParser, int, int)}. + */ + private ParseResult parseSplitBaseAppChildTags(ParseInput input, String tag, ParsingPackage pkg, + Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { + switch (tag) { + case "meta-data": + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + ParseResult metaDataResult = parseMetaData(pkg, null /*component*/, + res, parser, "", input); + if (metaDataResult.isSuccess() && metaDataResult.getResult() != null) { + pkg.setMetaData(metaDataResult.getResult().toBundle(pkg.getMetaData())); + } + return metaDataResult; + case "property": + ParseResult propertyResult = parseMetaData(pkg, null /*component*/, + res, parser, "", input); + if (propertyResult.isSuccess()) { + pkg.addProperty(propertyResult.getResult()); + } + return propertyResult; + case "uses-sdk-library": + return parseUsesSdkLibrary(input, pkg, res, parser); + case "uses-static-library": + return parseUsesStaticLibrary(input, pkg, res, parser); + case "uses-library": + return parseUsesLibrary(input, pkg, res, parser); + case "uses-native-library": + return parseUsesNativeLibrary(input, pkg, res, parser); + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + return input.success(null); + default: + return ParsingUtils.unknownTag("", pkg, parser, input); + } + } + private ParseResult parseBaseApkTags(ParseInput input, ParsingPackage pkg, + TypedArray sa, Resources res, XmlResourceParser parser, int flags, + boolean shouldSkipComponents) throws XmlPullParserException, IOException { + ParseResult sharedUserResult = parseSharedUser(input, pkg, sa); + if (sharedUserResult.isError()) { + return sharedUserResult; + } + + final boolean updatableSystem = parser.getAttributeBooleanValue(null /*namespace*/, + "updatableSystem", true); + + pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION, + R.styleable.AndroidManifest_installLocation, sa)) + .setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX, + R.styleable.AndroidManifest_targetSandboxVersion, sa)) + /* Set the global "on SD card" flag */ + .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0) + .setUpdatableSystem(updatableSystem); + + boolean foundApp = false; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + String tagName = parser.getName(); + final ParseResult result; + + // has special logic, so it's handled outside the general method + if (TAG_APPLICATION.equals(tagName)) { + if (foundApp) { + if (RIGID_PARSER) { + result = input.error(" has more than one "); + } else { + Slog.w(TAG, " has more than one "); + result = input.success(null); + } + } else { + foundApp = true; + result = parseBaseApplication(input, pkg, res, parser, flags, + shouldSkipComponents); + } + } else { + result = parseBaseApkTag(tagName, input, pkg, res, parser, flags); + } + + if (result.isError()) { + return input.error(result); + } + } + + if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) { + ParseResult deferResult = input.deferError( + " does not contain an or ", + DeferredError.MISSING_APP_TAG); + if (deferResult.isError()) { + return input.error(deferResult); + } + } + + return validateBaseApkTags(input, pkg); + } + + private ParseResult validateBaseApkTags(ParseInput input, ParsingPackage pkg) { + if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) { + return input.error( + INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Combination tags are not valid" + ); + } + + if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) { + return input.error( + INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Found duplicate permission with a different attribute value." + ); + } + + convertCompatPermissions(pkg); + + convertSplitPermissions(pkg); + + // At this point we can check if an application is not supporting densities and hence + // cannot be windowed / resized. Note that an SDK version of 0 is common for + // pre-Doughnut applications. + if (pkg.getTargetSdkVersion() < DONUT + || (!pkg.isSmallScreensSupported() + && !pkg.isNormalScreensSupported() + && !pkg.isLargeScreensSupported() + && !pkg.isExtraLargeScreensSupported() + && !pkg.isResizeable() + && !pkg.isAnyDensity())) { + adjustPackageToBeUnresizeableAndUnpipable(pkg); + } + + return input.success(pkg); + } + + private ParseResult parseBaseApkTag(String tag, ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) + throws IOException, XmlPullParserException { + switch (tag) { + case TAG_OVERLAY: + return parseOverlay(input, pkg, res, parser); + case TAG_KEY_SETS: + return parseKeySets(input, pkg, res, parser); + case "feature": // TODO moltmann: Remove + case TAG_ATTRIBUTION: + return parseAttribution(input, pkg, res, parser); + case TAG_PERMISSION_GROUP: + return parsePermissionGroup(input, pkg, res, parser); + case TAG_PERMISSION: + return parsePermission(input, pkg, res, parser); + case TAG_PERMISSION_TREE: + return parsePermissionTree(input, pkg, res, parser); + case TAG_USES_PERMISSION: + case TAG_USES_PERMISSION_SDK_M: + case TAG_USES_PERMISSION_SDK_23: + return parseUsesPermission(input, pkg, res, parser); + case TAG_USES_CONFIGURATION: + return parseUsesConfiguration(input, pkg, res, parser); + case TAG_USES_FEATURE: + return parseUsesFeature(input, pkg, res, parser); + case TAG_FEATURE_GROUP: + return parseFeatureGroup(input, pkg, res, parser); + case TAG_USES_SDK: + return parseUsesSdk(input, pkg, res, parser, flags); + case TAG_SUPPORT_SCREENS: + return parseSupportScreens(input, pkg, res, parser); + case TAG_PROTECTED_BROADCAST: + return parseProtectedBroadcast(input, pkg, res, parser); + case TAG_INSTRUMENTATION: + return parseInstrumentation(input, pkg, res, parser); + case TAG_ORIGINAL_PACKAGE: + return parseOriginalPackage(input, pkg, res, parser); + case TAG_ADOPT_PERMISSIONS: + return parseAdoptPermissions(input, pkg, res, parser); + case TAG_USES_GL_TEXTURE: + case TAG_COMPATIBLE_SCREENS: + case TAG_SUPPORTS_INPUT: + case TAG_EAT_COMMENT: + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + return input.success(pkg); + case TAG_RESTRICT_UPDATE: + return parseRestrictUpdateHash(flags, input, pkg, res, parser); + case TAG_INSTALL_CONSTRAINTS: + return parseInstallConstraints(input, pkg, res, parser, + mCallback.getInstallConstraintsAllowlist()); + case TAG_QUERIES: + return parseQueries(input, pkg, res, parser); + default: + return ParsingUtils.unknownTag("", pkg, parser, input); + } + } + + private static ParseResult parseSharedUser(ParseInput input, + ParsingPackage pkg, TypedArray sa) { + String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa); + if (TextUtils.isEmpty(str)) { + return input.success(pkg); + } + + if (!"android".equals(pkg.getPackageName())) { + ParseResult nameResult = FrameworkParsingPackageUtils.validateName(input, str, + true, true); + if (nameResult.isError()) { + return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + " specifies bad sharedUserId name \"" + str + "\": " + + nameResult.getErrorMessage()); + } + } + + boolean leaving = false; + if (PackageManager.ENABLE_SHARED_UID_MIGRATION) { + int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa); + leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT); + } + + return input.success(pkg + .setLeavingSharedUser(leaving) + .setSharedUserId(str.intern()) + .setSharedUserLabelResourceId( + resId(R.styleable.AndroidManifest_sharedUserLabel, sa))); + } + + private static ParseResult parseKeySets(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + // we've encountered the 'key-sets' tag + // all the keys and keysets that we want must be defined here + // so we're going to iterate over the parser and pull out the things we want + int outerDepth = parser.getDepth(); + int currentKeySetDepth = -1; + int type; + String currentKeySet = null; + ArrayMap publicKeys = new ArrayMap<>(); + ArraySet upgradeKeySets = new ArraySet<>(); + ArrayMap> definedKeySets = new ArrayMap<>(); + ArraySet improperKeySets = new ArraySet<>(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG) { + if (parser.getDepth() == currentKeySetDepth) { + currentKeySet = null; + currentKeySetDepth = -1; + } + continue; + } + String tagName = parser.getName(); + switch (tagName) { + case "key-set": { + if (currentKeySet != null) { + return input.error("Improperly nested 'key-set' tag at " + + parser.getPositionDescription()); + } + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestKeySet); + try { + final String keysetName = sa.getNonResourceString( + R.styleable.AndroidManifestKeySet_name); + definedKeySets.put(keysetName, new ArraySet<>()); + currentKeySet = keysetName; + currentKeySetDepth = parser.getDepth(); + } finally { + sa.recycle(); + } + } break; + case "public-key": { + if (currentKeySet == null) { + return input.error("Improperly nested 'key-set' tag at " + + parser.getPositionDescription()); + } + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestPublicKey); + try { + final String publicKeyName = nonResString( + R.styleable.AndroidManifestPublicKey_name, sa); + final String encodedKey = nonResString( + R.styleable.AndroidManifestPublicKey_value, sa); + if (encodedKey == null && publicKeys.get(publicKeyName) == null) { + return input.error("'public-key' " + publicKeyName + + " must define a public-key value on first use at " + + parser.getPositionDescription()); + } else if (encodedKey != null) { + PublicKey currentKey = + FrameworkParsingPackageUtils.parsePublicKey(encodedKey); + if (currentKey == null) { + Slog.w(TAG, "No recognized valid key in 'public-key' tag at " + + parser.getPositionDescription() + " key-set " + + currentKeySet + + " will not be added to the package's defined key-sets."); + improperKeySets.add(currentKeySet); + XmlUtils.skipCurrentTag(parser); + continue; + } + if (publicKeys.get(publicKeyName) == null + || publicKeys.get(publicKeyName).equals(currentKey)) { + + /* public-key first definition, or matches old definition */ + publicKeys.put(publicKeyName, currentKey); + } else { + return input.error("Value of 'public-key' " + publicKeyName + + " conflicts with previously defined value at " + + parser.getPositionDescription()); + } + } + definedKeySets.get(currentKeySet).add(publicKeyName); + XmlUtils.skipCurrentTag(parser); + } finally { + sa.recycle(); + } + } break; + case "upgrade-key-set": { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUpgradeKeySet); + try { + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUpgradeKeySet_name); + upgradeKeySets.add(name); + XmlUtils.skipCurrentTag(parser); + } finally { + sa.recycle(); + } + } break; + default: + ParseResult result = ParsingUtils.unknownTag("", pkg, parser, + input); + if (result.isError()) { + return input.error(result); + } + break; + } + } + String packageName = pkg.getPackageName(); + Set publicKeyNames = publicKeys.keySet(); + if (publicKeyNames.removeAll(definedKeySets.keySet())) { + return input.error("Package" + packageName + + " AndroidManifest.xml 'key-set' and 'public-key' names must be distinct."); + } + + for (ArrayMap.Entry> e : definedKeySets.entrySet()) { + final String keySetName = e.getKey(); + if (e.getValue().size() == 0) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " has no valid associated 'public-key'." + + " Not including in package's defined key-sets."); + continue; + } else if (improperKeySets.contains(keySetName)) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " contained improper 'public-key'" + + " tags. Not including in package's defined key-sets."); + continue; + } + + for (String s : e.getValue()) { + pkg.addKeySet(keySetName, publicKeys.get(s)); + } + } + if (pkg.getKeySetMapping().keySet().containsAll(upgradeKeySets)) { + pkg.setUpgradeKeySets(upgradeKeySets); + } else { + return input.error("Package" + packageName + + " AndroidManifest.xml does not define all 'upgrade-key-set's ."); + } + + return input.success(pkg); + } + + private static ParseResult parseAttribution(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws IOException, XmlPullParserException { + ParseResult result = ParsedAttributionUtils.parseAttribution(res, + parser, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addAttribution(result.getResult())); + } + + private static ParseResult parsePermissionGroup(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult result = ParsedPermissionUtils.parsePermissionGroup( + pkg, res, parser, sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addPermissionGroup(result.getResult())); + } + + private static ParseResult parsePermission(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult result = ParsedPermissionUtils.parsePermission( + pkg, res, parser, sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + ParsedPermission permission = result.getResult(); + if (permission != null) { + pkg.addPermission(permission); + } + return input.success(pkg); + } + + private static ParseResult parsePermissionTree(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult result = ParsedPermissionUtils.parsePermissionTree( + pkg, res, parser, sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addPermission(result.getResult())); + } + + private int parseMinOrMaxSdkVersion(TypedArray sa, int attr, int defaultValue) { + int val = defaultValue; + TypedValue peekVal = sa.peekValue(attr); + if (peekVal != null) { + if (peekVal.type >= TypedValue.TYPE_FIRST_INT + && peekVal.type <= TypedValue.TYPE_LAST_INT) { + val = peekVal.data; + } + } + return val; + } + + private ParseResult parseUsesPermission(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesPermission); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUsesPermission_name); + if (TextUtils.length(name) > MAX_PERMISSION_NAME_LENGTH) { + return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "The name in the is greater than " + + MAX_PERMISSION_NAME_LENGTH); + } + + int minSdkVersion = parseMinOrMaxSdkVersion(sa, + R.styleable.AndroidManifestUsesPermission_minSdkVersion, + Integer.MIN_VALUE); + + int maxSdkVersion = parseMinOrMaxSdkVersion(sa, + R.styleable.AndroidManifestUsesPermission_maxSdkVersion, + Integer.MAX_VALUE); + + final ArraySet requiredFeatures = new ArraySet<>(); + String feature = sa.getNonConfigurationString( + com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, + 0); + if (feature != null) { + requiredFeatures.add(feature); + } + + final ArraySet requiredNotFeatures = new ArraySet<>(); + feature = sa.getNonConfigurationString( + com.android.internal.R.styleable + .AndroidManifestUsesPermission_requiredNotFeature, + 0); + if (feature != null) { + requiredNotFeatures.add(feature); + } + + final int usesPermissionFlags = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesPermission_usesPermissionFlags, + 0); + + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final ParseResult result; + switch (parser.getName()) { + case "required-feature": + result = parseRequiredFeature(input, res, parser); + if (result.isSuccess()) { + requiredFeatures.add((String) result.getResult()); + } + break; + + case "required-not-feature": + result = parseRequiredNotFeature(input, res, parser); + if (result.isSuccess()) { + requiredNotFeatures.add((String) result.getResult()); + } + break; + + default: + result = ParsingUtils.unknownTag("", pkg, parser, input); + break; + } + + if (result.isError()) { + return input.error(result); + } + } + + // Can only succeed from here on out + ParseResult success = input.success(pkg); + + if (name == null) { + return success; + } + + if (Build.VERSION.RESOURCES_SDK_INT < minSdkVersion + || Build.VERSION.RESOURCES_SDK_INT > maxSdkVersion) { + return success; + } + + if (mCallback != null) { + // Only allow requesting this permission if the platform supports all of the + // "required-feature"s. + for (int i = requiredFeatures.size() - 1; i >= 0; i--) { + if (!mCallback.hasFeature(requiredFeatures.valueAt(i))) { + return success; + } + } + + // Only allow requesting this permission if the platform does not supports any of + // the "required-not-feature"s. + for (int i = requiredNotFeatures.size() - 1; i >= 0; i--) { + if (mCallback.hasFeature(requiredNotFeatures.valueAt(i))) { + return success; + } + } + } + + // Quietly ignore duplicate permission requests, but fail loudly if + // the two requests have conflicting flags + boolean found = false; + final List usesPermissions = pkg.getUsesPermissions(); + final int size = usesPermissions.size(); + for (int i = 0; i < size; i++) { + final ParsedUsesPermission usesPermission = usesPermissions.get(i); + if (Objects.equals(usesPermission.getName(), name)) { + if (usesPermission.getUsesPermissionFlags() != usesPermissionFlags) { + return input.error("Conflicting uses-permissions flags: " + + name + " in package: " + pkg.getPackageName() + " at: " + + parser.getPositionDescription()); + } else { + Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " + + name + " in package: " + pkg.getPackageName() + " at: " + + parser.getPositionDescription()); + } + found = true; + break; + } + } + + if (!found) { + pkg.addUsesPermission(new ParsedUsesPermissionImpl(name, usesPermissionFlags)); + } + return success; + } finally { + sa.recycle(); + } + } + + private ParseResult parseRequiredFeature(ParseInput input, Resources res, + AttributeSet attrs) { + final TypedArray sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestRequiredFeature); + try { + final String featureName = sa.getString( + R.styleable.AndroidManifestRequiredFeature_name); + return TextUtils.isEmpty(featureName) + ? input.error("Feature name is missing from tag.") + : input.success(featureName); + } finally { + sa.recycle(); + } + } + + private ParseResult parseRequiredNotFeature(ParseInput input, Resources res, + AttributeSet attrs) { + final TypedArray sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestRequiredNotFeature); + try { + final String featureName = sa.getString( + R.styleable.AndroidManifestRequiredNotFeature_name); + return TextUtils.isEmpty(featureName) + ? input.error("Feature name is missing from tag.") + : input.success(featureName); + } finally { + sa.recycle(); + } + } + + private static ParseResult parseUsesConfiguration(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + ConfigurationInfo cPref = new ConfigurationInfo(); + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesConfiguration); + try { + cPref.reqTouchScreen = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, + Configuration.TOUCHSCREEN_UNDEFINED); + cPref.reqKeyboardType = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, + Configuration.KEYBOARD_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; + } + cPref.reqNavigation = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqNavigation, + Configuration.NAVIGATION_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; + } + pkg.addConfigPreference(cPref); + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static ParseResult parseUsesFeature(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + FeatureInfo fi = parseFeatureInfo(res, parser); + pkg.addReqFeature(fi); + + if (fi.name == null) { + ConfigurationInfo cPref = new ConfigurationInfo(); + cPref.reqGlEsVersion = fi.reqGlEsVersion; + pkg.addConfigPreference(cPref); + } + + return input.success(pkg); + } + + private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) { + FeatureInfo fi = new FeatureInfo(); + TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestUsesFeature); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name); + fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0); + if (fi.name == null) { + fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion, + FeatureInfo.GL_ES_VERSION_UNDEFINED); + } + if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) { + fi.flags |= FeatureInfo.FLAG_REQUIRED; + } + return fi; + } finally { + sa.recycle(); + } + } + + private static ParseResult parseFeatureGroup(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws IOException, XmlPullParserException { + FeatureGroupInfo group = new FeatureGroupInfo(); + ArrayList features = null; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final String innerTagName = parser.getName(); + if (innerTagName.equals("uses-feature")) { + FeatureInfo featureInfo = parseFeatureInfo(res, parser); + // FeatureGroups are stricter and mandate that + // any declared are mandatory. + featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; + features = ArrayUtils.add(features, featureInfo); + } else { + Slog.w(TAG, + "Unknown element under : " + innerTagName + + " at " + pkg.getBaseApkPath() + " " + + parser.getPositionDescription()); + } + } + + if (features != null) { + group.features = new FeatureInfo[features.size()]; + group.features = features.toArray(group.features); + } + + pkg.addFeatureGroup(group); + return input.success(pkg); + } + + private static ParseResult parseUsesSdk(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) + throws IOException, XmlPullParserException { + if (SDK_VERSION > 0) { + final boolean isApkInApex = (flags & PARSE_APK_IN_APEX) != 0; + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); + try { + int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION; + String minCode = null; + boolean minAssigned = false; + int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION; + String targetCode = null; + int maxVers = Integer.MAX_VALUE; + + TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + minCode = val.string.toString(); + minAssigned = !TextUtils.isEmpty(minCode); + } else { + // If it's not a string, it's an integer. + minVers = val.data; + minAssigned = true; + } + } + + val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + targetCode = val.string.toString(); + if (!minAssigned) { + minCode = targetCode; + } + } else { + // If it's not a string, it's an integer. + targetVers = val.data; + } + } else { + targetVers = minVers; + targetCode = minCode; + } + + if (isApkInApex) { + val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion); + if (val != null) { + // maxSdkVersion only supports integer + maxVers = val.data; + } + } + + ParseResult targetSdkVersionResult = FrameworkParsingPackageUtils + .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input, + isApkInApex); + if (targetSdkVersionResult.isError()) { + return input.error(targetSdkVersionResult); + } + + int targetSdkVersion = targetSdkVersionResult.getResult(); + + ParseResult deferResult = + input.enableDeferredError(pkg.getPackageName(), targetSdkVersion); + if (deferResult.isError()) { + return input.error(deferResult); + } + + ParseResult minSdkVersionResult = FrameworkParsingPackageUtils + .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, input); + if (minSdkVersionResult.isError()) { + return input.error(minSdkVersionResult); + } + + int minSdkVersion = minSdkVersionResult.getResult(); + + pkg.setMinSdkVersion(minSdkVersion) + .setTargetSdkVersion(targetSdkVersion); + if (isApkInApex) { + ParseResult maxSdkVersionResult = FrameworkParsingPackageUtils + .computeMaxSdkVersion(maxVers, SDK_VERSION, input); + if (maxSdkVersionResult.isError()) { + return input.error(maxSdkVersionResult); + } + int maxSdkVersion = maxSdkVersionResult.getResult(); + pkg.setMaxSdkVersion(maxSdkVersion); + } + + int type; + final int innerDepth = parser.getDepth(); + SparseIntArray minExtensionVersions = null; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final ParseResult result; + if (parser.getName().equals("extension-sdk")) { + if (minExtensionVersions == null) { + minExtensionVersions = new SparseIntArray(); + } + result = parseExtensionSdk(input, res, parser, minExtensionVersions); + XmlUtils.skipCurrentTag(parser); + } else { + result = ParsingUtils.unknownTag("", pkg, parser, input); + } + + if (result.isError()) { + return input.error(result); + } + } + pkg.setMinExtensionVersions(exactSizedCopyOfSparseArray(minExtensionVersions)); + } finally { + sa.recycle(); + } + } + return input.success(pkg); + } + + @Nullable + private static SparseIntArray exactSizedCopyOfSparseArray(@Nullable SparseIntArray input) { + if (input == null) { + return null; + } + SparseIntArray output = new SparseIntArray(input.size()); + for (int i = 0; i < input.size(); i++) { + output.put(input.keyAt(i), input.valueAt(i)); + } + return output; + } + + private static ParseResult parseExtensionSdk( + ParseInput input, Resources res, XmlResourceParser parser, + SparseIntArray minExtensionVersions) { + int sdkVersion; + int minVersion; + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestExtensionSdk); + try { + sdkVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1); + minVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_minExtensionVersion, -1); + } finally { + sa.recycle(); + } + + if (sdkVersion < 0) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + " must specify an sdkVersion >= 0"); + } + if (minVersion < 0) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + " must specify minExtensionVersion >= 0"); + } + + try { + int version = SdkExtensions.getExtensionVersion(sdkVersion); + if (version < minVersion) { + return input.error( + PackageManager.INSTALL_FAILED_OLDER_SDK, + "Package requires " + sdkVersion + " extension version " + minVersion + + " which exceeds device version " + version); + } + } catch (RuntimeException e) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Specified sdkVersion " + sdkVersion + " is not valid"); + } + minExtensionVersions.put(sdkVersion, minVersion); + return input.success(minExtensionVersions); + } + + private static ParseResult parseRestrictUpdateHash(int flags, ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + if ((flags & PARSE_IS_SYSTEM_DIR) != 0) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestRestrictUpdate); + try { + final String hash = sa.getNonConfigurationString( + R.styleable.AndroidManifestRestrictUpdate_hash, + 0); + + if (hash != null) { + final int hashLength = hash.length(); + final byte[] hashBytes = new byte[hashLength / 2]; + for (int i = 0; i < hashLength; i += 2) { + hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16) + << 4) + + Character.digit(hash.charAt(i + 1), 16)); + } + pkg.setRestrictUpdateHash(hashBytes); + } else { + pkg.setRestrictUpdateHash(null); + } + } finally { + sa.recycle(); + } + } + return input.success(pkg); + } + + private static ParseResult parseInstallConstraints(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, Set allowlist) + throws IOException, XmlPullParserException { + return InstallConstraintsTagParser.parseInstallConstraints( + input, pkg, res, parser, allowlist); + } + + private static ParseResult parseQueries(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + if (parser.getName().equals("intent")) { + ParseResult result = ParsedIntentInfoUtils.parseIntentInfo( + null /*className*/, pkg, res, parser, true /*allowGlobs*/, + true /*allowAutoVerify*/, input); + if (result.isError()) { + return input.error(result); + } + + IntentFilter intentInfo = result.getResult().getIntentFilter(); + + Uri data = null; + String dataType = null; + String host = null; + final int numActions = intentInfo.countActions(); + final int numSchemes = intentInfo.countDataSchemes(); + final int numTypes = intentInfo.countDataTypes(); + final int numHosts = intentInfo.getHosts().length; + if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { + return input.error("intent tags must contain either an action or data."); + } + if (numActions > 1) { + return input.error("intent tag may have at most one action."); + } + if (numTypes > 1) { + return input.error("intent tag may have at most one data type."); + } + if (numSchemes > 1) { + return input.error("intent tag may have at most one data scheme."); + } + if (numHosts > 1) { + return input.error("intent tag may have at most one data host."); + } + Intent intent = new Intent(); + for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { + intent.addCategory(intentInfo.getCategory(i)); + } + if (numHosts == 1) { + host = intentInfo.getHosts()[0]; + } + if (numSchemes == 1) { + data = new Uri.Builder() + .scheme(intentInfo.getDataScheme(0)) + .authority(host) + .path(IntentFilter.WILDCARD_PATH) + .build(); + } + if (numTypes == 1) { + dataType = intentInfo.getDataType(0); + // The dataType may have had the '/' removed for the dynamic mimeType feature. + // If we detect that case, we add the * back. + if (!dataType.contains("/")) { + dataType = dataType + "/*"; + } + if (data == null) { + data = new Uri.Builder() + .scheme("content") + .authority(IntentFilter.WILDCARD) + .path(IntentFilter.WILDCARD_PATH) + .build(); + } + } + intent.setDataAndType(data, dataType); + if (numActions == 1) { + intent.setAction(intentInfo.getAction(0)); + } + pkg.addQueriesIntent(intent); + } else if (parser.getName().equals("package")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestQueriesPackage); + final String packageName = sa.getNonConfigurationString( + R.styleable.AndroidManifestQueriesPackage_name, 0); + if (TextUtils.isEmpty(packageName)) { + return input.error("Package name is missing from package tag."); + } + pkg.addQueriesPackage(packageName.intern()); + } else if (parser.getName().equals("provider")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestQueriesProvider); + try { + final String authorities = sa.getNonConfigurationString( + R.styleable.AndroidManifestQueriesProvider_authorities, 0); + if (TextUtils.isEmpty(authorities)) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Authority missing from provider tag." + ); + } + StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";"); + while (authoritiesTokenizer.hasMoreElements()) { + pkg.addQueriesProvider(authoritiesTokenizer.nextToken()); + } + } finally { + sa.recycle(); + } + } + } + return input.success(pkg); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * base APK manifest. + *

+ * When adding new features, carefully consider if they should also be supported by split APKs. + *

+ * This method should avoid using a getter for fields set by this method. Prefer assigning a + * local variable and using it. Otherwise there's an ordering problem which can be broken if any + * code moves around. + */ + private ParseResult parseBaseApplication(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, + boolean shouldSkipComponents) throws XmlPullParserException, IOException { + final String pkgName = pkg.getPackageName(); + int targetSdk = pkg.getTargetSdkVersion(); + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); + try { + // TODO(b/135203078): Remove this and force unit tests to mock an empty manifest + // This case can only happen in unit tests where we sometimes need to create fakes + // of various package parser data structures. + if (sa == null) { + return input.error(" does not contain any attributes"); + } + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestApplication_name, + 0); + if (name != null) { + String packageName = pkg.getPackageName(); + String outInfoName = ParsingUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { + return input.error(" invalid android:name"); + } else if (outInfoName == null) { + return input.error("Empty class name in package " + packageName); + } + + pkg.setApplicationClassName(outInfoName); + } + + TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label); + if (labelValue != null) { + pkg.setLabelResourceId(labelValue.resourceId); + if (labelValue.resourceId == 0) { + pkg.setNonLocalizedLabel(labelValue.coerceToString()); + } + } + + parseBaseAppBasicFlags(pkg, sa); + + String manageSpaceActivity = nonConfigString(Configuration.NATIVE_CONFIG_VERSION, + R.styleable.AndroidManifestApplication_manageSpaceActivity, sa); + if (manageSpaceActivity != null) { + String manageSpaceActivityName = ParsingUtils.buildClassName(pkgName, + manageSpaceActivity); + + if (manageSpaceActivityName == null) { + return input.error("Empty class name in package " + pkgName); + } + + pkg.setManageSpaceActivityName(manageSpaceActivityName); + } + + if (pkg.isBackupAllowed()) { + // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, + // and restoreAnyVersion are only relevant if backup is possible for the + // given application. + String backupAgent = nonConfigString(Configuration.NATIVE_CONFIG_VERSION, + R.styleable.AndroidManifestApplication_backupAgent, sa); + if (backupAgent != null) { + String backupAgentName = ParsingUtils.buildClassName(pkgName, backupAgent); + if (backupAgentName == null) { + return input.error("Empty class name in package " + pkgName); + } + + if (DEBUG_BACKUP) { + Slog.v(TAG, "android:backupAgent = " + backupAgentName + + " from " + pkgName + "+" + backupAgent); + } + + pkg.setBackupAgentName(backupAgentName) + .setKillAfterRestoreAllowed(bool(true, + R.styleable.AndroidManifestApplication_killAfterRestore, sa)) + .setRestoreAnyVersion(bool(false, + R.styleable.AndroidManifestApplication_restoreAnyVersion, sa)) + .setFullBackupOnly(bool(false, + R.styleable.AndroidManifestApplication_fullBackupOnly, sa)) + .setBackupInForeground(bool(false, + R.styleable.AndroidManifestApplication_backupInForeground, sa)); + } + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestApplication_fullBackupContent); + int fullBackupContent = 0; + + if (v != null) { + fullBackupContent = v.resourceId; + + if (v.resourceId == 0) { + if (DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent specified as boolean=" + + (v.data == 0 ? "false" : "true")); + } + // "false" => -1, "true" => 0 + fullBackupContent = v.data == 0 ? -1 : 0; + } + + pkg.setFullBackupContentResourceId(fullBackupContent); + } + if (DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName); + } + } + + if (sa.getBoolean(R.styleable.AndroidManifestApplication_persistent, false)) { + // Check if persistence is based on a feature being present + final String requiredFeature = sa.getNonResourceString(R.styleable + .AndroidManifestApplication_persistentWhenFeatureAvailable); + pkg.setPersistent(requiredFeature == null || mCallback.hasFeature(requiredFeature)); + } + + if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { + pkg.setResizeableActivity(sa.getBoolean( + R.styleable.AndroidManifestApplication_resizeableActivity, true)); + } else { + pkg.setResizeableActivityViaSdkVersion( + targetSdk >= Build.VERSION_CODES.N); + } + + String taskAffinity; + if (targetSdk >= Build.VERSION_CODES.FROYO) { + taskAffinity = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + taskAffinity = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_taskAffinity); + } + + ParseResult taskAffinityResult = ComponentParseUtils.buildTaskAffinityName( + pkgName, pkgName, taskAffinity, input); + if (taskAffinityResult.isError()) { + return input.error(taskAffinityResult); + } + + pkg.setTaskAffinity(taskAffinityResult.getResult()); + String factory = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_appComponentFactory); + if (factory != null) { + String appComponentFactory = ParsingUtils.buildClassName(pkgName, factory); + if (appComponentFactory == null) { + return input.error("Empty class name in package " + pkgName); + } + + pkg.setAppComponentFactory(appComponentFactory); + } + + CharSequence pname; + if (targetSdk >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_process); + } + ParseResult processNameResult = ComponentParseUtils.buildProcessName( + pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input); + if (processNameResult.isError()) { + return input.error(processNameResult); + } + + String processName = processNameResult.getResult(); + pkg.setProcessName(processName); + + if (pkg.isSaveStateDisallowed()) { + // A heavy-weight application can not be in a custom process. + // We can do direct compare because we intern all strings. + if (processName != null && !processName.equals(pkgName)) { + return input.error( + "cantSaveState applications can not use custom processes"); + } + } + + String classLoaderName = pkg.getClassLoaderName(); + if (classLoaderName != null + && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { + return input.error("Invalid class loader name: " + classLoaderName); + } + + pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1)); + pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1)); + if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized)) { + final boolean v = sa.getBoolean( + R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized, false); + pkg.setNativeHeapZeroInitialized( + v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED); + } + if (sa.hasValue( + R.styleable.AndroidManifestApplication_requestRawExternalStorageAccess)) { + pkg.setRequestRawExternalStorageAccess(sa.getBoolean(R.styleable + .AndroidManifestApplication_requestRawExternalStorageAccess, + false)); + } + if (sa.hasValue( + R.styleable.AndroidManifestApplication_requestForegroundServiceExemption)) { + pkg.setRequestForegroundServiceExemption(sa.getBoolean(R.styleable + .AndroidManifestApplication_requestForegroundServiceExemption, + false)); + } + final ParseResult> knownActivityEmbeddingCertsResult = + parseKnownActivityEmbeddingCerts(sa, res, + R.styleable.AndroidManifestApplication_knownActivityEmbeddingCerts, + input); + if (knownActivityEmbeddingCertsResult.isError()) { + return input.error(knownActivityEmbeddingCertsResult); + } else { + final Set knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult + .getResult(); + if (knownActivityEmbeddingCerts != null) { + pkg.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts); + } + } + } finally { + sa.recycle(); + } + + boolean hasActivityOrder = false; + boolean hasReceiverOrder = false; + boolean hasServiceOrder = false; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final ParseResult result; + String tagName = parser.getName(); + boolean isActivity = false; + switch (tagName) { + case "activity": + isActivity = true; + // fall-through + case "receiver": + if (shouldSkipComponents) { + continue; + } + ParseResult activityResult = + ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, + res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/, + input); + + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + if (isActivity) { + hasActivityOrder |= (activity.getOrder() != 0); + pkg.addActivity(activity); + } else { + hasReceiverOrder |= (activity.getOrder() != 0); + pkg.addReceiver(activity); + } + } + + result = activityResult; + break; + case "service": + if (shouldSkipComponents) { + continue; + } + ParseResult serviceResult = + ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser, + flags, sUseRoundIcon, null /*defaultSplitName*/, + input); + if (serviceResult.isSuccess()) { + ParsedService service = serviceResult.getResult(); + hasServiceOrder |= (service.getOrder() != 0); + pkg.addService(service); + } + + result = serviceResult; + break; + case "provider": + if (shouldSkipComponents) { + continue; + } + ParseResult providerResult = + ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, + flags, sUseRoundIcon, null /*defaultSplitName*/, + input); + if (providerResult.isSuccess()) { + pkg.addProvider(providerResult.getResult()); + } + + result = providerResult; + break; + case "activity-alias": + if (shouldSkipComponents) { + continue; + } + activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, + parser, sUseRoundIcon, null /*defaultSplitName*/, + input); + if (activityResult.isSuccess()) { + ParsedActivity activity = activityResult.getResult(); + hasActivityOrder |= (activity.getOrder() != 0); + pkg.addActivity(activity); + } + + result = activityResult; + break; + case "apex-system-service": + ParseResult systemServiceResult = + ParsedApexSystemServiceUtils.parseApexSystemService(res, + parser, input); + if (systemServiceResult.isSuccess()) { + ParsedApexSystemService systemService = + systemServiceResult.getResult(); + pkg.addApexSystemService(systemService); + } + + result = systemServiceResult; + break; + default: + result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags); + break; + } + + if (result.isError()) { + return input.error(result); + } + if (hasTooManyComponents(pkg)) { + return input.error(MAX_NUM_COMPONENTS_ERR_MSG); + } + } + + if (TextUtils.isEmpty(pkg.getStaticSharedLibraryName()) && TextUtils.isEmpty( + pkg.getSdkLibraryName())) { + // Add a hidden app detail activity to normal apps which forwards user to App Details + // page. + ParseResult a = generateAppDetailsHiddenActivity(input, pkg); + if (a.isError()) { + // Error should be impossible here, as the only failure case as of SDK R is a + // string validation error on a constant ":app_details" string passed in by the + // parsing code itself. For this reason, this is just a hard failure instead of + // deferred. + return input.error(a); + } + + pkg.addActivity(a.getResult()); + } + + if (hasActivityOrder) { + pkg.sortActivities(); + } + if (hasReceiverOrder) { + pkg.sortReceivers(); + } + if (hasServiceOrder) { + pkg.sortServices(); + } + + afterParseBaseApplication(pkg); + + return input.success(pkg); + } + + // Must be run after the entire {@link ApplicationInfo} has been fully processed and after + // every activity info has had a chance to set it from its attributes. + private void afterParseBaseApplication(ParsingPackage pkg) { + setMaxAspectRatio(pkg); + setMinAspectRatio(pkg); + setSupportsSizeChanges(pkg); + + pkg.setHasDomainUrls(hasDomainURLs(pkg)); + } + + /** + * Collection of single-line, no (or little) logic assignments. Separated for readability. + *

+ * Flags are separated by type and by default value. They are sorted alphabetically within each + * section. + */ + private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) { + int targetSdk = pkg.getTargetSdkVersion(); + //@formatter:off + // CHECKSTYLE:off + pkg + // Default true + .setBackupAllowed(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa)) + .setClearUserDataAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa)) + .setClearUserDataOnFailedRestoreAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa)) + .setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa)) + .setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa)) + .setExtractNativeLibrariesRequested(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa)) + .setDeclaredHavingCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa)) + // Default false + .setTaskReparentingAllowed(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa)) + .setSaveStateDisallowed(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa)) + .setCrossProfile(bool(false, R.styleable.AndroidManifestApplication_crossProfile, sa)) + .setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa)) + .setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa)) + .setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa)) + .setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa)) + .setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa)) + .setUserDataFragile(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa)) + .setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa)) + .setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa)) + .setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa)) + .setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa)) + .setRtlSupported(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa)) + .setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa)) + .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa)) + .setNonSdkApiRequested(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa)) + .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa)) + .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa)) + .setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa)) + .setResetEnabledSettingsOnAppDataCleared(bool(false, + R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared, + sa)) + .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa)) + // targetSdkVersion gated + .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa)) + .setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa)) + .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa)) + .setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa)) + // Ints Default 0 + .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa)) + // Ints + .setCategory(anInt(ApplicationInfo.CATEGORY_UNDEFINED, R.styleable.AndroidManifestApplication_appCategory, sa)) + // Floats Default 0f + .setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa)) + .setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa)) + // Resource ID + .setBannerResourceId(resId(R.styleable.AndroidManifestApplication_banner, sa)) + .setDescriptionResourceId(resId(R.styleable.AndroidManifestApplication_description, sa)) + .setIconResourceId(resId(R.styleable.AndroidManifestApplication_icon, sa)) + .setLogoResourceId(resId(R.styleable.AndroidManifestApplication_logo, sa)) + .setNetworkSecurityConfigResourceId(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa)) + .setRoundIconResourceId(resId(R.styleable.AndroidManifestApplication_roundIcon, sa)) + .setThemeResourceId(resId(R.styleable.AndroidManifestApplication_theme, sa)) + .setDataExtractionRulesResourceId( + resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa)) + .setLocaleConfigResourceId(resId(R.styleable.AndroidManifestApplication_localeConfig, sa)) + // Strings + .setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa)) + .setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa)) + .setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa)) + .setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa)) + // Non-Config String + .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa)); + // CHECKSTYLE:on + //@formatter:on + } + + /** + * For parsing non-MainComponents. Main ones have an order and some special handling which is + * done directly in {@link #parseBaseApplication(ParseInput, ParsingPackage, Resources, + * XmlResourceParser, int, boolean)}. + */ + private ParseResult parseBaseAppChildTag(ParseInput input, String tag, ParsingPackage pkg, + Resources res, XmlResourceParser parser, int flags) + throws IOException, XmlPullParserException { + switch (tag) { + case "meta-data": + // TODO(b/135203078): I have no idea what this comment means + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + final ParseResult metaDataResult = parseMetaData(pkg, null /*component*/, + res, parser, "", input); + if (metaDataResult.isSuccess() && metaDataResult.getResult() != null) { + pkg.setMetaData(metaDataResult.getResult().toBundle(pkg.getMetaData())); + } + return metaDataResult; + case "property": + final ParseResult propertyResult = parseMetaData(pkg, null /*component*/, + res, parser, "", input); + if (propertyResult.isSuccess()) { + pkg.addProperty(propertyResult.getResult()); + } + return propertyResult; + case "sdk-library": + return parseSdkLibrary(pkg, res, parser, input); + case "static-library": + return parseStaticLibrary(pkg, res, parser, input); + case "library": + return parseLibrary(pkg, res, parser, input); + case "uses-sdk-library": + return parseUsesSdkLibrary(input, pkg, res, parser); + case "uses-static-library": + return parseUsesStaticLibrary(input, pkg, res, parser); + case "uses-library": + return parseUsesLibrary(input, pkg, res, parser); + case "uses-native-library": + return parseUsesNativeLibrary(input, pkg, res, parser); + case "processes": + return parseProcesses(input, pkg, res, parser, mSeparateProcesses, flags); + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + return input.success(null); + case "profileable": + return parseProfileable(input, pkg, res, parser); + default: + return ParsingUtils.unknownTag("", pkg, parser, input); + } + } + + @NonNull + private static ParseResult parseSdkLibrary( + ParsingPackage pkg, Resources res, + XmlResourceParser parser, ParseInput input) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSdkLibrary); + try { + // Note: don't allow this value to be a reference to a resource that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestSdkLibrary_name); + final int versionMajor = sa.getInt( + R.styleable.AndroidManifestSdkLibrary_versionMajor, + -1); + + // Fail if malformed. + if (lname == null || versionMajor < 0) { + return input.error("Bad sdk-library declaration name: " + lname + + " version: " + versionMajor); + } else if (pkg.getSharedUserId() != null) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "sharedUserId not allowed in SDK library" + ); + } else if (pkg.getSdkLibraryName() != null) { + return input.error("Multiple SDKs for package " + + pkg.getPackageName()); + } + + return input.success(pkg.setSdkLibraryName(lname.intern()) + .setSdkLibVersionMajor(versionMajor) + .setSdkLibrary(true)); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parseStaticLibrary( + ParsingPackage pkg, Resources res, + XmlResourceParser parser, ParseInput input) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestStaticLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestStaticLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_version, -1); + final int versionMajor = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_versionMajor, + 0); + + // Since the app canot run without a static lib - fail if malformed + if (lname == null || version < 0) { + return input.error("Bad static-library declaration name: " + lname + + " version: " + version); + } else if (pkg.getSharedUserId() != null) { + return input.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "sharedUserId not allowed in static shared library" + ); + } else if (pkg.getStaticSharedLibraryName() != null) { + return input.error("Multiple static-shared libs for package " + + pkg.getPackageName()); + } + + return input.success(pkg.setStaticSharedLibraryName(lname.intern()) + .setStaticSharedLibraryVersion( + PackageInfo.composeLongVersionCode(versionMajor, version)) + .setStaticSharedLibrary(true)); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parseLibrary( + ParsingPackage pkg, Resources res, + XmlResourceParser parser, ParseInput input) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString(R.styleable.AndroidManifestLibrary_name); + + if (lname != null) { + lname = lname.intern(); + if (!ArrayUtils.contains(pkg.getLibraryNames(), lname)) { + pkg.addLibraryName(lname); + } + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parseUsesSdkLibrary(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdkLibrary); + try { + // Note: don't allow this value to be a reference to a resource that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesSdkLibrary_name); + final int versionMajor = sa.getInt( + R.styleable.AndroidManifestUsesSdkLibrary_versionMajor, -1); + String certSha256Digest = sa.getNonResourceString(R.styleable + .AndroidManifestUsesSdkLibrary_certDigest); + boolean optional = + sa.getBoolean(R.styleable.AndroidManifestUsesSdkLibrary_optional, false); + + // Since an APK providing a static shared lib can only provide the lib - fail if + // malformed + if (lname == null || versionMajor < 0 || certSha256Digest == null) { + return input.error("Bad uses-sdk-library declaration name: " + lname + + " version: " + versionMajor + " certDigest" + certSha256Digest); + } + + // Can depend only on one version of the same library + List usesSdkLibraries = pkg.getUsesSdkLibraries(); + if (usesSdkLibraries.contains(lname)) { + return input.error( + "Depending on multiple versions of SDK library " + lname); + } + + lname = lname.intern(); + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + + if ("".equals(certSha256Digest)) { + // Test-only uses-sdk-library empty certificate digest override. + certSha256Digest = SystemProperties.get( + "debug.pm.uses_sdk_library_default_cert_digest", ""); + // Validate the overridden digest. + try { + HexEncoding.decode(certSha256Digest, false); + } catch (IllegalArgumentException e) { + certSha256Digest = ""; + } + } + + ParseResult certResult = parseAdditionalCertificates(input, res, parser); + if (certResult.isError()) { + return input.error(certResult); + } + String[] additionalCertSha256Digests = certResult.getResult(); + + final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; + certSha256Digests[0] = certSha256Digest; + System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, + 1, additionalCertSha256Digests.length); + + return input.success( + pkg.addUsesSdkLibrary(lname, versionMajor, certSha256Digests, optional)); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parseUsesStaticLibrary(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesStaticLibrary); + try { + // Note: don't allow this value to be a reference to a resource that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestUsesStaticLibrary_version, -1); + String certSha256Digest = sa.getNonResourceString(R.styleable + .AndroidManifestUsesStaticLibrary_certDigest); + + // Since an APK providing a static shared lib can only provide the lib - fail if + // malformed + if (lname == null || version < 0 || certSha256Digest == null) { + return input.error("Bad uses-static-library declaration name: " + lname + + " version: " + version + " certDigest" + certSha256Digest); + } + + // Can depend only on one version of the same library + List usesStaticLibraries = pkg.getUsesStaticLibraries(); + if (usesStaticLibraries.contains(lname)) { + return input.error( + "Depending on multiple versions of static library " + lname); + } + + lname = lname.intern(); + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + + // Fot apps targeting O-MR1 we require explicit enumeration of all certs. + String[] additionalCertSha256Digests = EmptyArray.STRING; + if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) { + ParseResult certResult = parseAdditionalCertificates(input, res, parser); + if (certResult.isError()) { + return input.error(certResult); + } + additionalCertSha256Digests = certResult.getResult(); + } + + final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; + certSha256Digests[0] = certSha256Digest; + System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, + 1, additionalCertSha256Digests.length); + + return input.success(pkg.addUsesStaticLibrary(lname, version, certSha256Digests)); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parseUsesLibrary(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString(R.styleable.AndroidManifestUsesLibrary_name); + boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesLibrary_required, true); + + if (lname != null) { + lname = lname.intern(); + if (req) { + // Upgrade to treat as stronger constraint + pkg.addUsesLibrary(lname) + .removeUsesOptionalLibrary(lname); + } else { + // Ignore if someone already defined as required + if (!ArrayUtils.contains(pkg.getUsesLibraries(), lname)) { + pkg.addUsesOptionalLibrary(lname); + } + } + } + + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parseUsesNativeLibrary(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesNativeLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesNativeLibrary_name); + boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesNativeLibrary_required, + true); + + if (lname != null) { + if (req) { + // Upgrade to treat as stronger constraint + pkg.addUsesNativeLibrary(lname) + .removeUsesOptionalNativeLibrary(lname); + } else { + // Ignore if someone already defined as required + if (!ArrayUtils.contains(pkg.getUsesNativeLibraries(), lname)) { + pkg.addUsesOptionalNativeLibrary(lname); + } + } + } + + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + @NonNull + private static ParseResult parseProcesses(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser, String[] separateProcesses, int flags) + throws IOException, XmlPullParserException { + ParseResult> result = + ParsedProcessUtils.parseProcesses(separateProcesses, pkg, res, parser, flags, + input); + if (result.isError()) { + return input.error(result); + } + + return input.success(pkg.setProcesses(result.getResult())); + } + + @NonNull + private static ParseResult parseProfileable(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProfileable); + try { + ParsingPackage newPkg = pkg.setProfileableByShell(pkg.isProfileableByShell() + || bool(false, R.styleable.AndroidManifestProfileable_shell, sa)); + return input.success(newPkg.setProfileable(newPkg.isProfileable() + && bool(true, R.styleable.AndroidManifestProfileable_enabled, sa))); + } finally { + sa.recycle(); + } + } + + private static ParseResult parseAdditionalCertificates(ParseInput input, + Resources resources, XmlResourceParser parser) + throws XmlPullParserException, IOException { + String[] certSha256Digests = EmptyArray.STRING; + final int depth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > depth)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final String nodeName = parser.getName(); + if (nodeName.equals("additional-certificate")) { + TypedArray sa = resources.obtainAttributes(parser, + R.styleable.AndroidManifestAdditionalCertificate); + try { + String certSha256Digest = sa.getNonResourceString( + R.styleable.AndroidManifestAdditionalCertificate_certDigest); + + if (TextUtils.isEmpty(certSha256Digest)) { + return input.error("Bad additional-certificate declaration with empty" + + " certDigest:" + certSha256Digest); + } + + + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + certSha256Digests = ArrayUtils.appendElement(String.class, + certSha256Digests, certSha256Digest); + } finally { + sa.recycle(); + } + } + } + + return input.success(certSha256Digests); + } + + /** + * Generate activity object that forwards user to App Details page automatically. + * This activity should be invisible to user and user should not know or see it. + */ + @NonNull + private static ParseResult generateAppDetailsHiddenActivity(ParseInput input, + ParsingPackage pkg) { + String packageName = pkg.getPackageName(); + ParseResult result = ComponentParseUtils.buildTaskAffinityName( + packageName, packageName, ":app_details", input); + if (result.isError()) { + return input.error(result); + } + + String taskAffinity = result.getResult(); + + // Build custom App Details activity info instead of parsing it from xml + return input.success(ParsedActivityImpl.makeAppDetailsActivity(packageName, + pkg.getProcessName(), pkg.getUiOptions(), taskAffinity, + pkg.isHardwareAccelerated())); + } + + /** + * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI + * + * This is distinct from any of the functionality of app links domain verification, and cannot + * be converted to remain backwards compatible. It's possible the presence of this flag does + * not indicate a valid package for domain verification. + */ + private static boolean hasDomainURLs(ParsingPackage pkg) { + final List activities = pkg.getActivities(); + final int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + List filters = activity.getIntents(); + final int filtersSize = filters.size(); + for (int filtersIndex = 0; filtersIndex < filtersSize; filtersIndex++) { + IntentFilter aii = filters.get(filtersIndex).getIntentFilter(); + if (!aii.hasAction(Intent.ACTION_VIEW)) continue; + if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; + if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || + aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { + return true; + } + } + } + return false; + } + + /** + * Sets the max aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private static void setMaxAspectRatio(ParsingPackage pkg) { + // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. + // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. + float maxAspectRatio = pkg.getTargetSdkVersion() < O ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; + + float packageMaxAspectRatio = pkg.getMaxAspectRatio(); + if (packageMaxAspectRatio != 0) { + // Use the application max aspect ration as default if set. + maxAspectRatio = packageMaxAspectRatio; + } else { + Bundle appMetaData = pkg.getMetaData(); + if (appMetaData != null && appMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) { + maxAspectRatio = appMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio); + } + } + + List activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + // If the max aspect ratio for the activity has already been set, skip. + if (activity.getMaxAspectRatio() != ASPECT_RATIO_NOT_SET) { + continue; + } + + // By default we prefer to use a values defined on the activity directly than values + // defined on the application. We do not check the styled attributes on the activity + // as it would have already been set when we processed the activity. We wait to + // process the meta data here since this method is called at the end of processing + // the application and all meta data is guaranteed. + final float activityAspectRatio = activity.getMetaData() + .getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio); + + ComponentMutateUtils.setMaxAspectRatio(activity, activity.getResizeMode(), + activityAspectRatio); + } + } + + /** + * Sets the min aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private void setMinAspectRatio(ParsingPackage pkg) { + // Use the application max aspect ration as default if set. + final float minAspectRatio = pkg.getMinAspectRatio(); + + List activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + if (activity.getMinAspectRatio() == ASPECT_RATIO_NOT_SET) { + ComponentMutateUtils.setMinAspectRatio(activity, activity.getResizeMode(), + minAspectRatio); + } + } + } + + private void setSupportsSizeChanges(ParsingPackage pkg) { + final Bundle appMetaData = pkg.getMetaData(); + final boolean supportsSizeChanges = appMetaData != null + && appMetaData.getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false); + + List activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + if (supportsSizeChanges || activity.getMetaData() + .getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false)) { + ComponentMutateUtils.setSupportsSizeChanges(activity, true); + } + } + } + + private static ParseResult parseOverlay(ParseInput input, ParsingPackage pkg, + Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay); + try { + String target = sa.getString(R.styleable.AndroidManifestResourceOverlay_targetPackage); + int priority = anInt(0, R.styleable.AndroidManifestResourceOverlay_priority, sa); + + if (target == null) { + return input.error(" does not specify a target package"); + } else if (priority < 0 || priority > 9999) { + return input.error(" priority must be between 0 and 9999"); + } + + // check to see if overlay should be excluded based on system property condition + String propName = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName); + String propValue = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue); + if (!FrameworkParsingPackageUtils.checkRequiredSystemProperties(propName, propValue)) { + String message = "Skipping target and overlay pair " + target + " and " + + pkg.getBaseApkPath() + + ": overlay ignored due to required system property: " + + propName + " with value: " + propValue; + Slog.i(TAG, message); + return input.skip(message); + } + + return input.success(pkg.setResourceOverlay(true) + .setOverlayTarget(target) + .setOverlayPriority(priority) + .setOverlayTargetOverlayableName( + sa.getString(R.styleable.AndroidManifestResourceOverlay_targetName)) + .setOverlayCategory( + sa.getString(R.styleable.AndroidManifestResourceOverlay_category)) + .setOverlayIsStatic( + bool(false, R.styleable.AndroidManifestResourceOverlay_isStatic, sa))); + } finally { + sa.recycle(); + } + } + + private static ParseResult parseProtectedBroadcast(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProtectedBroadcast); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = nonResString(R.styleable.AndroidManifestProtectedBroadcast_name, sa); + if (name != null) { + pkg.addProtectedBroadcast(name); + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static ParseResult parseSupportScreens(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSupportsScreens); + try { + int requiresSmallestWidthDp = anInt(0, + R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, sa); + int compatibleWidthLimitDp = anInt(0, + R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, sa); + int largestWidthLimitDp = anInt(0, + R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, sa); + + // This is a trick to get a boolean and still able to detect + // if a value was actually set. + return input.success(pkg + .setSmallScreensSupported( + anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa)) + .setNormalScreensSupported( + anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa)) + .setLargeScreensSupported( + anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa)) + .setExtraLargeScreensSupported( + anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa)) + .setResizeable( + anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa)) + .setAnyDensity( + anInt(1, R.styleable.AndroidManifestSupportsScreens_anyDensity, sa)) + .setRequiresSmallestWidthDp(requiresSmallestWidthDp) + .setCompatibleWidthLimitDp(compatibleWidthLimitDp) + .setLargestWidthLimitDp(largestWidthLimitDp)); + } finally { + sa.recycle(); + } + } + + private static ParseResult parseInstrumentation(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) + throws XmlPullParserException, IOException { + ParseResult result = ParsedInstrumentationUtils.parseInstrumentation( + pkg, res, parser, sUseRoundIcon, input); + if (result.isError()) { + return input.error(result); + } + return input.success(pkg.addInstrumentation(result.getResult())); + } + + private static ParseResult parseOriginalPackage(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage); + try { + String orig = sa.getNonConfigurationString( + R.styleable.AndroidManifestOriginalPackage_name, + 0); + if (!pkg.getPackageName().equals(orig)) { + pkg.addOriginalPackage(orig); + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static ParseResult parseAdoptPermissions(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage); + try { + String name = nonConfigString(0, R.styleable.AndroidManifestOriginalPackage_name, sa); + if (name != null) { + pkg.addAdoptPermission(name); + } + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + private static void convertCompatPermissions(ParsingPackage pkg) { + for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) { + final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i]; + if (pkg.getTargetSdkVersion() >= info.getSdkVersion()) { + break; + } + if (!pkg.getRequestedPermissions().contains(info.getName())) { + pkg.addImplicitPermission(info.getName()); + } + } + } + + private void convertSplitPermissions(ParsingPackage pkg) { + final int listSize = mSplitPermissionInfos.size(); + for (int is = 0; is < listSize; is++) { + final PermissionManager.SplitPermissionInfo spi = mSplitPermissionInfos.get(is); + Set requestedPermissions = pkg.getRequestedPermissions(); + if (pkg.getTargetSdkVersion() >= spi.getTargetSdk() + || !requestedPermissions.contains(spi.getSplitPermission())) { + continue; + } + final List newPerms = spi.getNewPermissions(); + for (int in = 0; in < newPerms.size(); in++) { + final String perm = newPerms.get(in); + if (!requestedPermissions.contains(perm)) { + pkg.addImplicitPermission(perm); + } + } + } + } + + /** + * This is a pre-density application which will get scaled - instead of being pixel perfect. + * This type of application is not resizable. + * + * @param pkg The package which needs to be marked as unresizable. + */ + private static void adjustPackageToBeUnresizeableAndUnpipable(ParsingPackage pkg) { + List activities = pkg.getActivities(); + int activitiesSize = activities.size(); + for (int index = 0; index < activitiesSize; index++) { + ParsedActivity activity = activities.get(index); + ComponentMutateUtils.setResizeMode(activity, RESIZE_MODE_UNRESIZEABLE); + ComponentMutateUtils.setExactFlags(activity, + activity.getFlags() & ~FLAG_SUPPORTS_PICTURE_IN_PICTURE); + } + } + + /** + * Parse a meta data defined on the enclosing tag. + *

Meta data can be defined by either <meta-data> or <property> elements. + */ + public static ParseResult parseMetaData(ParsingPackage pkg, ParsedComponent component, + Resources res, XmlResourceParser parser, String tagName, ParseInput input) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestMetaData); + try { + final Property property; + final String name = TextUtils.safeIntern( + nonConfigString(0, R.styleable.AndroidManifestMetaData_name, sa)); + if (name == null) { + return input.error(tagName + " requires an android:name attribute"); + } + + final String packageName = pkg.getPackageName(); + final String className = component != null ? component.getName() : null; + TypedValue v = sa.peekValue(R.styleable.AndroidManifestMetaData_resource); + if (v != null && v.resourceId != 0) { + property = new Property(name, v.resourceId, true, packageName, className); + } else { + v = sa.peekValue(R.styleable.AndroidManifestMetaData_value); + if (v != null) { + if (v.type == TypedValue.TYPE_STRING) { + final CharSequence cs = v.coerceToString(); + final String stringValue = cs != null ? cs.toString() : null; + property = new Property(name, stringValue, packageName, className); + } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { + property = new Property(name, v.data != 0, packageName, className); + } else if (v.type >= TypedValue.TYPE_FIRST_INT + && v.type <= TypedValue.TYPE_LAST_INT) { + property = new Property(name, v.data, false, packageName, className); + } else if (v.type == TypedValue.TYPE_FLOAT) { + property = new Property(name, v.getFloat(), packageName, className); + } else { + if (!RIGID_PARSER) { + Slog.w(TAG, + tagName + " only supports string, integer, float, color, " + + "boolean, and resource reference types: " + + parser.getName() + " at " + + pkg.getBaseApkPath() + " " + + parser.getPositionDescription()); + property = null; + } else { + return input.error(tagName + " only supports string, integer, float, " + + "color, boolean, and resource reference types"); + } + } + } else { + return input.error(tagName + " requires an android:value " + + "or android:resource attribute"); + } + } + return input.success(property); + } finally { + sa.recycle(); + } + } + + /** + * Collect certificates from all the APKs described in the given package. Also asserts that + * all APK contents are signed correctly and consistently. + * + * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse + * call if requested. Leaving this as an optional method for the caller means we have to + * construct a placeholder ParseInput. + */ + @CheckResult + public static ParseResult getSigningDetails(ParseInput input, + ParsedPackage pkg, boolean skipVerify) { + return getSigningDetails(input, pkg.getBaseApkPath(), pkg.isStaticSharedLibrary(), + pkg.getTargetSdkVersion(), pkg.getSplitCodePaths(), skipVerify); + } + + @CheckResult + private static ParseResult getSigningDetails(ParseInput input, + ParsingPackage pkg, boolean skipVerify) { + return getSigningDetails(input, pkg.getBaseApkPath(), pkg.isStaticSharedLibrary(), + pkg.getTargetSdkVersion(), pkg.getSplitCodePaths(), skipVerify); + } + + /** + * Collect certificates from all the APKs described in the given package. Also asserts that + * all APK contents are signed correctly and consistently. + * + * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse + * call if requested. Leaving this as an optional method for the caller means we have to + * construct a dummy ParseInput. + */ + @CheckResult + public static ParseResult getSigningDetails(ParseInput input, + String baseApkPath, boolean isStaticSharedLibrary, int targetSdkVersion, + String[] splitCodePaths, boolean skipVerify) { + SigningDetails signingDetails = SigningDetails.UNKNOWN; + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); + try { + ParseResult result = getSigningDetails( + input, + baseApkPath, + skipVerify, + isStaticSharedLibrary, + signingDetails, + targetSdkVersion + ); + if (result.isError()) { + return input.error(result); + } + + signingDetails = result.getResult(); + final File frameworkRes = new File(Environment.getRootDirectory(), + "framework/framework-res.apk"); + boolean isFrameworkResSplit = frameworkRes.getAbsolutePath() + .equals(baseApkPath); + if (!ArrayUtils.isEmpty(splitCodePaths) && !isFrameworkResSplit) { + for (int i = 0; i < splitCodePaths.length; i++) { + result = getSigningDetails( + input, + splitCodePaths[i], + skipVerify, + isStaticSharedLibrary, + signingDetails, + targetSdkVersion + ); + if (result.isError()) { + return input.error(result); + } + } + } + return result; + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + @CheckResult + public static ParseResult getSigningDetails(ParseInput input, + String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary, + @NonNull SigningDetails existingSigningDetails, int targetSdk) { + int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( + targetSdk); + if (isStaticSharedLibrary) { + // must use v2 signing scheme + minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; + } + final ParseResult verified; + if (skipVerify) { + // systemDir APKs are already trusted, save time by not verifying + verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(input, baseCodePath, + minSignatureScheme); + } else { + verified = ApkSignatureVerifier.verify(input, baseCodePath, minSignatureScheme); + } + + if (verified.isError()) { + return input.error(verified); + } + + // Verify that entries are signed consistently with the first pkg + // we encountered. Note that for splits, certificates may have + // already been populated during an earlier parse of a base APK. + if (existingSigningDetails == SigningDetails.UNKNOWN) { + return verified; + } else { + if (!Signature.areExactMatch(existingSigningDetails, verified.getResult())) { + return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, + baseCodePath + " has mismatched certificates"); + } + + return input.success(existingSigningDetails); + } + } + + /** + * @hide + */ + public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { + sCompatibilityModeEnabled = compatibilityModeEnabled; + } + + /** + * @hide + */ + public static void readConfigUseRoundIcon(Resources r) { + if (r != null) { + sUseRoundIcon = r.getBoolean(com.android.internal.R.bool.config_useRoundIcon); + return; + } + + final ApplicationInfo androidAppInfo; + try { + androidAppInfo = ActivityThread.getPackageManager().getApplicationInfo( + "android", 0 /* flags */, + UserHandle.myUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + final Resources systemResources = Resources.getSystem(); + + // Create in-flight as this overlayable resource is only used when config changes + final Resources overlayableRes = ResourcesManager.getInstance().getResources( + null /* activityToken */, + null /* resDir */, + null /* splitResDirs */, + androidAppInfo.resourceDirs, + androidAppInfo.overlayPaths, + androidAppInfo.sharedLibraryFiles, + null /* overrideDisplayId */, + null /* overrideConfig */, + systemResources.getCompatibilityInfo(), + systemResources.getClassLoader(), + null /* loaders */); + + sUseRoundIcon = overlayableRes.getBoolean(com.android.internal.R.bool.config_useRoundIcon); + } + + /* + The following set of methods makes code easier to read by re-ordering the TypedArray methods. + + The first parameter is the default, which is the most important to understand for someone + reading through the parsing code. + + That's followed by the attribute name, which is usually irrelevant during reading because + it'll look like setSomeValue(true, R.styleable.ReallyLongParentName_SomeValueAttr... and + the "setSomeValue" part is enough to communicate what the line does. + + Last comes the TypedArray, which is by far the least important since each try-with-resources + should only have 1. + */ + + // Note there is no variant of bool without a defaultValue parameter, since explicit true/false + // is important to specify when adding an attribute. + private static boolean bool(boolean defaultValue, @StyleableRes int attribute, TypedArray sa) { + return sa.getBoolean(attribute, defaultValue); + } + + private static float aFloat(float defaultValue, @StyleableRes int attribute, TypedArray sa) { + return sa.getFloat(attribute, defaultValue); + } + + private static float aFloat(@StyleableRes int attribute, TypedArray sa) { + return sa.getFloat(attribute, 0f); + } + + private static int anInt(int defaultValue, @StyleableRes int attribute, TypedArray sa) { + return sa.getInt(attribute, defaultValue); + } + + private static int anInteger(int defaultValue, @StyleableRes int attribute, TypedArray sa) { + return sa.getInteger(attribute, defaultValue); + } + + private static int anInt(@StyleableRes int attribute, TypedArray sa) { + return sa.getInt(attribute, 0); + } + + @AnyRes + private static int resId(@StyleableRes int attribute, TypedArray sa) { + return sa.getResourceId(attribute, 0); + } + + private static String string(@StyleableRes int attribute, TypedArray sa) { + return sa.getString(attribute); + } + + private static String nonConfigString(int allowedChangingConfigs, @StyleableRes int attribute, + TypedArray sa) { + return sa.getNonConfigurationString(attribute, allowedChangingConfigs); + } + + private static String nonResString(@StyleableRes int index, TypedArray sa) { + return sa.getNonResourceString(index); + } + + /** + * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. + */ + public static void writeKeySetMapping(@NonNull Parcel dest, + @NonNull Map> keySetMapping) { + if (keySetMapping == null) { + dest.writeInt(-1); + return; + } + + final int N = keySetMapping.size(); + dest.writeInt(N); + + for (String key : keySetMapping.keySet()) { + dest.writeString(key); + ArraySet keys = keySetMapping.get(key); + if (keys == null) { + dest.writeInt(-1); + continue; + } + + final int M = keys.size(); + dest.writeInt(M); + for (int j = 0; j < M; j++) { + dest.writeSerializable(keys.valueAt(j)); + } + } + } + + /** + * Reads a keyset mapping from the given parcel at the given data position. May return + * {@code null} if the serialized mapping was {@code null}. + */ + @NonNull + public static ArrayMap> readKeySetMapping(@NonNull Parcel in) { + final int N = in.readInt(); + if (N == -1) { + return null; + } + + ArrayMap> keySetMapping = new ArrayMap<>(); + for (int i = 0; i < N; ++i) { + String key = in.readString(); + final int M = in.readInt(); + if (M == -1) { + keySetMapping.put(key, null); + continue; + } + + ArraySet keys = new ArraySet<>(M); + for (int j = 0; j < M; ++j) { + PublicKey pk = (PublicKey) in.readSerializable(java.security.PublicKey.class.getClassLoader(), java.security.PublicKey.class); + keys.add(pk); + } + + keySetMapping.put(key, keys); + } + + return keySetMapping; + } + + /** + * Callback interface for retrieving information that may be needed while parsing + * a package. + */ + public interface Callback { + boolean hasFeature(String feature); + + ParsingPackage startParsingPackage(@NonNull String packageName, + @NonNull String baseApkPath, @NonNull String path, + @NonNull TypedArray manifestArray, boolean isCoreApp); + + @NonNull Set getHiddenApiWhitelistedApps(); + + @NonNull Set getInstallConstraintsAllowlist(); + } +} diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java new file mode 100644 index 000000000000..26822c649db7 --- /dev/null +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.pm.pkg.parsing; + +import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Pair; +import android.util.Slog; + +import com.android.internal.pm.pkg.component.ParsedIntentInfo; +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl; +import com.android.internal.util.Parcelling; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** @hide **/ +public class ParsingUtils { + + public static final String TAG = "PackageParsing"; + + public static final String ANDROID_RES_NAMESPACE = "http://schemas.android.com/apk/res/android"; + + public static final int DEFAULT_MIN_SDK_VERSION = 1; + public static final int DEFAULT_MAX_SDK_VERSION = Integer.MAX_VALUE; + public static final int DEFAULT_TARGET_SDK_VERSION = 0; + + public static final int NOT_SET = -1; + + @Nullable + public static String buildClassName(String pkg, CharSequence clsSeq) { + if (clsSeq == null || clsSeq.length() <= 0) { + return null; + } + String cls = clsSeq.toString(); + char c = cls.charAt(0); + if (c == '.') { + return pkg + cls; + } + if (cls.indexOf('.') < 0) { + StringBuilder b = new StringBuilder(pkg); + b.append('.'); + b.append(cls); + return b.toString(); + } + return cls; + } + + @NonNull + public static ParseResult unknownTag(String parentTag, ParsingPackage pkg, + XmlResourceParser parser, ParseInput input) throws IOException, XmlPullParserException { + if (RIGID_PARSER) { + return input.error("Bad element under " + parentTag + ": " + parser.getName()); + } + Slog.w(TAG, "Unknown element under " + parentTag + ": " + + parser.getName() + " at " + pkg.getBaseApkPath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + return input.success(null); // Type doesn't matter + } + + /** + * Use with {@link Parcel#writeTypedList(List)} or + * {@link #writeInterfaceAsImplList(Parcel, List)} + * + * @see Parcel#createTypedArrayList(Parcelable.Creator) + */ + @NonNull + public static List createTypedInterfaceList( + @NonNull Parcel parcel, @NonNull Parcelable.Creator creator) { + int size = parcel.readInt(); + if (size < 0) { + return new ArrayList<>(); + } + ArrayList list = new ArrayList(size); + while (size > 0) { + list.add(parcel.readTypedObject(creator)); + size--; + } + return list; + } + + /** + * Use with {@link #createTypedInterfaceList(Parcel, Parcelable.Creator)}. + * + * Writes a list that can be cast as Parcelable types at runtime. + * TODO: Remove with ImmutableList multi-casting support + * + * @see Parcel#writeTypedList(List) + */ + @NonNull + public static void writeParcelableList(@NonNull Parcel parcel, List list) { + if (list == null) { + parcel.writeInt(-1); + return; + } + int size = list.size(); + int index = 0; + parcel.writeInt(size); + while (index < size) { + parcel.writeTypedObject((Parcelable) list.get(index), 0); + index++; + } + } + + public static class StringPairListParceler implements + Parcelling>> { + + @Override + public void parcel(List> item, Parcel dest, + int parcelFlags) { + if (item == null) { + dest.writeInt(-1); + return; + } + + final int size = item.size(); + dest.writeInt(size); + + for (int index = 0; index < size; index++) { + Pair pair = item.get(index); + dest.writeString(pair.first); + dest.writeParcelable((Parcelable) pair.second, parcelFlags); + } + } + + @Override + public List> unparcel(Parcel source) { + int size = source.readInt(); + if (size == -1) { + return null; + } + + if (size == 0) { + return new ArrayList<>(0); + } + + final List> list = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + list.add(Pair.create(source.readString(), source.readParcelable( + ParsedIntentInfoImpl.class.getClassLoader(), ParsedIntentInfo.class))); + } + + return list; + } + } + + /** + * Parse the {@link android.R.attr#knownActivityEmbeddingCerts} attribute, if available. + */ + @NonNull + public static ParseResult> parseKnownActivityEmbeddingCerts(@NonNull TypedArray sa, + @NonNull Resources res, int resourceId, @NonNull ParseInput input) { + if (!sa.hasValue(resourceId)) { + return input.success(null); + } + + final int knownActivityEmbeddingCertsResource = sa.getResourceId(resourceId, 0); + if (knownActivityEmbeddingCertsResource != 0) { + // The knownCerts attribute supports both a string array resource as well as a + // string resource for the case where the permission should only be granted to a + // single known signer. + Set knownEmbeddingCertificates = null; + final String resourceType = res.getResourceTypeName( + knownActivityEmbeddingCertsResource); + if (resourceType.equals("array")) { + final String[] knownCerts = res.getStringArray(knownActivityEmbeddingCertsResource); + if (knownCerts != null) { + knownEmbeddingCertificates = Set.of(knownCerts); + } + } else { + final String knownCert = res.getString(knownActivityEmbeddingCertsResource); + if (knownCert != null) { + knownEmbeddingCertificates = Set.of(knownCert); + } + } + if (knownEmbeddingCertificates == null || knownEmbeddingCertificates.isEmpty()) { + return input.error("Defined a knownActivityEmbeddingCerts attribute but the " + + "provided resource is null"); + } + return input.success(knownEmbeddingCertificates); + } + + // If the knownCerts resource ID is null - the app specified a string value for the + // attribute representing a single trusted signer. + final String knownCert = sa.getString(resourceId); + if (knownCert == null || knownCert.isEmpty()) { + return input.error("Defined a knownActivityEmbeddingCerts attribute but the provided " + + "string is empty"); + } + return input.success(Set.of(knownCert)); + } +} diff --git a/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java new file mode 100644 index 000000000000..50c62437b192 --- /dev/null +++ b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 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.pm.split; + +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.res.ApkAssets; +import android.content.res.AssetManager; +import android.os.Build; + +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags; +import com.android.internal.util.ArrayUtils; + +import libcore.io.IoUtils; + +import java.io.IOException; + +/** + * Loads the base and split APKs into a single AssetManager. + * @hide + */ +public class DefaultSplitAssetLoader implements SplitAssetLoader { + private final String mBaseApkPath; + private final String[] mSplitApkPaths; + private final @ParseFlags int mFlags; + private AssetManager mCachedAssetManager; + + private ApkAssets mBaseApkAssets; + + public DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags) { + mBaseApkPath = pkg.getBaseApkPath(); + mSplitApkPaths = pkg.getSplitApkPaths(); + mFlags = flags; + } + + private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) + throws IllegalArgumentException { + if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0 + && !ApkLiteParseUtils.isApkPath(path)) { + throw new IllegalArgumentException("Invalid package file: " + path); + } + + try { + return ApkAssets.loadFromPath(path); + } catch (IOException e) { + throw new IllegalArgumentException("Failed to load APK at path " + path, e); + } + } + + @Override + public AssetManager getBaseAssetManager() throws IllegalArgumentException { + if (mCachedAssetManager != null) { + return mCachedAssetManager; + } + + ApkAssets[] apkAssets = new ApkAssets[(mSplitApkPaths != null + ? mSplitApkPaths.length : 0) + 1]; + + // Load the base. + int splitIdx = 0; + apkAssets[splitIdx++] = mBaseApkAssets = loadApkAssets(mBaseApkPath, mFlags); + + // Load any splits. + if (!ArrayUtils.isEmpty(mSplitApkPaths)) { + for (String apkPath : mSplitApkPaths) { + apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags); + } + } + + AssetManager assets = new AssetManager(); + assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, Build.VERSION.RESOURCES_SDK_INT); + assets.setApkAssets(apkAssets, false /*invalidateCaches*/); + + mCachedAssetManager = assets; + return mCachedAssetManager; + } + + @Override + public AssetManager getSplitAssetManager(int splitIdx) throws IllegalArgumentException { + return getBaseAssetManager(); + } + + @Override + public ApkAssets getBaseApkAssets() { + return mBaseApkAssets; + } + + @Override + public void close() throws Exception { + IoUtils.closeQuietly(mCachedAssetManager); + } +} diff --git a/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java new file mode 100644 index 000000000000..c166cdcf9451 --- /dev/null +++ b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 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.pm.split; + +import android.annotation.NonNull; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.split.SplitDependencyLoader; +import android.content.res.ApkAssets; +import android.content.res.AssetManager; +import android.os.Build; +import android.util.SparseArray; + +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags; + +import libcore.io.IoUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; + +/** + * Loads AssetManagers for splits and their dependencies. This SplitAssetLoader implementation + * is to be used when an application opts-in to isolated split loading. + * @hide + */ +public class SplitAssetDependencyLoader extends SplitDependencyLoader + implements SplitAssetLoader { + private final String[] mSplitPaths; + private final @ParseFlags int mFlags; + private final ApkAssets[][] mCachedSplitApks; + private final AssetManager[] mCachedAssetManagers; + + public SplitAssetDependencyLoader(PackageLite pkg, + SparseArray dependencies, @ParseFlags int flags) { + super(dependencies); + + // The base is inserted into index 0, so we need to shift all the splits by 1. + mSplitPaths = new String[pkg.getSplitApkPaths().length + 1]; + mSplitPaths[0] = pkg.getBaseApkPath(); + System.arraycopy(pkg.getSplitApkPaths(), 0, mSplitPaths, 1, pkg.getSplitApkPaths().length); + + mFlags = flags; + mCachedSplitApks = new ApkAssets[mSplitPaths.length][]; + mCachedAssetManagers = new AssetManager[mSplitPaths.length]; + } + + @Override + protected boolean isSplitCached(int splitIdx) { + return mCachedAssetManagers[splitIdx] != null; + } + + private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) + throws IllegalArgumentException { + if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0 + && !ApkLiteParseUtils.isApkPath(path)) { + throw new IllegalArgumentException("Invalid package file: " + path); + } + + try { + return ApkAssets.loadFromPath(path); + } catch (IOException e) { + throw new IllegalArgumentException("Failed to load APK at path " + path, e); + } + } + + private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) { + final AssetManager assets = new AssetManager(); + assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, Build.VERSION.RESOURCES_SDK_INT); + assets.setApkAssets(apkAssets, false /*invalidateCaches*/); + return assets; + } + + @Override + protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, + int parentSplitIdx) throws IllegalArgumentException { + final ArrayList assets = new ArrayList<>(); + + // Include parent ApkAssets. + if (parentSplitIdx >= 0) { + Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]); + } + + // Include this ApkAssets. + assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags)); + + // Load and include all config splits for this feature. + for (int configSplitIdx : configSplitIndices) { + assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags)); + } + + // Cache the results. + mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]); + mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets(mCachedSplitApks[splitIdx]); + } + + @Override + public AssetManager getBaseAssetManager() throws IllegalArgumentException { + loadDependenciesForSplit(0); + return mCachedAssetManagers[0]; + } + + @Override + public AssetManager getSplitAssetManager(int idx) throws IllegalArgumentException { + // Since we insert the base at position 0, and ParsingPackageUtils keeps splits separate + // from the base, we need to adjust the index. + loadDependenciesForSplit(idx + 1); + return mCachedAssetManagers[idx + 1]; + } + + @Override + public ApkAssets getBaseApkAssets() { + return mCachedSplitApks[0][0]; + } + + @Override + public void close() throws Exception { + for (AssetManager assets : mCachedAssetManagers) { + IoUtils.closeQuietly(assets); + } + } +} diff --git a/core/java/com/android/internal/pm/split/SplitAssetLoader.java b/core/java/com/android/internal/pm/split/SplitAssetLoader.java new file mode 100644 index 000000000000..c7c409d826ba --- /dev/null +++ b/core/java/com/android/internal/pm/split/SplitAssetLoader.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 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.pm.split; + +import android.content.res.ApkAssets; +import android.content.res.AssetManager; + +/** + * Simple interface for loading base Assets and Splits. Used by ParsingPackageUtils when parsing + * split APKs. + * + * @hide + */ +public interface SplitAssetLoader extends AutoCloseable { + AssetManager getBaseAssetManager() throws IllegalArgumentException; + AssetManager getSplitAssetManager(int splitIdx) throws IllegalArgumentException; + + ApkAssets getBaseApkAssets(); +} diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java index f86595f1ea7b..adb0c6959f12 100644 --- a/core/java/com/android/server/pm/pkg/AndroidPackage.java +++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java @@ -58,6 +58,7 @@ import com.android.internal.pm.pkg.component.ParsedProcess; import com.android.internal.pm.pkg.component.ParsedProvider; import com.android.internal.pm.pkg.component.ParsedService; import com.android.internal.pm.pkg.component.ParsedUsesPermission; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import java.security.PublicKey; import java.util.List; @@ -690,7 +691,7 @@ public interface AndroidPackage { /** * The names of packages to adopt ownership of permissions from, parsed under {@link - * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}. + * ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}. * * @see R.styleable#AndroidManifestOriginalPackage_name * @hide @@ -795,7 +796,7 @@ public interface AndroidPackage { /** * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link - * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}. + * ParsingPackageUtils#TAG_KEY_SETS}. * * @see R.styleable#AndroidManifestKeySet * @see R.styleable#AndroidManifestPublicKey @@ -1266,7 +1267,7 @@ public interface AndroidPackage { /** * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link - * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}. + * ParsingPackageUtils#TAG_KEY_SETS}. * * @see R.styleable#AndroidManifestUpgradeKeySet * @hide diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ac173f3b5b7a..d9dcfab5c53b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -421,6 +421,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.os.TimeoutRecord; import com.android.internal.os.TransferPipe; import com.android.internal.os.Zygote; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.policy.AttributeCache; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; @@ -468,7 +469,6 @@ import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.SELinuxUtil; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.pm.snapshot.PackageDataSnapshot; import com.android.server.power.stats.BatteryStatsImpl; import com.android.server.sdksandbox.SdkSandboxManagerLocal; diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index ec858ee296e1..f2dcba45e312 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -59,6 +59,7 @@ import android.util.apk.SourceStampVerifier; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; @@ -67,7 +68,6 @@ import com.android.server.integrity.model.IntegrityCheckResult; import com.android.server.integrity.model.RuleMetadata; import com.android.server.pm.PackageManagerServiceUtils; import com.android.server.pm.parsing.PackageParser2; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.ByteArrayInputStream; import java.io.File; diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java index 5c4447eb99a4..3b9f9c804e27 100644 --- a/services/core/java/com/android/server/pm/InitAppsHelper.java +++ b/services/core/java/com/android/server/pm/InitAppsHelper.java @@ -18,6 +18,7 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX; import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME; import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME; import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX; @@ -30,7 +31,6 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX; import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN; import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS; import static com.android.server.pm.PackageManagerService.TAG; -import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX; import android.annotation.NonNull; import android.annotation.Nullable; @@ -46,12 +46,12 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfig; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.pm.parsing.PackageCacher; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.utils.WatchedArrayMap; import java.io.File; diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 9b8ee741476e..6480d6483062 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -154,12 +154,16 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.F2fsUtils; +import com.android.internal.pm.parsing.PackageParserException; +import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.component.ComponentMutateUtils; import com.android.internal.pm.pkg.component.ParsedActivity; import com.android.internal.pm.pkg.component.ParsedInstrumentation; import com.android.internal.pm.pkg.component.ParsedIntentInfo; import com.android.internal.pm.pkg.component.ParsedPermission; import com.android.internal.pm.pkg.component.ParsedPermissionGroup; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.security.VerityUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; @@ -181,8 +185,6 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.SharedLibraryWrapper; -import com.android.server.pm.pkg.component.ComponentMutateUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.rollback.RollbackManagerInternal; import com.android.server.security.FileIntegrityService; import com.android.server.utils.WatchedArrayMap; @@ -1165,7 +1167,7 @@ final class InstallPackageHelper { parseFlags); archivedPackage = request.getPackageLite().getArchivedPackage(); } - } catch (PackageManagerException e) { + } catch (PackageManagerException | PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -3856,7 +3858,7 @@ final class InstallPackageHelper { synchronized (mPm.mLock) { platformPackage = mPm.getPlatformPackage(); - var isSystemApp = AndroidPackageUtils.isSystem(parsedPackage); + var isSystemApp = AndroidPackageLegacyUtils.isSystem(parsedPackage); final String renamedPkgName = mPm.mSettings.getRenamedPackageLPr( AndroidPackageUtils.getRealPackageOrNull(parsedPackage, isSystemApp)); realPkgName = ScanPackageUtils.getRealPackageName(parsedPackage, renamedPkgName, @@ -4574,7 +4576,7 @@ final class InstallPackageHelper { private void assertPackageWithSharedUserIdIsPrivileged(AndroidPackage pkg) throws PackageManagerException { - if (!AndroidPackageUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) { + if (!AndroidPackageLegacyUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) { SharedUserSetting sharedUserSetting = null; try { synchronized (mPm.mLock) { @@ -4612,7 +4614,7 @@ final class InstallPackageHelper { final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0) && ScanPackageUtils.getVendorPartitionVersion() < 28; if (((scanFlags & SCAN_AS_PRIVILEGED) == 0) - && !AndroidPackageUtils.isPrivileged(pkg) + && !AndroidPackageLegacyUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null) && !skipVendorPrivilegeScan) { SharedUserSetting sharedUserSetting = null; diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index 5494bd9808c8..9a51cc0e26ba 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -51,12 +51,12 @@ import android.util.ExceptionUtils; import android.util.Slog; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.util.ArrayUtils; import com.android.server.art.model.DexoptResult; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; import com.android.server.pm.pkg.PackageStateInternal; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 47d1df5df1c0..4adb60c34c52 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -168,6 +168,7 @@ import com.android.internal.content.InstallLocationUtils; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.os.SomeArgs; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.security.VerityUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; @@ -181,7 +182,6 @@ import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import libcore.io.IoUtils; import libcore.util.EmptyArray; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c5b006c4c77d..84d47549cf9b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -185,6 +185,7 @@ import com.android.internal.pm.parsing.pkg.AndroidPackageInternal; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.internal.pm.pkg.component.ParsedInstrumentation; import com.android.internal.pm.pkg.component.ParsedMainComponent; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; @@ -238,7 +239,6 @@ import com.android.server.pm.pkg.SharedUserApi; import com.android.server.pm.pkg.mutate.PackageStateMutator; import com.android.server.pm.pkg.mutate.PackageStateWrite; import com.android.server.pm.pkg.mutate.PackageUserStateWrite; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.pm.resolution.ComponentResolver; import com.android.server.pm.resolution.ComponentResolverApi; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; @@ -2013,6 +2013,16 @@ public class PackageManagerService implements PackageSender, TestUtilityService public boolean hasFeature(String feature) { return PackageManagerService.this.hasSystemFeature(feature, 0); } + + @Override + public Set getHiddenApiWhitelistedApps() { + return SystemConfig.getInstance().getHiddenApiWhitelistedApps(); + } + + @Override + public Set getInstallConstraintsAllowlist() { + return SystemConfig.getInstance().getInstallConstraintsAllowlist(); + } }; // CHECKSTYLE:ON IndentationCheck diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java index bb0017c80d6d..981f24bc179a 100644 --- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java +++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java @@ -31,8 +31,8 @@ import android.util.ArrayMap; import android.util.Log; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.utils.WatchedLongSparseArray; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java index 109d7ba1d29e..8ff4a6dd9440 100644 --- a/services/core/java/com/android/server/pm/RemovePackageHelper.java +++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java @@ -44,12 +44,12 @@ import android.util.Slog; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.pkg.component.ParsedInstrumentation; import com.android.internal.util.ArrayUtils; import com.android.server.pm.Installer.LegacyDexoptDisabledException; import com.android.server.pm.parsing.PackageCacher; -import com.android.server.pm.parsing.pkg.AndroidPackageUtils; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; @@ -167,7 +167,7 @@ final class RemovePackageHelper { if (removedPackage != null) { // TODO: Use PackageState for isSystem cleanPackageDataStructuresLILPw(removedPackage, - AndroidPackageUtils.isSystem(removedPackage), chatty); + AndroidPackageLegacyUtils.isSystem(removedPackage), chatty); } } } diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java index 31a63e07b66c..5c6d61e3eaf9 100644 --- a/services/core/java/com/android/server/pm/ScanPackageUtils.java +++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java @@ -74,11 +74,13 @@ import android.util.jar.StrictJarFile; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.component.ComponentMutateUtils; import com.android.internal.pm.pkg.component.ParsedActivity; import com.android.internal.pm.pkg.component.ParsedMainComponent; import com.android.internal.pm.pkg.component.ParsedProcess; import com.android.internal.pm.pkg.component.ParsedProvider; import com.android.internal.pm.pkg.component.ParsedService; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.util.ArrayUtils; import com.android.server.SystemConfig; import com.android.server.pm.parsing.PackageInfoUtils; @@ -86,8 +88,6 @@ import com.android.server.pm.parsing.library.PackageBackwardCompatibility; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateUtils; -import com.android.server.pm.pkg.component.ComponentMutateUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.utils.WatchedArraySet; import dalvik.system.VMRuntime; diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java index 37cf30bd63fe..41e2a3f3d318 100644 --- a/services/core/java/com/android/server/pm/ScanRequest.java +++ b/services/core/java/com/android/server/pm/ScanRequest.java @@ -22,8 +22,8 @@ import android.os.UserHandle; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; /** A package to be scanned */ @VisibleForTesting diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 75d88da059b5..cfbaae3d0f30 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -89,6 +89,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.pkg.component.ParsedComponent; import com.android.internal.pm.pkg.component.ParsedIntentInfo; import com.android.internal.pm.pkg.component.ParsedPermission; @@ -106,7 +107,6 @@ import com.android.server.LocalServices; import com.android.server.backup.PreferredActivityBackupHelper; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.parsing.PackageInfoUtils; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.permission.LegacyPermissionSettings; import com.android.server.pm.permission.LegacyPermissionState; diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index dddc6b0fbb7a..5c0a15a28285 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -25,14 +25,14 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; +import com.android.internal.pm.pkg.component.ComponentMutateUtils; import com.android.internal.pm.pkg.component.ParsedProcess; +import com.android.internal.pm.pkg.component.ParsedProcessImpl; import com.android.internal.util.ArrayUtils; import com.android.server.pm.permission.LegacyPermissionState; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.SharedUserApi; -import com.android.server.pm.pkg.component.ComponentMutateUtils; -import com.android.server.pm.pkg.component.ParsedProcessImpl; import com.android.server.utils.SnapshotCache; import com.android.server.utils.Watchable; import com.android.server.utils.WatchedArraySet; diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java index b607502baada..7d87d1b27da0 100644 --- a/services/core/java/com/android/server/pm/StorageEventHelper.java +++ b/services/core/java/com/android/server/pm/StorageEventHelper.java @@ -47,11 +47,11 @@ import android.util.Log; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.policy.AttributeCache; import com.android.internal.util.IndentingPrintWriter; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java index 459e2cf7f5c0..79c9c8ec8b0b 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java +++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java @@ -28,9 +28,9 @@ import android.system.StructStat; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.ApexManager; -import com.android.server.pm.parsing.pkg.PackageImpl; import libcore.io.IoUtils; diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java index b23dbee5e973..fa54f0ba18cd 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -52,6 +52,9 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils; +import com.android.internal.pm.parsing.pkg.PackageImpl; +import com.android.internal.pm.pkg.component.ComponentParseUtils; import com.android.internal.pm.pkg.component.ParsedActivity; import com.android.internal.pm.pkg.component.ParsedAttribution; import com.android.internal.pm.pkg.component.ParsedComponent; @@ -63,11 +66,12 @@ import com.android.internal.pm.pkg.component.ParsedProcess; import com.android.internal.pm.pkg.component.ParsedProvider; import com.android.internal.pm.pkg.component.ParsedService; import com.android.internal.pm.pkg.component.ParsedUsesPermission; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingUtils; import com.android.internal.util.ArrayUtils; import com.android.server.SystemConfig; import com.android.server.pm.PackageArchiver; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageStateUnserialized; @@ -75,9 +79,6 @@ import com.android.server.pm.pkg.PackageUserState; import com.android.server.pm.pkg.PackageUserStateInternal; import com.android.server.pm.pkg.PackageUserStateUtils; import com.android.server.pm.pkg.SELinuxUtil; -import com.android.server.pm.pkg.component.ComponentParseUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; import java.io.File; import java.util.ArrayList; @@ -273,8 +274,8 @@ public class PackageInfoUtils { final ActivityInfo[] res = new ActivityInfo[N]; for (int i = 0; i < N; i++) { final ParsedActivity a = pkg.getActivities().get(i); - if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a, - aflags)) { + if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), + a.isEnabled(), a.isDirectBootAware(), a.getName(), aflags)) { if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( a.getName())) { continue; @@ -293,8 +294,8 @@ public class PackageInfoUtils { final ActivityInfo[] res = new ActivityInfo[size]; for (int i = 0; i < size; i++) { final ParsedActivity a = pkg.getReceivers().get(i); - if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a, - flags)) { + if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), + a.isEnabled(), a.isDirectBootAware(), a.getName(), flags)) { res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, userId, pkgSetting); } @@ -309,8 +310,8 @@ public class PackageInfoUtils { final ServiceInfo[] res = new ServiceInfo[size]; for (int i = 0; i < size; i++) { final ParsedService s = pkg.getServices().get(i); - if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), s, - flags)) { + if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), + s.isEnabled(), s.isDirectBootAware(), s.getName(), flags)) { res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo, userId, pkgSetting); } @@ -326,8 +327,8 @@ public class PackageInfoUtils { for (int i = 0; i < size; i++) { final ParsedProvider pr = pkg.getProviders() .get(i); - if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), pr, - flags)) { + if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), + pr.isEnabled(), pr.isDirectBootAware(), pr.getName(), flags)) { res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo, userId, pkgSetting); } @@ -923,7 +924,7 @@ public class PackageInfoUtils { | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) - | flag(AndroidPackageUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM) + | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM) | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST); return appInfoFlags(pkgWithoutStateFlags, pkgSetting); @@ -964,12 +965,12 @@ public class PackageInfoUtils { | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING) - | flag(AndroidPackageUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) - | flag(AndroidPackageUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) - | flag(AndroidPackageUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM) - | flag(AndroidPackageUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR) - | flag(AndroidPackageUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT) - | flag(AndroidPackageUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM) + | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) + | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) + | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM) + | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR) + | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT) + | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM) | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY); Boolean resizeableActivity = pkg.getResizeableActivity(); diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java index 1c751e07bbbe..b6a08a5a546f 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java +++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java @@ -35,17 +35,19 @@ import android.util.DisplayMetrics; import android.util.Slog; import com.android.internal.compat.IPlatformCompat; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.internal.pm.pkg.parsing.ParsingUtils; import com.android.internal.util.ArrayUtils; +import com.android.server.SystemConfig; import com.android.server.pm.PackageManagerException; import com.android.server.pm.PackageManagerService; -import com.android.server.pm.parsing.pkg.PackageImpl; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; import java.io.File; import java.util.List; +import java.util.Set; /** * The v2 of package parsing for use when parsing is initiated in the server and must @@ -88,6 +90,16 @@ public class PackageParser2 implements AutoCloseable { // behavior. return false; } + + @Override + public Set getHiddenApiWhitelistedApps() { + return SystemConfig.getInstance().getHiddenApiWhitelistedApps(); + } + + @Override + public Set getInstallConstraintsAllowlist() { + return SystemConfig.getInstance().getInstallConstraintsAllowlist(); + } }); } @@ -221,7 +233,7 @@ public class PackageParser2 implements AutoCloseable { @NonNull String baseCodePath, @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) { return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray, - isCoreApp); + isCoreApp, Callback.this); } /** diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java index 61be6e1036f2..1b7c7ad94dc9 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java @@ -29,7 +29,9 @@ import android.content.pm.parsing.result.ParseTypeImpl; import android.os.incremental.IncrementalManager; import com.android.internal.content.NativeLibraryHelper; +import com.android.internal.pm.parsing.PackageParserException; import com.android.internal.pm.parsing.pkg.AndroidPackageHidden; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.pkg.component.ParsedActivity; import com.android.internal.pm.pkg.component.ParsedInstrumentation; import com.android.internal.pm.pkg.component.ParsedProvider; @@ -37,7 +39,6 @@ import com.android.internal.pm.pkg.component.ParsedService; import com.android.internal.pm.pkg.parsing.ParsingPackageHidden; import com.android.internal.util.ArrayUtils; import com.android.server.SystemConfig; -import com.android.server.pm.PackageManagerException; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; import com.android.server.pm.pkg.PackageStateInternal; @@ -134,10 +135,10 @@ public class AndroidPackageUtils { /** * Validate the dex metadata files installed for the given package. * - * @throws PackageManagerException in case of errors. + * @throws PackageParserException in case of errors. */ public static void validatePackageDexMetadata(AndroidPackage pkg) - throws PackageManagerException { + throws PackageParserException { Collection apkToDexMetadataList = getPackageDexMetadata(pkg).values(); String packageName = pkg.getPackageName(); long versionCode = pkg.getLongVersionCode(); @@ -146,7 +147,7 @@ public class AndroidPackageUtils { final ParseResult result = DexMetadataHelper.validateDexMetadataFile( input.reset(), dexMetadata, packageName, versionCode); if (result.isError()) { - throw new PackageManagerException( + throw new PackageParserException( result.getErrorCode(), result.getErrorMessage(), result.getException()); } } @@ -314,60 +315,4 @@ public class AndroidPackageUtils { info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode(); info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor(); } - - /** - * @deprecated Use {@link PackageState#isSystem} - */ - @Deprecated - public static boolean isSystem(@NonNull AndroidPackage pkg) { - return ((AndroidPackageHidden) pkg).isSystem(); - } - - /** - * @deprecated Use {@link PackageState#isSystemExt} - */ - @Deprecated - public static boolean isSystemExt(@NonNull AndroidPackage pkg) { - return ((AndroidPackageHidden) pkg).isSystemExt(); - } - - /** - * @deprecated Use {@link PackageState#isPrivileged} - */ - @Deprecated - public static boolean isPrivileged(@NonNull AndroidPackage pkg) { - return ((AndroidPackageHidden) pkg).isPrivileged(); - } - - /** - * @deprecated Use {@link PackageState#isOem} - */ - @Deprecated - public static boolean isOem(@NonNull AndroidPackage pkg) { - return ((AndroidPackageHidden) pkg).isOem(); - } - - /** - * @deprecated Use {@link PackageState#isVendor} - */ - @Deprecated - public static boolean isVendor(@NonNull AndroidPackage pkg) { - return ((AndroidPackageHidden) pkg).isVendor(); - } - - /** - * @deprecated Use {@link PackageState#isProduct} - */ - @Deprecated - public static boolean isProduct(@NonNull AndroidPackage pkg) { - return ((AndroidPackageHidden) pkg).isProduct(); - } - - /** - * @deprecated Use {@link PackageState#isOdm} - */ - @Deprecated - public static boolean isOdm(@NonNull AndroidPackage pkg) { - return ((AndroidPackageHidden) pkg).isOdm(); - } } diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java deleted file mode 100644 index da58d47edbfe..000000000000 --- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java +++ /dev/null @@ -1,3783 +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.server.pm.parsing.pkg; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.emptySet; - -import android.annotation.LongDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.ConfigurationInfo; -import android.content.pm.FeatureGroupInfo; -import android.content.pm.FeatureInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.SigningDetails; -import android.content.res.TypedArray; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.UserHandle; -import android.os.storage.StorageManager; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Pair; -import android.util.SparseArray; -import android.util.SparseIntArray; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.parsing.pkg.AndroidPackageHidden; -import com.android.internal.pm.parsing.pkg.AndroidPackageInternal; -import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.internal.pm.pkg.AndroidPackageSplitImpl; -import com.android.internal.pm.pkg.component.ParsedActivity; -import com.android.internal.pm.pkg.component.ParsedApexSystemService; -import com.android.internal.pm.pkg.component.ParsedAttribution; -import com.android.internal.pm.pkg.component.ParsedComponent; -import com.android.internal.pm.pkg.component.ParsedInstrumentation; -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.pm.pkg.component.ParsedMainComponent; -import com.android.internal.pm.pkg.component.ParsedPermission; -import com.android.internal.pm.pkg.component.ParsedPermissionGroup; -import com.android.internal.pm.pkg.component.ParsedProcess; -import com.android.internal.pm.pkg.component.ParsedProvider; -import com.android.internal.pm.pkg.component.ParsedService; -import com.android.internal.pm.pkg.component.ParsedUsesPermission; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.internal.pm.pkg.parsing.ParsingPackageHidden; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.CollectionUtils; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; -import com.android.server.pm.parsing.PackageInfoUtils; -import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.AndroidPackageSplit; -import com.android.server.pm.pkg.SELinuxUtil; -import com.android.server.pm.pkg.component.ComponentMutateUtils; -import com.android.server.pm.pkg.component.ParsedActivityImpl; -import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl; -import com.android.server.pm.pkg.component.ParsedAttributionImpl; -import com.android.server.pm.pkg.component.ParsedInstrumentationImpl; -import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl; -import com.android.server.pm.pkg.component.ParsedPermissionImpl; -import com.android.server.pm.pkg.component.ParsedProcessImpl; -import com.android.server.pm.pkg.component.ParsedProviderImpl; -import com.android.server.pm.pkg.component.ParsedServiceImpl; -import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import libcore.util.EmptyArray; - -import java.io.File; -import java.security.PublicKey; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -/** - * Extensions to {@link PackageImpl} including fields/state contained in the system server - * and not exposed to the core SDK. - * - * @hide - */ -public class PackageImpl implements ParsedPackage, AndroidPackageInternal, - AndroidPackageHidden, ParsingPackage, ParsingPackageHidden, Parcelable { - - private static final SparseArray EMPTY_INT_ARRAY_SPARSE_ARRAY = new SparseArray<>(); - private static final Comparator ORDER_COMPARATOR = - (first, second) -> Integer.compare(second.getOrder(), first.getOrder()); - public static final Parcelling.BuiltIn.ForBoolean sForBoolean = Parcelling.Cache.getOrCreate( - Parcelling.BuiltIn.ForBoolean.class); - public static final ForInternedString sForInternedString = Parcelling.Cache.getOrCreate( - ForInternedString.class); - public static final Parcelling.BuiltIn.ForInternedStringArray sForInternedStringArray = - Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringArray.class); - public static final Parcelling.BuiltIn.ForInternedStringList sForInternedStringList = - Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringList.class); - public static final Parcelling.BuiltIn.ForInternedStringValueMap sForInternedStringValueMap = - Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringValueMap.class); - public static final Parcelling.BuiltIn.ForStringSet sForStringSet = - Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class); - public static final Parcelling.BuiltIn.ForInternedStringSet sForInternedStringSet = - Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringSet.class); - protected static final ParsingUtils.StringPairListParceler sForIntentInfoPairs = - new ParsingUtils.StringPairListParceler(); - protected int versionCode; - protected int versionCodeMajor; - @NonNull - @DataClass.ParcelWith(ForInternedString.class) - protected String packageName; - @NonNull - protected String mBaseApkPath; - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - protected List usesLibraries = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - protected List usesOptionalLibraries = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - protected List usesNativeLibraries = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - protected List usesOptionalNativeLibraries = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - protected List originalPackages = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - protected List adoptPermissions = emptyList(); - /** - * @deprecated consider migrating to {@link #getUsesPermissions} which has - * more parsed details, such as flags - */ - @NonNull - @Deprecated - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) - protected Set requestedPermissions = emptySet(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - protected List protectedBroadcasts = emptyList(); - @NonNull - protected List activities = emptyList(); - @NonNull - protected List apexSystemServices = emptyList(); - @NonNull - protected List receivers = emptyList(); - @NonNull - protected List services = emptyList(); - @NonNull - protected List providers = emptyList(); - @NonNull - protected List permissions = emptyList(); - @NonNull - protected List permissionGroups = emptyList(); - @NonNull - protected List instrumentations = emptyList(); - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - protected String volumeUuid; - @NonNull - @DataClass.ParcelWith(ForInternedString.class) - protected String mPath; - @Nullable - protected String[] splitCodePaths; - @NonNull - protected UUID mStorageUuid; - // These are objects because null represents not explicitly set - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean supportsSmallScreens; - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean supportsNormalScreens; - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean supportsLargeScreens; - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean supportsExtraLargeScreens; - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean resizeable; - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean anyDensity; - private int baseRevisionCode; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String versionName; - private int compileSdkVersion; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String compileSdkVersionCodeName; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String restrictedAccountType; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String requiredAccountType; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String overlayTarget; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String overlayTargetOverlayableName; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String overlayCategory; - private int overlayPriority; - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringValueMap.class) - private Map overlayables = emptyMap(); - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String sdkLibraryName; - private int sdkLibVersionMajor; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String staticSharedLibraryName; - private long staticSharedLibVersion; - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - private List libraryNames = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - private List usesStaticLibraries = emptyList(); - @Nullable - private long[] usesStaticLibrariesVersions; - @Nullable - private String[][] usesStaticLibrariesCertDigests; - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - private List usesSdkLibraries = emptyList(); - @Nullable - private long[] usesSdkLibrariesVersionsMajor; - @Nullable - private String[][] usesSdkLibrariesCertDigests; - @Nullable - private boolean[] usesSdkLibrariesOptional; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String sharedUserId; - private int sharedUserLabel; - @NonNull - private List configPreferences = emptyList(); - @NonNull - private List reqFeatures = emptyList(); - @NonNull - private List featureGroups = emptyList(); - @Nullable - private byte[] restrictUpdateHash; - @NonNull - private List usesPermissions = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) - private Set implicitPermissions = emptySet(); - @NonNull - private Set upgradeKeySets = emptySet(); - @NonNull - private Map> keySetMapping = emptyMap(); - @NonNull - private List attributions = emptyList(); - @NonNull -// @DataClass.ParcelWith(ParsingUtils.StringPairListParceler.class) - private List> preferredActivityFilters = emptyList(); - /** - * Map from a process name to a {@link ParsedProcess}. - */ - @NonNull - private Map processes = emptyMap(); - @Nullable - private Bundle metaData; - @NonNull - private Map mProperties = emptyMap(); - @NonNull - private SigningDetails signingDetails = SigningDetails.UNKNOWN; - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - private List queriesIntents = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class) - private List queriesPackages = emptyList(); - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) - private Set queriesProviders = emptySet(); - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringArray.class) - private String[] splitClassLoaderNames; - @Nullable - private SparseArray splitDependencies; - @Nullable - private int[] splitFlags; - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringArray.class) - private String[] splitNames; - @Nullable - private int[] splitRevisionCodes; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String appComponentFactory; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String backupAgentName; - private int banner; - private int category = ApplicationInfo.CATEGORY_UNDEFINED; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String classLoaderName; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String className; - private int compatibleWidthLimitDp; - private int descriptionRes; - private int fullBackupContent; - private int dataExtractionRules; - private int iconRes; - private int installLocation = ParsingPackageUtils.PARSE_DEFAULT_INSTALL_LOCATION; - private int labelRes; - private int largestWidthLimitDp; - private int logo; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String manageSpaceActivityName; - private float maxAspectRatio; - private float minAspectRatio; - @Nullable - private SparseIntArray minExtensionVersions; - private int minSdkVersion = ParsingUtils.DEFAULT_MIN_SDK_VERSION; - private int maxSdkVersion = ParsingUtils.DEFAULT_MAX_SDK_VERSION; - private int networkSecurityConfigRes; - @Nullable - private CharSequence nonLocalizedLabel; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String permission; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String processName; - private int requiresSmallestWidthDp; - private int roundIconRes; - private int targetSandboxVersion; - private int targetSdkVersion = ParsingUtils.DEFAULT_TARGET_SDK_VERSION; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String taskAffinity; - private int theme; - private int uiOptions; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String zygotePreloadName; - /** - * @see AndroidPackage#getResizeableActivity() - */ - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean resizeableActivity; - private int autoRevokePermissions; - @ApplicationInfo.GwpAsanMode - private int gwpAsanMode; - @ApplicationInfo.MemtagMode - private int memtagMode; - @ApplicationInfo.NativeHeapZeroInitialized - private int nativeHeapZeroInitialized; - @Nullable - @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) - private Boolean requestRawExternalStorageAccess; - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) - private Set mimeGroups = emptySet(); - // Usually there's code to set enabled to true during parsing, but it's possible to install - // an APK targeting tag. That code would be skipped - // and never assign this, so initialize this to true for those cases. - private long mBooleans = Booleans.ENABLED; - private long mBooleans2 = Booleans2.UPDATABLE_SYSTEM; - @NonNull - private Set mKnownActivityEmbeddingCerts = emptySet(); - // Derived fields - private long mLongVersionCode; - private int mLocaleConfigRes; - - private List mSplits; - - @NonNull - private String[] mUsesLibrariesSorted; - @NonNull - private String[] mUsesOptionalLibrariesSorted; - @NonNull - private String[] mUsesSdkLibrariesSorted; - @NonNull - private String[] mUsesStaticLibrariesSorted; - - @NonNull - public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath, - @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) { - return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp); - } - - /** - * Mock an unavailable {@link AndroidPackage} to use when - * removing - * a package from the system. - * This can occur if the package was installed on a storage device that has since been removed. - * Since the infrastructure uses {@link AndroidPackage}, but - * for - * this case only cares about - * volumeUuid, just fake it rather than having separate method paths. - */ - @NonNull - public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) { - return PackageImpl.forTesting(packageName) - .setVolumeUuid(volumeUuid) - .hideAsParsed() - .hideAsFinal(); - } - - @NonNull - @VisibleForTesting - public static ParsingPackage forTesting(String packageName) { - return forTesting(packageName, ""); - } - - @NonNull - @VisibleForTesting - public static ParsingPackage forTesting(String packageName, String baseCodePath) { - return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false); - } - - @NonNull - @DataClass.ParcelWith(ForInternedString.class) - private final String manifestPackageName; - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - protected String nativeLibraryDir; - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - protected String nativeLibraryRootDir; - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - protected String primaryCpuAbi; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - protected String secondaryCpuAbi; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - protected String secondaryNativeLibraryDir; - - /** - * This is an appId, the uid if the userId is == USER_SYSTEM - */ - private int uid = -1; - - // This is kept around as a boolean to avoid flag calculation - // during ApplicationInfo generation. - private boolean nativeLibraryRootRequiresIsa; - - @Override - public PackageImpl addActivity(ParsedActivity parsedActivity) { - this.activities = CollectionUtils.add(this.activities, parsedActivity); - addMimeGroupsFromComponent(parsedActivity); - return this; - } - - @Override - public PackageImpl addAdoptPermission(String adoptPermission) { - this.adoptPermissions = CollectionUtils.add(this.adoptPermissions, - TextUtils.safeIntern(adoptPermission)); - return this; - } - - @Override - public final PackageImpl addApexSystemService( - ParsedApexSystemService parsedApexSystemService) { - this.apexSystemServices = CollectionUtils.add( - this.apexSystemServices, parsedApexSystemService); - return this; - } - - @Override - public PackageImpl addAttribution(ParsedAttribution attribution) { - this.attributions = CollectionUtils.add(this.attributions, attribution); - return this; - } - - @Override - public PackageImpl addConfigPreference(ConfigurationInfo configPreference) { - this.configPreferences = CollectionUtils.add(this.configPreferences, configPreference); - return this; - } - - @Override - public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) { - this.featureGroups = CollectionUtils.add(this.featureGroups, featureGroup); - return this; - } - - @Override - public PackageImpl addImplicitPermission(String permission) { - addUsesPermission(new ParsedUsesPermissionImpl(permission, 0 /*usesPermissionFlags*/)); - this.implicitPermissions = CollectionUtils.add(this.implicitPermissions, - TextUtils.safeIntern(permission)); - return this; - } - - @Override - public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) { - this.instrumentations = CollectionUtils.add(this.instrumentations, instrumentation); - return this; - } - - @Override - public PackageImpl addKeySet(String keySetName, PublicKey publicKey) { - ArraySet publicKeys = keySetMapping.get(keySetName); - if (publicKeys == null) { - publicKeys = new ArraySet<>(); - } - publicKeys.add(publicKey); - keySetMapping = CollectionUtils.add(this.keySetMapping, keySetName, publicKeys); - return this; - } - - @Override - public PackageImpl addLibraryName(String libraryName) { - this.libraryNames = CollectionUtils.add(this.libraryNames, - TextUtils.safeIntern(libraryName)); - return this; - } - - private void addMimeGroupsFromComponent(ParsedComponent component) { - for (int i = component.getIntents().size() - 1; i >= 0; i--) { - IntentFilter filter = component.getIntents().get(i).getIntentFilter(); - for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) { - if (mimeGroups != null && mimeGroups.size() > 500) { - throw new IllegalStateException("Max limit on number of MIME Groups reached"); - } - mimeGroups = CollectionUtils.add(mimeGroups, filter.getMimeGroup(groupIndex)); - } - } - } - - @Override - public PackageImpl addOriginalPackage(String originalPackage) { - this.originalPackages = CollectionUtils.add(this.originalPackages, originalPackage); - return this; - } - - @Override - public ParsingPackage addOverlayable(String overlayableName, String actorName) { - this.overlayables = CollectionUtils.add(this.overlayables, overlayableName, - TextUtils.safeIntern(actorName)); - return this; - } - - @Override - public PackageImpl addPermission(ParsedPermission permission) { - this.permissions = CollectionUtils.add(this.permissions, permission); - return this; - } - - @Override - public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) { - this.permissionGroups = CollectionUtils.add(this.permissionGroups, permissionGroup); - return this; - } - - @Override - public PackageImpl addPreferredActivityFilter(String className, - ParsedIntentInfo intentInfo) { - this.preferredActivityFilters = CollectionUtils.add(this.preferredActivityFilters, - Pair.create(className, intentInfo)); - return this; - } - - @Override - public PackageImpl addProperty(@Nullable PackageManager.Property property) { - if (property == null) { - return this; - } - this.mProperties = CollectionUtils.add(this.mProperties, property.getName(), property); - return this; - } - - @Override - public PackageImpl addProtectedBroadcast(String protectedBroadcast) { - if (!this.protectedBroadcasts.contains(protectedBroadcast)) { - this.protectedBroadcasts = CollectionUtils.add(this.protectedBroadcasts, - TextUtils.safeIntern(protectedBroadcast)); - } - return this; - } - - @Override - public PackageImpl addProvider(ParsedProvider parsedProvider) { - this.providers = CollectionUtils.add(this.providers, parsedProvider); - addMimeGroupsFromComponent(parsedProvider); - return this; - } - - @Override - public PackageImpl addQueriesIntent(Intent intent) { - this.queriesIntents = CollectionUtils.add(this.queriesIntents, intent); - return this; - } - - @Override - public PackageImpl addQueriesPackage(String packageName) { - this.queriesPackages = CollectionUtils.add(this.queriesPackages, - TextUtils.safeIntern(packageName)); - return this; - } - - @Override - public PackageImpl addQueriesProvider(String authority) { - this.queriesProviders = CollectionUtils.add(this.queriesProviders, authority); - return this; - } - - @Override - public PackageImpl addReceiver(ParsedActivity parsedReceiver) { - this.receivers = CollectionUtils.add(this.receivers, parsedReceiver); - addMimeGroupsFromComponent(parsedReceiver); - return this; - } - - @Override - public PackageImpl addReqFeature(FeatureInfo reqFeature) { - this.reqFeatures = CollectionUtils.add(this.reqFeatures, reqFeature); - return this; - } - - @Override - public PackageImpl addService(ParsedService parsedService) { - this.services = CollectionUtils.add(this.services, parsedService); - addMimeGroupsFromComponent(parsedService); - return this; - } - - @Override - public PackageImpl addUsesLibrary(String libraryName) { - libraryName = TextUtils.safeIntern(libraryName); - if (!ArrayUtils.contains(this.usesLibraries, libraryName)) { - this.usesLibraries = CollectionUtils.add(this.usesLibraries, libraryName); - } - return this; - } - - @Override - public final PackageImpl addUsesNativeLibrary(String libraryName) { - libraryName = TextUtils.safeIntern(libraryName); - if (!ArrayUtils.contains(this.usesNativeLibraries, libraryName)) { - this.usesNativeLibraries = CollectionUtils.add(this.usesNativeLibraries, libraryName); - } - return this; - } - - @Override - public PackageImpl addUsesOptionalLibrary(String libraryName) { - libraryName = TextUtils.safeIntern(libraryName); - if (!ArrayUtils.contains(this.usesOptionalLibraries, libraryName)) { - this.usesOptionalLibraries = CollectionUtils.add(this.usesOptionalLibraries, - libraryName); - } - return this; - } - - @Override - public final PackageImpl addUsesOptionalNativeLibrary(String libraryName) { - libraryName = TextUtils.safeIntern(libraryName); - if (!ArrayUtils.contains(this.usesOptionalNativeLibraries, libraryName)) { - this.usesOptionalNativeLibraries = CollectionUtils.add(this.usesOptionalNativeLibraries, - libraryName); - } - return this; - } - - @Override - public PackageImpl addUsesPermission(ParsedUsesPermission permission) { - this.usesPermissions = CollectionUtils.add(this.usesPermissions, permission); - - // Continue populating legacy data structures to avoid performance - // issues until all that code can be migrated - this.requestedPermissions = CollectionUtils.add(this.requestedPermissions, - permission.getName()); - - return this; - } - - @Override - public PackageImpl addUsesSdkLibrary(String libraryName, long versionMajor, - String[] certSha256Digests, boolean usesSdkLibrariesOptional) { - this.usesSdkLibraries = CollectionUtils.add(this.usesSdkLibraries, - TextUtils.safeIntern(libraryName)); - this.usesSdkLibrariesVersionsMajor = ArrayUtils.appendLong( - this.usesSdkLibrariesVersionsMajor, versionMajor, true); - this.usesSdkLibrariesCertDigests = ArrayUtils.appendElement(String[].class, - this.usesSdkLibrariesCertDigests, certSha256Digests, true); - this.usesSdkLibrariesOptional = appendBoolean(this.usesSdkLibrariesOptional, - usesSdkLibrariesOptional); - return this; - } - - /** - * Adds value to given array if not already present, providing set-like - * behavior. - */ - public static boolean[] appendBoolean(@Nullable boolean[] cur, boolean val) { - if (cur == null) { - return new boolean[] { val }; - } - final int N = cur.length; - boolean[] ret = new boolean[N + 1]; - System.arraycopy(cur, 0, ret, 0, N); - ret[N] = val; - return ret; - } - - @Override - public PackageImpl addUsesStaticLibrary(String libraryName, long version, - String[] certSha256Digests) { - this.usesStaticLibraries = CollectionUtils.add(this.usesStaticLibraries, - TextUtils.safeIntern(libraryName)); - this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions, - version, true); - this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, - this.usesStaticLibrariesCertDigests, certSha256Digests, true); - return this; - } - - @Override - public boolean isAttributionsUserVisible() { - return getBoolean(Booleans.ATTRIBUTIONS_ARE_USER_VISIBLE); - } - - @Override - public PackageImpl asSplit(String[] splitNames, String[] splitCodePaths, - int[] splitRevisionCodes, SparseArray splitDependencies) { - this.splitNames = splitNames; - this.splitCodePaths = splitCodePaths; - this.splitRevisionCodes = splitRevisionCodes; - this.splitDependencies = splitDependencies; - - int count = splitNames.length; - this.splitFlags = new int[count]; - this.splitClassLoaderNames = new String[count]; - return this; - } - - protected void assignDerivedFields() { - mStorageUuid = StorageManager.convert(volumeUuid); - mLongVersionCode = PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); - } - - /** - * Create a map from a process name to the custom application class for this process, - * which comes from . - * - * The original information is stored in {@link #processes}, but it's stored in - * a form of: [process name] -[1:N]-> [package name] -[1:N]-> [class name]. - * We scan it and collect the process names and their app class names, only for this package. - * - * The resulting map only contains processes with a custom application class set. - */ - @Nullable - private ArrayMap buildAppClassNamesByProcess() { - if (ArrayUtils.size(processes) == 0) { - return null; - } - final ArrayMap ret = new ArrayMap<>(4); - for (String processName : processes.keySet()) { - final ParsedProcess process = processes.get(processName); - final ArrayMap appClassesByPackage = - process.getAppClassNamesByPackage(); - - for (int i = 0; i < appClassesByPackage.size(); i++) { - final String packageName = appClassesByPackage.keyAt(i); - - if (this.packageName.equals(packageName)) { - final String appClassName = appClassesByPackage.valueAt(i); - if (!TextUtils.isEmpty(appClassName)) { - ret.put(processName, appClassName); - } - } - } - } - return ret; - } - - @Override - public List getSplits() { - if (mSplits == null) { - var splits = new ArrayList(); - splits.add(new AndroidPackageSplitImpl( - null, - getBaseApkPath(), - getBaseRevisionCode(), - isDeclaredHavingCode() ? ApplicationInfo.FLAG_HAS_CODE : 0, - getClassLoaderName() - )); - - if (splitNames != null) { - for (int index = 0; index < splitNames.length; index++) { - splits.add(new AndroidPackageSplitImpl( - splitNames[index], - splitCodePaths[index], - splitRevisionCodes[index], - splitFlags[index], - splitClassLoaderNames[index] - )); - } - } - - if (splitDependencies != null) { - for (int index = 0; index < splitDependencies.size(); index++) { - var splitIndex = splitDependencies.keyAt(index); - var dependenciesByIndex = splitDependencies.valueAt(index); - var dependencies = new ArrayList(); - for (int dependencyIndex : dependenciesByIndex) { - // Legacy holdover, base dependencies are an array of -1 rather than empty - if (dependencyIndex >= 0) { - dependencies.add(splits.get(dependencyIndex)); - } - } - ((AndroidPackageSplitImpl) splits.get(splitIndex)) - .fillDependencies(Collections.unmodifiableList(dependencies)); - } - } - - mSplits = Collections.unmodifiableList(splits); - } - return mSplits; - } - - @Override - public String toString() { - return "Package{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + packageName + "}"; - } - - @NonNull - @Override - public List getActivities() { - return activities; - } - - @NonNull - @Override - public List getAdoptPermissions() { - return adoptPermissions; - } - - @NonNull - @Override - public List getApexSystemServices() { - return apexSystemServices; - } - - @Nullable - @Override - public String getAppComponentFactory() { - return appComponentFactory; - } - - @NonNull - @Override - public List getAttributions() { - return attributions; - } - - @Override - public int getAutoRevokePermissions() { - return autoRevokePermissions; - } - - @Nullable - @Override - public String getBackupAgentName() { - return backupAgentName; - } - - @Override - public int getBannerResourceId() { - return banner; - } - - @NonNull - @Override - public String getBaseApkPath() { - return mBaseApkPath; - } - - @Override - public int getBaseRevisionCode() { - return baseRevisionCode; - } - - @Override - public int getCategory() { - return category; - } - - @Nullable - @Override - public String getClassLoaderName() { - return classLoaderName; - } - - @Nullable - @Override - public String getApplicationClassName() { - return className; - } - - @Override - public int getCompatibleWidthLimitDp() { - return compatibleWidthLimitDp; - } - - @Override - public int getCompileSdkVersion() { - return compileSdkVersion; - } - - @Nullable - @Override - public String getCompileSdkVersionCodeName() { - return compileSdkVersionCodeName; - } - - @NonNull - @Override - public List getConfigPreferences() { - return configPreferences; - } - - @Override - public int getDataExtractionRulesResourceId() { - return dataExtractionRules; - } - - @Override - public int getDescriptionResourceId() { - return descriptionRes; - } - - @NonNull - @Override - public List getFeatureGroups() { - return featureGroups; - } - - @Override - public int getFullBackupContentResourceId() { - return fullBackupContent; - } - - @ApplicationInfo.GwpAsanMode - @Override - public int getGwpAsanMode() { - return gwpAsanMode; - } - - @Override - public int getIconResourceId() { - return iconRes; - } - - @NonNull - @Override - public Set getImplicitPermissions() { - return implicitPermissions; - } - - @Override - public int getInstallLocation() { - return installLocation; - } - - @NonNull - @Override - public List getInstrumentations() { - return instrumentations; - } - - @NonNull - @Override - public Map> getKeySetMapping() { - return keySetMapping; - } - - @NonNull - @Override - public Set getKnownActivityEmbeddingCerts() { - return mKnownActivityEmbeddingCerts; - } - - @Override - public int getLabelResourceId() { - return labelRes; - } - - @Override - public int getLargestWidthLimitDp() { - return largestWidthLimitDp; - } - - @NonNull - @Override - public List getLibraryNames() { - return libraryNames; - } - - @Override - public int getLocaleConfigResourceId() { - return mLocaleConfigRes; - } - - @Override - public int getLogoResourceId() { - return logo; - } - - @Nullable - @Override - public String getManageSpaceActivityName() { - return manageSpaceActivityName; - } - - @Override - public float getMaxAspectRatio() { - return maxAspectRatio; - } - - @Override - public int getMaxSdkVersion() { - return maxSdkVersion; - } - - @ApplicationInfo.MemtagMode - @Override - public int getMemtagMode() { - return memtagMode; - } - - @Nullable - @Override - public Bundle getMetaData() { - return metaData; - } - - @Override - @Nullable - public Set getMimeGroups() { - return mimeGroups; - } - - @Override - public float getMinAspectRatio() { - return minAspectRatio; - } - - @Nullable - @Override - public SparseIntArray getMinExtensionVersions() { - return minExtensionVersions; - } - - @Override - public int getMinSdkVersion() { - return minSdkVersion; - } - - @ApplicationInfo.NativeHeapZeroInitialized - @Override - public int getNativeHeapZeroInitialized() { - return nativeHeapZeroInitialized; - } - - @Override - public int getNetworkSecurityConfigResourceId() { - return networkSecurityConfigRes; - } - - @Nullable - @Override - public CharSequence getNonLocalizedLabel() { - return nonLocalizedLabel; - } - - @NonNull - @Override - public List getOriginalPackages() { - return originalPackages; - } - - @Nullable - @Override - public String getOverlayCategory() { - return overlayCategory; - } - - @Override - public int getOverlayPriority() { - return overlayPriority; - } - - @Nullable - @Override - public String getOverlayTarget() { - return overlayTarget; - } - - @Nullable - @Override - public String getOverlayTargetOverlayableName() { - return overlayTargetOverlayableName; - } - - @NonNull - @Override - public Map getOverlayables() { - return overlayables; - } - - @NonNull - @Override - public String getPackageName() { - return packageName; - } - - @NonNull - @Override - public String getPath() { - return mPath; - } - - @Nullable - @Override - public String getPermission() { - return permission; - } - - @NonNull - @Override - public List getPermissionGroups() { - return permissionGroups; - } - - @NonNull - @Override - public List getPermissions() { - return permissions; - } - - @NonNull - @Override - public List> getPreferredActivityFilters() { - return preferredActivityFilters; - } - - @NonNull - @Override - public String getProcessName() { - return processName != null ? processName : packageName; - } - - @NonNull - @Override - public Map getProcesses() { - return processes; - } - - @NonNull - @Override - public Map getProperties() { - return mProperties; - } - - @NonNull - @Override - public List getProtectedBroadcasts() { - return protectedBroadcasts; - } - - @NonNull - @Override - public List getProviders() { - return providers; - } - - @NonNull - @Override - public List getQueriesIntents() { - return queriesIntents; - } - - @NonNull - @Override - public List getQueriesPackages() { - return queriesPackages; - } - - @NonNull - @Override - public Set getQueriesProviders() { - return queriesProviders; - } - - @NonNull - @Override - public List getReceivers() { - return receivers; - } - - @NonNull - @Override - public List getRequestedFeatures() { - return reqFeatures; - } - - /** - * @deprecated consider migrating to {@link #getUsesPermissions} which has - * more parsed details, such as flags - */ - @NonNull - @Override - @Deprecated - public Set getRequestedPermissions() { - return requestedPermissions; - } - - @Nullable - @Override - public String getRequiredAccountType() { - return requiredAccountType; - } - - @Override - public int getRequiresSmallestWidthDp() { - return requiresSmallestWidthDp; - } - - @Nullable - @Override - public Boolean getResizeableActivity() { - return resizeableActivity; - } - - @Nullable - @Override - public byte[] getRestrictUpdateHash() { - return restrictUpdateHash; - } - - @Nullable - @Override - public String getRestrictedAccountType() { - return restrictedAccountType; - } - - @Override - public int getRoundIconResourceId() { - return roundIconRes; - } - - @Nullable - @Override - public String getSdkLibraryName() { - return sdkLibraryName; - } - - @Override - public int getSdkLibVersionMajor() { - return sdkLibVersionMajor; - } - - @NonNull - @Override - public List getServices() { - return services; - } - - @Nullable - @Override - public String getSharedUserId() { - return sharedUserId; - } - - @Override - public int getSharedUserLabelResourceId() { - return sharedUserLabel; - } - - @NonNull - @Override - public SigningDetails getSigningDetails() { - return signingDetails; - } - - @NonNull - @Override - public String[] getSplitClassLoaderNames() { - return splitClassLoaderNames == null ? EmptyArray.STRING : splitClassLoaderNames; - } - - @NonNull - @Override - public String[] getSplitCodePaths() { - return splitCodePaths == null ? EmptyArray.STRING : splitCodePaths; - } - - @Nullable - @Override - public SparseArray getSplitDependencies() { - return splitDependencies == null ? EMPTY_INT_ARRAY_SPARSE_ARRAY : splitDependencies; - } - - @Nullable - @Override - public int[] getSplitFlags() { - return splitFlags; - } - - @NonNull - @Override - public String[] getSplitNames() { - return splitNames == null ? EmptyArray.STRING : splitNames; - } - - @NonNull - @Override - public int[] getSplitRevisionCodes() { - return splitRevisionCodes == null ? EmptyArray.INT : splitRevisionCodes; - } - - @Nullable - @Override - public String getStaticSharedLibraryName() { - return staticSharedLibraryName; - } - - @Override - public long getStaticSharedLibraryVersion() { - return staticSharedLibVersion; - } - - @Override - public UUID getStorageUuid() { - return mStorageUuid; - } - - @Override - public int getTargetSandboxVersion() { - return targetSandboxVersion; - } - - @Override - public int getTargetSdkVersion() { - return targetSdkVersion; - } - - @Nullable - @Override - public String getTaskAffinity() { - return taskAffinity; - } - - @Override - public int getThemeResourceId() { - return theme; - } - - @Override - public int getUiOptions() { - return uiOptions; - } - - @NonNull - @Override - public Set getUpgradeKeySets() { - return upgradeKeySets; - } - - @NonNull - @Override - public List getUsesLibraries() { - return usesLibraries; - } - - @NonNull - @Override - public String[] getUsesLibrariesSorted() { - if (mUsesLibrariesSorted == null) { - // Note lazy-sorting here doesn't break immutability because it always - // return the same content. In the case of multi-threading, data race in accessing - // mUsesLibrariesSorted might result in unnecessary creation of sorted copies - // which is OK because the case is quite rare. - mUsesLibrariesSorted = sortLibraries(usesLibraries); - } - return mUsesLibrariesSorted; - } - - @NonNull - @Override - public List getUsesNativeLibraries() { - return usesNativeLibraries; - } - - @NonNull - @Override - public List getUsesOptionalLibraries() { - return usesOptionalLibraries; - } - - @NonNull - @Override - public String[] getUsesOptionalLibrariesSorted() { - if (mUsesOptionalLibrariesSorted == null) { - mUsesOptionalLibrariesSorted = sortLibraries(usesOptionalLibraries); - } - return mUsesOptionalLibrariesSorted; - } - - @NonNull - @Override - public List getUsesOptionalNativeLibraries() { - return usesOptionalNativeLibraries; - } - - @NonNull - @Override - public List getUsesPermissions() { - return usesPermissions; - } - - @NonNull - @Override - public List getUsesSdkLibraries() { return usesSdkLibraries; } - - @NonNull - @Override - public String[] getUsesSdkLibrariesSorted() { - if (mUsesSdkLibrariesSorted == null) { - mUsesSdkLibrariesSorted = sortLibraries(usesSdkLibraries); - } - return mUsesSdkLibrariesSorted; - } - - @Nullable - @Override - public String[][] getUsesSdkLibrariesCertDigests() { return usesSdkLibrariesCertDigests; } - - @Nullable - @Override - public long[] getUsesSdkLibrariesVersionsMajor() { return usesSdkLibrariesVersionsMajor; } - - @Nullable - @Override - public boolean[] getUsesSdkLibrariesOptional() { - return usesSdkLibrariesOptional; - } - - @NonNull - @Override - public List getUsesStaticLibraries() { - return usesStaticLibraries; - } - - @NonNull - @Override - public String[] getUsesStaticLibrariesSorted() { - if (mUsesStaticLibrariesSorted == null) { - mUsesStaticLibrariesSorted = sortLibraries(usesStaticLibraries); - } - return mUsesStaticLibrariesSorted; - } - - @Nullable - @Override - public String[][] getUsesStaticLibrariesCertDigests() { - return usesStaticLibrariesCertDigests; - } - - @Nullable - @Override - public long[] getUsesStaticLibrariesVersions() { - return usesStaticLibrariesVersions; - } - - @Override - public int getVersionCode() { - return versionCode; - } - - @Override - public int getVersionCodeMajor() { - return versionCodeMajor; - } - - @Nullable - @Override - public String getVersionName() { - return versionName; - } - - @Nullable - @Override - public String getVolumeUuid() { - return volumeUuid; - } - - @Nullable - @Override - public String getZygotePreloadName() { - return zygotePreloadName; - } - - @Override - public boolean hasPreserveLegacyExternalStorage() { - return getBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE); - } - - @Override - public boolean hasRequestForegroundServiceExemption() { - return getBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION); - } - - @Nullable - @Override - public Boolean hasRequestRawExternalStorageAccess() { - return requestRawExternalStorageAccess; - } - - @Override - public boolean isAllowAudioPlaybackCapture() { - return getBoolean(Booleans.ALLOW_AUDIO_PLAYBACK_CAPTURE); - } - - @Override - public boolean isBackupAllowed() { - return getBoolean(Booleans.ALLOW_BACKUP); - } - - @Override - public boolean isClearUserDataAllowed() { - return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA); - } - - @Override - public boolean isClearUserDataOnFailedRestoreAllowed() { - return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE); - } - - @Override - public boolean isAllowNativeHeapPointerTagging() { - return getBoolean(Booleans.ALLOW_NATIVE_HEAP_POINTER_TAGGING); - } - - @Override - public boolean isTaskReparentingAllowed() { - return getBoolean(Booleans.ALLOW_TASK_REPARENTING); - } - - public boolean isAnyDensity() { - if (anyDensity == null) { - return targetSdkVersion >= Build.VERSION_CODES.DONUT; - } - - return anyDensity; - } - - @Override - public boolean isBackupInForeground() { - return getBoolean(Booleans.BACKUP_IN_FOREGROUND); - } - - @Override - public boolean isHardwareAccelerated() { - return getBoolean(Booleans.HARDWARE_ACCELERATED); - } - - @Override - public boolean isSaveStateDisallowed() { - return getBoolean(Booleans.CANT_SAVE_STATE); - } - - @Override - public boolean isCrossProfile() { - return getBoolean(Booleans.CROSS_PROFILE); - } - - @Override - public boolean isDebuggable() { - return getBoolean(Booleans.DEBUGGABLE); - } - - @Override - public boolean isDefaultToDeviceProtectedStorage() { - return getBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE); - } - - @Override - public boolean isDirectBootAware() { - return getBoolean(Booleans.DIRECT_BOOT_AWARE); - } - - @Override - public boolean isEnabled() { - return getBoolean(Booleans.ENABLED); - } - - @Override - public boolean isExternalStorage() { - return getBoolean(Booleans.EXTERNAL_STORAGE); - } - - @Override - public boolean isExtractNativeLibrariesRequested() { - return getBoolean(Booleans.EXTRACT_NATIVE_LIBS); - } - - @Override - public boolean isForceQueryable() { - return getBoolean(Booleans.FORCE_QUERYABLE); - } - - @Override - public boolean isFullBackupOnly() { - return getBoolean(Booleans.FULL_BACKUP_ONLY); - } - - @Override - public boolean isGame() { - return getBoolean(Booleans.GAME); - } - - @Override - public boolean isDeclaredHavingCode() { - return getBoolean(Booleans.HAS_CODE); - } - - @Override - public boolean isHasDomainUrls() { - return getBoolean(Booleans.HAS_DOMAIN_URLS); - } - - @Override - public boolean isUserDataFragile() { - return getBoolean(Booleans.HAS_FRAGILE_USER_DATA); - } - - @Override - public boolean isIsolatedSplitLoading() { - return getBoolean(Booleans.ISOLATED_SPLIT_LOADING); - } - - @Override - public boolean isKillAfterRestoreAllowed() { - return getBoolean(Booleans.KILL_AFTER_RESTORE); - } - - @Override - public boolean isLargeHeap() { - return getBoolean(Booleans.LARGE_HEAP); - } - - @Override - public boolean isLeavingSharedUser() { - return getBoolean(Booleans.LEAVING_SHARED_UID); - } - - @Override - public boolean isMultiArch() { - return getBoolean(Booleans.MULTI_ARCH); - } - - @Override - public boolean isOnBackInvokedCallbackEnabled() { - return getBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK); - } - - @Override - public boolean isResourceOverlay() { - return getBoolean(Booleans.OVERLAY); - } - - @Override - public boolean isOverlayIsStatic() { - return getBoolean(Booleans.OVERLAY_IS_STATIC); - } - - @Override - public boolean isPartiallyDirectBootAware() { - return getBoolean(Booleans.PARTIALLY_DIRECT_BOOT_AWARE); - } - - @Override - public boolean isPersistent() { - return getBoolean(Booleans.PERSISTENT); - } - - @Override - public boolean isProfileable() { - return !getBoolean(Booleans.DISALLOW_PROFILING); - } - - @Override - public boolean isProfileableByShell() { - return isProfileable() && getBoolean(Booleans.PROFILEABLE_BY_SHELL); - } - - @Override - public boolean isRequestLegacyExternalStorage() { - return getBoolean(Booleans.REQUEST_LEGACY_EXTERNAL_STORAGE); - } - - @Override - public boolean isRequiredForAllUsers() { - return getBoolean(Booleans.REQUIRED_FOR_ALL_USERS); - } - - @Override - public boolean isResetEnabledSettingsOnAppDataCleared() { - return getBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED); - } - - public boolean isResizeable() { - if (resizeable == null) { - return targetSdkVersion >= Build.VERSION_CODES.DONUT; - } - - return resizeable; - } - - @Override - public boolean isResizeableActivityViaSdkVersion() { - return getBoolean(Booleans.RESIZEABLE_ACTIVITY_VIA_SDK_VERSION); - } - - @Override - public boolean isRestoreAnyVersion() { - return getBoolean(Booleans.RESTORE_ANY_VERSION); - } - - @Override - public boolean isSdkLibrary() { - return getBoolean(Booleans.SDK_LIBRARY); - } - - @Override - public boolean isStaticSharedLibrary() { - return getBoolean(Booleans.STATIC_SHARED_LIBRARY); - } - - public boolean isExtraLargeScreensSupported() { - if (supportsExtraLargeScreens == null) { - return targetSdkVersion >= Build.VERSION_CODES.GINGERBREAD; - } - - return supportsExtraLargeScreens; - } - - public boolean isLargeScreensSupported() { - if (supportsLargeScreens == null) { - return targetSdkVersion >= Build.VERSION_CODES.DONUT; - } - - return supportsLargeScreens; - } - - public boolean isNormalScreensSupported() { - return supportsNormalScreens == null || supportsNormalScreens; - } - - @Override - public boolean isRtlSupported() { - return getBoolean(Booleans.SUPPORTS_RTL); - } - - public boolean isSmallScreensSupported() { - if (supportsSmallScreens == null) { - return targetSdkVersion >= Build.VERSION_CODES.DONUT; - } - - return supportsSmallScreens; - } - - @Override - public boolean isTestOnly() { - return getBoolean(Booleans.TEST_ONLY); - } - - @Override - public boolean is32BitAbiPreferred() { - return getBoolean(Booleans.USE_32_BIT_ABI); - } - - @Override - public boolean isUseEmbeddedDex() { - return getBoolean(Booleans.USE_EMBEDDED_DEX); - } - - @Override - public boolean isCleartextTrafficAllowed() { - return getBoolean(Booleans.USES_CLEARTEXT_TRAFFIC); - } - - @Override - public boolean isNonSdkApiRequested() { - return getBoolean(Booleans.USES_NON_SDK_API); - } - - @Override - public boolean isVisibleToInstantApps() { - return getBoolean(Booleans.VISIBLE_TO_INSTANT_APPS); - } - - @Override - public boolean isVmSafeMode() { - return getBoolean(Booleans.VM_SAFE_MODE); - } - - @Override public PackageImpl removeUsesOptionalNativeLibrary(String libraryName) { - this.usesOptionalNativeLibraries = CollectionUtils.remove(this.usesOptionalNativeLibraries, - libraryName); - return this; - } - - @Override - public PackageImpl setAllowAudioPlaybackCapture(boolean value) { - return setBoolean(Booleans.ALLOW_AUDIO_PLAYBACK_CAPTURE, value); - } - - @Override - public PackageImpl setBackupAllowed(boolean value) { - return setBoolean(Booleans.ALLOW_BACKUP, value); - } - - @Override - public PackageImpl setClearUserDataAllowed(boolean value) { - return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA, value); - } - - @Override - public PackageImpl setClearUserDataOnFailedRestoreAllowed(boolean value) { - return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, value); - } - - @Override - public PackageImpl setAllowNativeHeapPointerTagging(boolean value) { - return setBoolean(Booleans.ALLOW_NATIVE_HEAP_POINTER_TAGGING, value); - } - - @Override - public PackageImpl setTaskReparentingAllowed(boolean value) { - return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value); - } - - @Override - public PackageImpl setAnyDensity(int anyDensity) { - if (anyDensity == 1) { - return this; - } - - this.anyDensity = anyDensity < 0; - return this; - } - - @Override - public PackageImpl setAppComponentFactory(@Nullable String appComponentFactory) { - this.appComponentFactory = appComponentFactory; - return this; - } - - @Override - public ParsingPackage setAttributionsAreUserVisible(boolean attributionsAreUserVisible) { - setBoolean(Booleans.ATTRIBUTIONS_ARE_USER_VISIBLE, attributionsAreUserVisible); - return this; - } - - @Override - public PackageImpl setAutoRevokePermissions(int value) { - autoRevokePermissions = value; - return this; - } - - @Override - public PackageImpl setBackupAgentName(@Nullable String backupAgentName) { - this.backupAgentName = backupAgentName; - return this; - } - - @Override - public PackageImpl setBackupInForeground(boolean value) { - return setBoolean(Booleans.BACKUP_IN_FOREGROUND, value); - } - - @Override - public PackageImpl setBannerResourceId(int value) { - banner = value; - return this; - } - - @Override - public PackageImpl setHardwareAccelerated(boolean value) { - return setBoolean(Booleans.HARDWARE_ACCELERATED, value); - } - - @Override - public PackageImpl setBaseRevisionCode(int value) { - baseRevisionCode = value; - return this; - } - - @Override - public PackageImpl setSaveStateDisallowed(boolean value) { - return setBoolean(Booleans.CANT_SAVE_STATE, value); - } - - @Override - public PackageImpl setCategory(int value) { - category = value; - return this; - } - - @Override - public PackageImpl setClassLoaderName(@Nullable String classLoaderName) { - this.classLoaderName = classLoaderName; - return this; - } - - @Override - public PackageImpl setApplicationClassName(@Nullable String className) { - this.className = className == null ? null : className.trim(); - return this; - } - - @Override - public PackageImpl setCompatibleWidthLimitDp(int value) { - compatibleWidthLimitDp = value; - return this; - } - - @Override - public PackageImpl setCompileSdkVersion(int value) { - compileSdkVersion = value; - return this; - } - - @Override - public ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName) { - this.compileSdkVersionCodeName = compileSdkVersionCodeName; - return this; - } - - @Override - public PackageImpl setCrossProfile(boolean value) { - return setBoolean(Booleans.CROSS_PROFILE, value); - } - - @Override - public PackageImpl setDataExtractionRulesResourceId(int value) { - dataExtractionRules = value; - return this; - } - - @Override - public PackageImpl setDebuggable(boolean value) { - return setBoolean(Booleans.DEBUGGABLE, value); - } - - @Override - public PackageImpl setDescriptionResourceId(int value) { - descriptionRes = value; - return this; - } - - @Override - public PackageImpl setEnabled(boolean value) { - return setBoolean(Booleans.ENABLED, value); - } - - @Override - public PackageImpl setExternalStorage(boolean value) { - return setBoolean(Booleans.EXTERNAL_STORAGE, value); - } - - @Override - public PackageImpl setExtractNativeLibrariesRequested(boolean value) { - return setBoolean(Booleans.EXTRACT_NATIVE_LIBS, value); - } - - @Override - public PackageImpl setForceQueryable(boolean value) { - return setBoolean(Booleans.FORCE_QUERYABLE, value); - } - - @Override - public PackageImpl setFullBackupContentResourceId(int value) { - fullBackupContent = value; - return this; - } - - @Override - public PackageImpl setFullBackupOnly(boolean value) { - return setBoolean(Booleans.FULL_BACKUP_ONLY, value); - } - - @Override - public PackageImpl setGame(boolean value) { - return setBoolean(Booleans.GAME, value); - } - - @Override - public PackageImpl setGwpAsanMode(@ApplicationInfo.GwpAsanMode int value) { - gwpAsanMode = value; - return this; - } - - @Override - public PackageImpl setDeclaredHavingCode(boolean value) { - return setBoolean(Booleans.HAS_CODE, value); - } - - @Override - public PackageImpl setHasDomainUrls(boolean value) { - return setBoolean(Booleans.HAS_DOMAIN_URLS, value); - } - - @Override - public PackageImpl setUserDataFragile(boolean value) { - return setBoolean(Booleans.HAS_FRAGILE_USER_DATA, value); - } - - @Override - public PackageImpl setIconResourceId(int value) { - iconRes = value; - return this; - } - - @Override - public PackageImpl setInstallLocation(int value) { - installLocation = value; - return this; - } - - @Override - public PackageImpl setIsolatedSplitLoading(boolean value) { - return setBoolean(Booleans.ISOLATED_SPLIT_LOADING, value); - } - - @Override - public PackageImpl setKillAfterRestoreAllowed(boolean value) { - return setBoolean(Booleans.KILL_AFTER_RESTORE, value); - } - - @Override - public ParsingPackage setKnownActivityEmbeddingCerts(@NonNull Set knownEmbeddingCerts) { - mKnownActivityEmbeddingCerts = knownEmbeddingCerts; - return this; - } - - @Override - public PackageImpl setLabelResourceId(int value) { - labelRes = value; - return this; - } - - @Override - public PackageImpl setLargeHeap(boolean value) { - return setBoolean(Booleans.LARGE_HEAP, value); - } - - @Override - public PackageImpl setLargestWidthLimitDp(int value) { - largestWidthLimitDp = value; - return this; - } - - @Override - public PackageImpl setLeavingSharedUser(boolean value) { - return setBoolean(Booleans.LEAVING_SHARED_UID, value); - } - - @Override - public PackageImpl setLocaleConfigResourceId(int value) { - mLocaleConfigRes = value; - return this; - } - - @Override - public PackageImpl setLogoResourceId(int value) { - logo = value; - return this; - } - - @Override - public PackageImpl setManageSpaceActivityName(@Nullable String manageSpaceActivityName) { - this.manageSpaceActivityName = manageSpaceActivityName; - return this; - } - - @Override - public PackageImpl setMaxAspectRatio(float value) { - maxAspectRatio = value; - return this; - } - - @Override - public PackageImpl setMaxSdkVersion(int value) { - maxSdkVersion = value; - return this; - } - - @Override - public PackageImpl setMemtagMode(@ApplicationInfo.MemtagMode int value) { - memtagMode = value; - return this; - } - - @Override - public PackageImpl setMetaData(@Nullable Bundle value) { - metaData = value; - return this; - } - - @Override - public PackageImpl setMinAspectRatio(float value) { - minAspectRatio = value; - return this; - } - - @Override - public PackageImpl setMinExtensionVersions(@Nullable SparseIntArray value) { - minExtensionVersions = value; - return this; - } - - @Override - public PackageImpl setMinSdkVersion(int value) { - minSdkVersion = value; - return this; - } - - @Override - public PackageImpl setMultiArch(boolean value) { - return setBoolean(Booleans.MULTI_ARCH, value); - } - - @Override - public PackageImpl setNativeHeapZeroInitialized( - @ApplicationInfo.NativeHeapZeroInitialized int value) { - nativeHeapZeroInitialized = value; - return this; - } - - @Override - public PackageImpl setNetworkSecurityConfigResourceId(int value) { - networkSecurityConfigRes = value; - return this; - } - - @Override - public PackageImpl setNonLocalizedLabel(@Nullable CharSequence value) { - nonLocalizedLabel = value == null ? null : value.toString().trim(); - return this; - } - - @Override - public ParsingPackage setOnBackInvokedCallbackEnabled(boolean value) { - setBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK, value); - return this; - } - - @Override - public PackageImpl setResourceOverlay(boolean value) { - return setBoolean(Booleans.OVERLAY, value); - } - - @Override - public PackageImpl setOverlayCategory(@Nullable String overlayCategory) { - this.overlayCategory = overlayCategory; - return this; - } - - @Override - public PackageImpl setOverlayIsStatic(boolean value) { - return setBoolean(Booleans.OVERLAY_IS_STATIC, value); - } - - @Override - public PackageImpl setOverlayPriority(int value) { - overlayPriority = value; - return this; - } - - @Override - public PackageImpl setOverlayTarget(@Nullable String overlayTarget) { - this.overlayTarget = TextUtils.safeIntern(overlayTarget); - return this; - } - - @Override - public PackageImpl setOverlayTargetOverlayableName( - @Nullable String overlayTargetOverlayableName) { - this.overlayTargetOverlayableName = overlayTargetOverlayableName; - return this; - } - - @Override - public PackageImpl setPartiallyDirectBootAware(boolean value) { - return setBoolean(Booleans.PARTIALLY_DIRECT_BOOT_AWARE, value); - } - - @Override - public PackageImpl setPermission(@Nullable String permission) { - this.permission = permission; - return this; - } - - @Override - public PackageImpl setPreserveLegacyExternalStorage(boolean value) { - return setBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE, value); - } - - @Override - public PackageImpl setProcessName(String processName) { - this.processName = processName; - return this; - } - - @Override - public PackageImpl setProcesses(@NonNull Map value) { - processes = value; - return this; - } - - @Override - public PackageImpl setProfileable(boolean value) { - return setBoolean(Booleans.DISALLOW_PROFILING, !value); - } - - @Override - public PackageImpl setProfileableByShell(boolean value) { - return setBoolean(Booleans.PROFILEABLE_BY_SHELL, value); - } - - @Override - public PackageImpl setRequestForegroundServiceExemption(boolean value) { - return setBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION, value); - } - - @Override - public PackageImpl setRequestLegacyExternalStorage(boolean value) { - return setBoolean(Booleans.REQUEST_LEGACY_EXTERNAL_STORAGE, value); - } - - @Override - public PackageImpl setRequestRawExternalStorageAccess(@Nullable Boolean value) { - requestRawExternalStorageAccess = value; - return this; - } - - @Override - public PackageImpl setRequiredAccountType(@Nullable String requiredAccountType) { - this.requiredAccountType = TextUtils.nullIfEmpty(requiredAccountType); - return this; - } - - @Override - public PackageImpl setRequiredForAllUsers(boolean value) { - return setBoolean(Booleans.REQUIRED_FOR_ALL_USERS, value); - } - - @Override - public PackageImpl setRequiresSmallestWidthDp(int value) { - requiresSmallestWidthDp = value; - return this; - } - - @Override - public ParsingPackage setResetEnabledSettingsOnAppDataCleared( - boolean resetEnabledSettingsOnAppDataCleared) { - setBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED, - resetEnabledSettingsOnAppDataCleared); - return this; - } - - @Override - public PackageImpl setResizeable(int resizeable) { - if (resizeable == 1) { - return this; - } - - this.resizeable = resizeable < 0; - return this; - } - - @Override - public PackageImpl setResizeableActivity(@Nullable Boolean value) { - resizeableActivity = value; - return this; - } - - @Override - public PackageImpl setResizeableActivityViaSdkVersion(boolean value) { - return setBoolean(Booleans.RESIZEABLE_ACTIVITY_VIA_SDK_VERSION, value); - } - - @Override - public PackageImpl setRestoreAnyVersion(boolean value) { - return setBoolean(Booleans.RESTORE_ANY_VERSION, value); - } - - @Override - public PackageImpl setRestrictedAccountType(@Nullable String restrictedAccountType) { - this.restrictedAccountType = restrictedAccountType; - return this; - } - - @Override - public PackageImpl setRoundIconResourceId(int value) { - roundIconRes = value; - return this; - } - - @Override - public PackageImpl setSdkLibraryName(String sdkLibraryName) { - this.sdkLibraryName = TextUtils.safeIntern(sdkLibraryName); - return this; - } - - @Override - public PackageImpl setSdkLibVersionMajor(int sdkLibVersionMajor) { - this.sdkLibVersionMajor = sdkLibVersionMajor; - return this; - } - - @Override - public PackageImpl setSdkLibrary(boolean value) { - return setBoolean(Booleans.SDK_LIBRARY, value); - } - - @Override - public PackageImpl setSharedUserId(String sharedUserId) { - this.sharedUserId = TextUtils.safeIntern(sharedUserId); - return this; - } - - @Override - public PackageImpl setSharedUserLabelResourceId(int value) { - sharedUserLabel = value; - return this; - } - - @Override - public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) { - this.splitClassLoaderNames[splitIndex] = classLoaderName; - return this; - } - - @Override - public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) { - this.splitFlags[splitIndex] = splitHasCode - ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE - : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE; - return this; - } - - @Override - public PackageImpl setStaticSharedLibraryName(String staticSharedLibraryName) { - this.staticSharedLibraryName = TextUtils.safeIntern(staticSharedLibraryName); - return this; - } - - @Override - public PackageImpl setStaticSharedLibraryVersion(long value) { - staticSharedLibVersion = value; - return this; - } - - @Override - public PackageImpl setStaticSharedLibrary(boolean value) { - return setBoolean(Booleans.STATIC_SHARED_LIBRARY, value); - } - - @Override - public PackageImpl setExtraLargeScreensSupported(int supportsExtraLargeScreens) { - if (supportsExtraLargeScreens == 1) { - return this; - } - - this.supportsExtraLargeScreens = supportsExtraLargeScreens < 0; - return this; - } - - @Override - public PackageImpl setLargeScreensSupported(int supportsLargeScreens) { - if (supportsLargeScreens == 1) { - return this; - } - - this.supportsLargeScreens = supportsLargeScreens < 0; - return this; - } - - @Override - public PackageImpl setNormalScreensSupported(int supportsNormalScreens) { - if (supportsNormalScreens == 1) { - return this; - } - - this.supportsNormalScreens = supportsNormalScreens < 0; - return this; - } - - @Override - public PackageImpl setRtlSupported(boolean value) { - return setBoolean(Booleans.SUPPORTS_RTL, value); - } - - @Override - public PackageImpl setSmallScreensSupported(int supportsSmallScreens) { - if (supportsSmallScreens == 1) { - return this; - } - - this.supportsSmallScreens = supportsSmallScreens < 0; - return this; - } - - @Override - public PackageImpl setTargetSandboxVersion(int value) { - targetSandboxVersion = value; - return this; - } - - @Override - public PackageImpl setTargetSdkVersion(int value) { - targetSdkVersion = value; - return this; - } - - @Override - public PackageImpl setTaskAffinity(@Nullable String taskAffinity) { - this.taskAffinity = taskAffinity; - return this; - } - - @Override - public PackageImpl setTestOnly(boolean value) { - return setBoolean(Booleans.TEST_ONLY, value); - } - - @Override - public PackageImpl setThemeResourceId(int value) { - theme = value; - return this; - } - - @Override - public PackageImpl setUiOptions(int value) { - uiOptions = value; - return this; - } - - @Override - public PackageImpl setUpgradeKeySets(@NonNull Set value) { - upgradeKeySets = value; - return this; - } - - @Override - public PackageImpl set32BitAbiPreferred(boolean value) { - return setBoolean(Booleans.USE_32_BIT_ABI, value); - } - - @Override - public PackageImpl setUseEmbeddedDex(boolean value) { - return setBoolean(Booleans.USE_EMBEDDED_DEX, value); - } - - @Override - public PackageImpl setCleartextTrafficAllowed(boolean value) { - return setBoolean(Booleans.USES_CLEARTEXT_TRAFFIC, value); - } - - @Override - public PackageImpl setNonSdkApiRequested(boolean value) { - return setBoolean(Booleans.USES_NON_SDK_API, value); - } - - @Override - public PackageImpl setVersionName(String versionName) { - this.versionName = versionName; - return this; - } - - @Override - public PackageImpl setVisibleToInstantApps(boolean value) { - return setBoolean(Booleans.VISIBLE_TO_INSTANT_APPS, value); - } - - @Override - public PackageImpl setVmSafeMode(boolean value) { - return setBoolean(Booleans.VM_SAFE_MODE, value); - } - - @Override - public PackageImpl setVolumeUuid(@Nullable String volumeUuid) { - this.volumeUuid = TextUtils.safeIntern(volumeUuid); - return this; - } - - @Override - public PackageImpl setZygotePreloadName(@Nullable String zygotePreloadName) { - this.zygotePreloadName = zygotePreloadName; - return this; - } - - @Override - public PackageImpl sortActivities() { - Collections.sort(this.activities, ORDER_COMPARATOR); - return this; - } - - @Override - public PackageImpl sortReceivers() { - Collections.sort(this.receivers, ORDER_COMPARATOR); - return this; - } - - @Override - public PackageImpl sortServices() { - Collections.sort(this.services, ORDER_COMPARATOR); - return this; - } - - public ApplicationInfo toAppInfoWithoutStateWithoutFlags() { - ApplicationInfo appInfo = new ApplicationInfo(); - - // Lines that are commented below are state related and should not be assigned here. - // They are left in as placeholders, since there is no good backwards compatible way to - // separate these. - appInfo.appComponentFactory = appComponentFactory; - appInfo.backupAgentName = backupAgentName; - appInfo.banner = banner; - appInfo.category = category; - appInfo.classLoaderName = classLoaderName; - appInfo.className = className; - appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp; - appInfo.compileSdkVersion = compileSdkVersion; - appInfo.compileSdkVersionCodename = compileSdkVersionCodeName; -// appInfo.credentialProtectedDataDir - appInfo.crossProfile = isCrossProfile(); -// appInfo.dataDir - appInfo.descriptionRes = descriptionRes; -// appInfo.deviceProtectedDataDir - appInfo.enabled = getBoolean(Booleans.ENABLED); -// appInfo.enabledSetting - appInfo.fullBackupContent = fullBackupContent; - appInfo.dataExtractionRulesRes = dataExtractionRules; - // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy -// appInfo.mHiddenApiPolicy -// appInfo.hiddenUntilInstalled - appInfo.icon = - (ParsingPackageUtils.sUseRoundIcon && roundIconRes != 0) ? roundIconRes : iconRes; - appInfo.iconRes = iconRes; - appInfo.roundIconRes = roundIconRes; - appInfo.installLocation = installLocation; - appInfo.labelRes = labelRes; - appInfo.largestWidthLimitDp = largestWidthLimitDp; - appInfo.logo = logo; - appInfo.manageSpaceActivityName = manageSpaceActivityName; - appInfo.maxAspectRatio = maxAspectRatio; - appInfo.metaData = metaData; - appInfo.minAspectRatio = minAspectRatio; - appInfo.minSdkVersion = minSdkVersion; - appInfo.name = className; -// appInfo.nativeLibraryDir -// appInfo.nativeLibraryRootDir -// appInfo.nativeLibraryRootRequiresIsa - appInfo.networkSecurityConfigRes = networkSecurityConfigRes; - appInfo.nonLocalizedLabel = nonLocalizedLabel; - appInfo.packageName = packageName; - appInfo.permission = permission; -// appInfo.primaryCpuAbi - appInfo.processName = getProcessName(); - appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp; -// appInfo.resourceDirs -// appInfo.secondaryCpuAbi -// appInfo.secondaryNativeLibraryDir -// appInfo.seInfo -// appInfo.seInfoUser -// appInfo.sharedLibraryFiles -// appInfo.sharedLibraryInfos -// appInfo.showUserIcon - appInfo.splitClassLoaderNames = splitClassLoaderNames; - appInfo.splitDependencies = (splitDependencies == null || splitDependencies.size() == 0) - ? null : splitDependencies; - appInfo.splitNames = splitNames; - appInfo.storageUuid = mStorageUuid; - appInfo.targetSandboxVersion = targetSandboxVersion; - appInfo.targetSdkVersion = targetSdkVersion; - appInfo.taskAffinity = taskAffinity; - appInfo.theme = theme; -// appInfo.uid - appInfo.uiOptions = uiOptions; - appInfo.volumeUuid = volumeUuid; - appInfo.zygotePreloadName = zygotePreloadName; - appInfo.setGwpAsanMode(gwpAsanMode); - appInfo.setMemtagMode(memtagMode); - appInfo.setNativeHeapZeroInitialized(nativeHeapZeroInitialized); - appInfo.setRequestRawExternalStorageAccess(requestRawExternalStorageAccess); - appInfo.setBaseCodePath(mBaseApkPath); - appInfo.setBaseResourcePath(mBaseApkPath); - appInfo.setCodePath(mPath); - appInfo.setResourcePath(mPath); - appInfo.setSplitCodePaths(ArrayUtils.size(splitCodePaths) == 0 ? null : splitCodePaths); - appInfo.setSplitResourcePaths(ArrayUtils.size(splitCodePaths) == 0 ? null : splitCodePaths); - appInfo.setVersionCode(mLongVersionCode); - appInfo.setAppClassNamesByProcess(buildAppClassNamesByProcess()); - appInfo.setLocaleConfigRes(mLocaleConfigRes); - if (!mKnownActivityEmbeddingCerts.isEmpty()) { - appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts); - } - - return appInfo; - } - - private PackageImpl setBoolean(@Booleans.Flags long flag, boolean value) { - if (value) { - mBooleans |= flag; - } else { - mBooleans &= ~flag; - } - return this; - } - - private boolean getBoolean(@Booleans.Flags long flag) { - return (mBooleans & flag) != 0; - } - - private PackageImpl setBoolean2(@Booleans2.Flags long flag, boolean value) { - if (value) { - mBooleans2 |= flag; - } else { - mBooleans2 &= ~flag; - } - return this; - } - - private boolean getBoolean2(@Booleans2.Flags long flag) { - return (mBooleans2 & flag) != 0; - } - - // Derived fields - private int mBaseAppInfoFlags; - private int mBaseAppInfoPrivateFlags; - private int mBaseAppInfoPrivateFlagsExt; - private String mBaseAppDataCredentialProtectedDirForSystemUser; - private String mBaseAppDataDeviceProtectedDirForSystemUser; - - @VisibleForTesting - public PackageImpl(@NonNull String packageName, @NonNull String baseApkPath, - @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp) { - this.packageName = TextUtils.safeIntern(packageName); - this.mBaseApkPath = baseApkPath; - this.mPath = path; - - if (manifestArray != null) { - versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0); - versionCodeMajor = manifestArray.getInteger( - R.styleable.AndroidManifest_versionCodeMajor, 0); - setBaseRevisionCode( - manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, 0)); - setVersionName(manifestArray.getNonConfigurationString( - R.styleable.AndroidManifest_versionName, 0)); - - setCompileSdkVersion(manifestArray.getInteger( - R.styleable.AndroidManifest_compileSdkVersion, 0)); - setCompileSdkVersionCodeName(manifestArray.getNonConfigurationString( - R.styleable.AndroidManifest_compileSdkVersionCodename, 0)); - - setIsolatedSplitLoading(manifestArray.getBoolean( - R.styleable.AndroidManifest_isolatedSplits, false)); - - } - this.manifestPackageName = this.packageName; - setBoolean(Booleans.CORE_APP, isCoreApp); - } - - @Override - public PackageImpl hideAsParsed() { - assignDerivedFields(); - return this; - } - - @Override - public AndroidPackageInternal hideAsFinal() { - if (mStorageUuid == null) { - assignDerivedFields(); - } - assignDerivedFields2(); - makeImmutable(); - return this; - } - - private static String[] sortLibraries(List libraryNames) { - int size = libraryNames.size(); - if (size == 0) { - return EmptyArray.STRING; - } - var arr = libraryNames.toArray(EmptyArray.STRING); - Arrays.sort(arr); - return arr; - } - - private void assignDerivedFields2() { - mBaseAppInfoFlags = PackageInfoUtils.appInfoFlags(this, null); - mBaseAppInfoPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null); - mBaseAppInfoPrivateFlagsExt = PackageInfoUtils.appInfoPrivateFlagsExt(this, null); - String baseAppDataDir = Environment.getDataDirectoryPath(getVolumeUuid()) + File.separator; - String systemUserSuffix = File.separator + UserHandle.USER_SYSTEM + File.separator; - mBaseAppDataCredentialProtectedDirForSystemUser = TextUtils.safeIntern( - baseAppDataDir + Environment.DIR_USER_CE + systemUserSuffix); - mBaseAppDataDeviceProtectedDirForSystemUser = TextUtils.safeIntern( - baseAppDataDir + Environment.DIR_USER_DE + systemUserSuffix); - } - - private void makeImmutable() { - usesLibraries = Collections.unmodifiableList(usesLibraries); - usesOptionalLibraries = Collections.unmodifiableList(usesOptionalLibraries); - usesNativeLibraries = Collections.unmodifiableList(usesNativeLibraries); - usesOptionalNativeLibraries = Collections.unmodifiableList(usesOptionalNativeLibraries); - originalPackages = Collections.unmodifiableList(originalPackages); - adoptPermissions = Collections.unmodifiableList(adoptPermissions); - requestedPermissions = Collections.unmodifiableSet(requestedPermissions); - protectedBroadcasts = Collections.unmodifiableList(protectedBroadcasts); - apexSystemServices = Collections.unmodifiableList(apexSystemServices); - - activities = Collections.unmodifiableList(activities); - receivers = Collections.unmodifiableList(receivers); - services = Collections.unmodifiableList(services); - providers = Collections.unmodifiableList(providers); - permissions = Collections.unmodifiableList(permissions); - permissionGroups = Collections.unmodifiableList(permissionGroups); - instrumentations = Collections.unmodifiableList(instrumentations); - - overlayables = Collections.unmodifiableMap(overlayables); - libraryNames = Collections.unmodifiableList(libraryNames); - usesStaticLibraries = Collections.unmodifiableList(usesStaticLibraries); - usesSdkLibraries = Collections.unmodifiableList(usesSdkLibraries); - configPreferences = Collections.unmodifiableList(configPreferences); - reqFeatures = Collections.unmodifiableList(reqFeatures); - featureGroups = Collections.unmodifiableList(featureGroups); - usesPermissions = Collections.unmodifiableList(usesPermissions); - usesSdkLibraries = Collections.unmodifiableList(usesSdkLibraries); - implicitPermissions = Collections.unmodifiableSet(implicitPermissions); - upgradeKeySets = Collections.unmodifiableSet(upgradeKeySets); - keySetMapping = Collections.unmodifiableMap(keySetMapping); - attributions = Collections.unmodifiableList(attributions); - preferredActivityFilters = Collections.unmodifiableList(preferredActivityFilters); - processes = Collections.unmodifiableMap(processes); - mProperties = Collections.unmodifiableMap(mProperties); - queriesIntents = Collections.unmodifiableList(queriesIntents); - queriesPackages = Collections.unmodifiableList(queriesPackages); - queriesProviders = Collections.unmodifiableSet(queriesProviders); - mimeGroups = Collections.unmodifiableSet(mimeGroups); - mKnownActivityEmbeddingCerts = Collections.unmodifiableSet(mKnownActivityEmbeddingCerts); - } - - @Override - public long getLongVersionCode() { - return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); - } - - @Override - public PackageImpl removePermission(int index) { - this.permissions.remove(index); - return this; - } - - @Override - public PackageImpl addUsesOptionalLibrary(int index, String libraryName) { - this.usesOptionalLibraries = CollectionUtils.add(usesOptionalLibraries, index, - TextUtils.safeIntern(libraryName)); - return this; - } - - @Override - public PackageImpl addUsesLibrary(int index, String libraryName) { - this.usesLibraries = CollectionUtils.add(usesLibraries, index, - TextUtils.safeIntern(libraryName)); - return this; - } - - @Override - public PackageImpl removeUsesLibrary(String libraryName) { - this.usesLibraries = CollectionUtils.remove(this.usesLibraries, libraryName); - return this; - } - - @Override - public PackageImpl removeUsesOptionalLibrary(String libraryName) { - this.usesOptionalLibraries = CollectionUtils.remove(this.usesOptionalLibraries, - libraryName); - return this; - } - - @Override - public PackageImpl setSigningDetails(@NonNull SigningDetails value) { - signingDetails = value; - return this; - } - - @Override - public PackageImpl setRestrictUpdateHash(@Nullable byte... value) { - restrictUpdateHash = value; - return this; - } - - @Override - public PackageImpl setPersistent(boolean value) { - setBoolean(Booleans.PERSISTENT, value); - return this; - } - - @Override - public PackageImpl setDefaultToDeviceProtectedStorage(boolean value) { - setBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE, value); - return this; - } - - @Override - public PackageImpl setDirectBootAware(boolean value) { - setBoolean(Booleans.DIRECT_BOOT_AWARE, value); - return this; - } - - @Override - public PackageImpl clearProtectedBroadcasts() { - protectedBroadcasts.clear(); - return this; - } - - @Override - public PackageImpl clearOriginalPackages() { - originalPackages.clear(); - return this; - } - - @Override - public PackageImpl clearAdoptPermissions() { - adoptPermissions.clear(); - return this; - } - - @Override - public PackageImpl setPath(@NonNull String path) { - this.mPath = path; - return this; - } - - // TODO(b/135203078): Move PackageManagerService#renameStaticSharedLibraryPackage - // into initial package parsing - @Override - public PackageImpl setPackageName(@NonNull String packageName) { - this.packageName = TextUtils.safeIntern(packageName); - - int permissionsSize = permissions.size(); - for (int index = 0; index < permissionsSize; index++) { - ComponentMutateUtils.setPackageName(permissions.get(index), this.packageName); - } - - int permissionGroupsSize = permissionGroups.size(); - for (int index = 0; index < permissionGroupsSize; index++) { - ComponentMutateUtils.setPackageName(permissionGroups.get(index), this.packageName); - } - - int activitiesSize = activities.size(); - for (int index = 0; index < activitiesSize; index++) { - ComponentMutateUtils.setPackageName(activities.get(index), this.packageName); - } - - int receiversSize = receivers.size(); - for (int index = 0; index < receiversSize; index++) { - ComponentMutateUtils.setPackageName(receivers.get(index), this.packageName); - } - - int providersSize = providers.size(); - for (int index = 0; index < providersSize; index++) { - ComponentMutateUtils.setPackageName(providers.get(index), this.packageName); - } - - int servicesSize = services.size(); - for (int index = 0; index < servicesSize; index++) { - ComponentMutateUtils.setPackageName(services.get(index), this.packageName); - } - - int instrumentationsSize = instrumentations.size(); - for (int index = 0; index < instrumentationsSize; index++) { - ComponentMutateUtils.setPackageName(instrumentations.get(index), this.packageName); - } - - return this; - } - - @Override - public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) { - int activitiesSize = activities.size(); - for (int index = 0; index < activitiesSize; index++) { - ComponentMutateUtils.setDirectBootAware(activities.get(index), - allComponentsDirectBootAware); - } - - int receiversSize = receivers.size(); - for (int index = 0; index < receiversSize; index++) { - ComponentMutateUtils.setDirectBootAware(receivers.get(index), - allComponentsDirectBootAware); - } - - int providersSize = providers.size(); - for (int index = 0; index < providersSize; index++) { - ComponentMutateUtils.setDirectBootAware(providers.get(index), - allComponentsDirectBootAware); - } - - int servicesSize = services.size(); - for (int index = 0; index < servicesSize; index++) { - ComponentMutateUtils.setDirectBootAware(services.get(index), - allComponentsDirectBootAware); - } - - return this; - } - - @Override - public PackageImpl setBaseApkPath(@NonNull String baseApkPath) { - this.mBaseApkPath = TextUtils.safeIntern(baseApkPath); - return this; - } - - @Override - public PackageImpl setNativeLibraryDir(@Nullable String nativeLibraryDir) { - this.nativeLibraryDir = TextUtils.safeIntern(nativeLibraryDir); - return this; - } - - @Override - public PackageImpl setNativeLibraryRootDir(@Nullable String nativeLibraryRootDir) { - this.nativeLibraryRootDir = TextUtils.safeIntern(nativeLibraryRootDir); - return this; - } - - @Override - public PackageImpl setPrimaryCpuAbi(@Nullable String primaryCpuAbi) { - this.primaryCpuAbi = TextUtils.safeIntern(primaryCpuAbi); - return this; - } - - @Override - public PackageImpl setSecondaryCpuAbi(@Nullable String secondaryCpuAbi) { - this.secondaryCpuAbi = TextUtils.safeIntern(secondaryCpuAbi); - return this; - } - - @Override - public PackageImpl setSecondaryNativeLibraryDir(@Nullable String secondaryNativeLibraryDir) { - this.secondaryNativeLibraryDir = TextUtils.safeIntern(secondaryNativeLibraryDir); - return this; - } - - @Override - public PackageImpl setSplitCodePaths(@Nullable String[] splitCodePaths) { - this.splitCodePaths = splitCodePaths; - if (splitCodePaths != null) { - int size = splitCodePaths.length; - for (int index = 0; index < size; index++) { - this.splitCodePaths[index] = TextUtils.safeIntern(this.splitCodePaths[index]); - } - } - return this; - } - - @Override - public PackageImpl capPermissionPriorities() { - int size = permissionGroups.size(); - for (int index = size - 1; index >= 0; --index) { - // TODO(b/135203078): Builder/immutability - ComponentMutateUtils.setPriority(permissionGroups.get(index), 0); - } - return this; - } - - @Override - public PackageImpl markNotActivitiesAsNotExportedIfSingleUser() { - // ignore export request for single user receivers - int receiversSize = receivers.size(); - for (int index = 0; index < receiversSize; index++) { - ParsedActivity receiver = receivers.get(index); - if ((receiver.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { - ComponentMutateUtils.setExported(receiver, false); - } - } - - // ignore export request for single user services - int servicesSize = services.size(); - for (int index = 0; index < servicesSize; index++) { - ParsedService service = services.get(index); - if ((service.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { - ComponentMutateUtils.setExported(service, false); - } - } - - // ignore export request for single user providers - int providersSize = providers.size(); - for (int index = 0; index < providersSize; index++) { - ParsedProvider provider = providers.get(index); - if ((provider.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) { - ComponentMutateUtils.setExported(provider, false); - } - } - - return this; - } - - @Override - public PackageImpl setCoreApp(boolean coreApp) { - return setBoolean(Booleans.CORE_APP, coreApp); - } - - @Override - public PackageImpl setVersionCode(int versionCode) { - this.versionCode = versionCode; - return this; - } - - @Override - public PackageImpl setVersionCodeMajor(int versionCodeMajor) { - this.versionCodeMajor = versionCodeMajor; - return this; - } - - @Override - public ApplicationInfo toAppInfoWithoutState() { - ApplicationInfo appInfo = toAppInfoWithoutStateWithoutFlags(); - appInfo.flags = mBaseAppInfoFlags; - appInfo.privateFlags = mBaseAppInfoPrivateFlags; - appInfo.privateFlagsExt = mBaseAppInfoPrivateFlagsExt; - appInfo.nativeLibraryDir = nativeLibraryDir; - appInfo.nativeLibraryRootDir = nativeLibraryRootDir; - appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; - appInfo.primaryCpuAbi = primaryCpuAbi; - appInfo.secondaryCpuAbi = secondaryCpuAbi; - appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; - appInfo.seInfoUser = SELinuxUtil.COMPLETE_STR; - appInfo.uid = uid; - return appInfo; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - sForBoolean.parcel(this.supportsSmallScreens, dest, flags); - sForBoolean.parcel(this.supportsNormalScreens, dest, flags); - sForBoolean.parcel(this.supportsLargeScreens, dest, flags); - sForBoolean.parcel(this.supportsExtraLargeScreens, dest, flags); - sForBoolean.parcel(this.resizeable, dest, flags); - sForBoolean.parcel(this.anyDensity, dest, flags); - dest.writeInt(this.versionCode); - dest.writeInt(this.versionCodeMajor); - dest.writeInt(this.baseRevisionCode); - sForInternedString.parcel(this.versionName, dest, flags); - dest.writeInt(this.compileSdkVersion); - dest.writeString(this.compileSdkVersionCodeName); - sForInternedString.parcel(this.packageName, dest, flags); - dest.writeString(this.mBaseApkPath); - dest.writeString(this.restrictedAccountType); - dest.writeString(this.requiredAccountType); - sForInternedString.parcel(this.overlayTarget, dest, flags); - dest.writeString(this.overlayTargetOverlayableName); - dest.writeString(this.overlayCategory); - dest.writeInt(this.overlayPriority); - sForInternedStringValueMap.parcel(this.overlayables, dest, flags); - sForInternedString.parcel(this.sdkLibraryName, dest, flags); - dest.writeInt(this.sdkLibVersionMajor); - sForInternedString.parcel(this.staticSharedLibraryName, dest, flags); - dest.writeLong(this.staticSharedLibVersion); - sForInternedStringList.parcel(this.libraryNames, dest, flags); - sForInternedStringList.parcel(this.usesLibraries, dest, flags); - sForInternedStringList.parcel(this.usesOptionalLibraries, dest, flags); - sForInternedStringList.parcel(this.usesNativeLibraries, dest, flags); - sForInternedStringList.parcel(this.usesOptionalNativeLibraries, dest, flags); - - sForInternedStringList.parcel(this.usesStaticLibraries, dest, flags); - dest.writeLongArray(this.usesStaticLibrariesVersions); - if (this.usesStaticLibrariesCertDigests == null) { - dest.writeInt(-1); - } else { - dest.writeInt(this.usesStaticLibrariesCertDigests.length); - for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) { - dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]); - } - } - - sForInternedStringList.parcel(this.usesSdkLibraries, dest, flags); - dest.writeLongArray(this.usesSdkLibrariesVersionsMajor); - if (this.usesSdkLibrariesCertDigests == null) { - dest.writeInt(-1); - } else { - dest.writeInt(this.usesSdkLibrariesCertDigests.length); - for (int index = 0; index < this.usesSdkLibrariesCertDigests.length; index++) { - dest.writeStringArray(this.usesSdkLibrariesCertDigests[index]); - } - } - dest.writeBooleanArray(this.usesSdkLibrariesOptional); - - sForInternedString.parcel(this.sharedUserId, dest, flags); - dest.writeInt(this.sharedUserLabel); - dest.writeTypedList(this.configPreferences); - dest.writeTypedList(this.reqFeatures); - dest.writeTypedList(this.featureGroups); - dest.writeByteArray(this.restrictUpdateHash); - dest.writeStringList(this.originalPackages); - sForInternedStringList.parcel(this.adoptPermissions, dest, flags); - sForInternedStringSet.parcel(this.requestedPermissions, dest, flags); - ParsingUtils.writeParcelableList(dest, this.usesPermissions); - sForInternedStringSet.parcel(this.implicitPermissions, dest, flags); - sForStringSet.parcel(this.upgradeKeySets, dest, flags); - ParsingPackageUtils.writeKeySetMapping(dest, this.keySetMapping); - sForInternedStringList.parcel(this.protectedBroadcasts, dest, flags); - ParsingUtils.writeParcelableList(dest, this.activities); - ParsingUtils.writeParcelableList(dest, this.apexSystemServices); - ParsingUtils.writeParcelableList(dest, this.receivers); - ParsingUtils.writeParcelableList(dest, this.services); - ParsingUtils.writeParcelableList(dest, this.providers); - ParsingUtils.writeParcelableList(dest, this.attributions); - ParsingUtils.writeParcelableList(dest, this.permissions); - ParsingUtils.writeParcelableList(dest, this.permissionGroups); - ParsingUtils.writeParcelableList(dest, this.instrumentations); - sForIntentInfoPairs.parcel(this.preferredActivityFilters, dest, flags); - dest.writeMap(this.processes); - dest.writeBundle(this.metaData); - sForInternedString.parcel(this.volumeUuid, dest, flags); - dest.writeParcelable(this.signingDetails, flags); - dest.writeString(this.mPath); - dest.writeTypedList(this.queriesIntents, flags); - sForInternedStringList.parcel(this.queriesPackages, dest, flags); - sForInternedStringSet.parcel(this.queriesProviders, dest, flags); - dest.writeString(this.appComponentFactory); - dest.writeString(this.backupAgentName); - dest.writeInt(this.banner); - dest.writeInt(this.category); - dest.writeString(this.classLoaderName); - dest.writeString(this.className); - dest.writeInt(this.compatibleWidthLimitDp); - dest.writeInt(this.descriptionRes); - dest.writeInt(this.fullBackupContent); - dest.writeInt(this.dataExtractionRules); - dest.writeInt(this.iconRes); - dest.writeInt(this.installLocation); - dest.writeInt(this.labelRes); - dest.writeInt(this.largestWidthLimitDp); - dest.writeInt(this.logo); - dest.writeString(this.manageSpaceActivityName); - dest.writeFloat(this.maxAspectRatio); - dest.writeFloat(this.minAspectRatio); - dest.writeInt(this.minSdkVersion); - dest.writeInt(this.maxSdkVersion); - dest.writeInt(this.networkSecurityConfigRes); - dest.writeCharSequence(this.nonLocalizedLabel); - dest.writeString(this.permission); - dest.writeString(this.processName); - dest.writeInt(this.requiresSmallestWidthDp); - dest.writeInt(this.roundIconRes); - dest.writeInt(this.targetSandboxVersion); - dest.writeInt(this.targetSdkVersion); - dest.writeString(this.taskAffinity); - dest.writeInt(this.theme); - dest.writeInt(this.uiOptions); - dest.writeString(this.zygotePreloadName); - dest.writeStringArray(this.splitClassLoaderNames); - dest.writeStringArray(this.splitCodePaths); - dest.writeSparseArray(this.splitDependencies); - dest.writeIntArray(this.splitFlags); - dest.writeStringArray(this.splitNames); - dest.writeIntArray(this.splitRevisionCodes); - sForBoolean.parcel(this.resizeableActivity, dest, flags); - dest.writeInt(this.autoRevokePermissions); - sForInternedStringSet.parcel(this.mimeGroups, dest, flags); - dest.writeInt(this.gwpAsanMode); - dest.writeSparseIntArray(this.minExtensionVersions); - dest.writeMap(this.mProperties); - dest.writeInt(this.memtagMode); - dest.writeInt(this.nativeHeapZeroInitialized); - sForBoolean.parcel(this.requestRawExternalStorageAccess, dest, flags); - dest.writeInt(this.mLocaleConfigRes); - sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags); - sForInternedString.parcel(this.manifestPackageName, dest, flags); - dest.writeString(this.nativeLibraryDir); - dest.writeString(this.nativeLibraryRootDir); - dest.writeBoolean(this.nativeLibraryRootRequiresIsa); - sForInternedString.parcel(this.primaryCpuAbi, dest, flags); - sForInternedString.parcel(this.secondaryCpuAbi, dest, flags); - dest.writeString(this.secondaryNativeLibraryDir); - dest.writeInt(this.uid); - dest.writeLong(this.mBooleans); - dest.writeLong(this.mBooleans2); - } - - public PackageImpl(Parcel in) { - // We use the boot classloader for all classes that we load. - final ClassLoader boot = Object.class.getClassLoader(); - this.supportsSmallScreens = sForBoolean.unparcel(in); - this.supportsNormalScreens = sForBoolean.unparcel(in); - this.supportsLargeScreens = sForBoolean.unparcel(in); - this.supportsExtraLargeScreens = sForBoolean.unparcel(in); - this.resizeable = sForBoolean.unparcel(in); - this.anyDensity = sForBoolean.unparcel(in); - this.versionCode = in.readInt(); - this.versionCodeMajor = in.readInt(); - this.baseRevisionCode = in.readInt(); - this.versionName = sForInternedString.unparcel(in); - this.compileSdkVersion = in.readInt(); - this.compileSdkVersionCodeName = in.readString(); - this.packageName = sForInternedString.unparcel(in); - this.mBaseApkPath = in.readString(); - this.restrictedAccountType = in.readString(); - this.requiredAccountType = in.readString(); - this.overlayTarget = sForInternedString.unparcel(in); - this.overlayTargetOverlayableName = in.readString(); - this.overlayCategory = in.readString(); - this.overlayPriority = in.readInt(); - this.overlayables = sForInternedStringValueMap.unparcel(in); - this.sdkLibraryName = sForInternedString.unparcel(in); - this.sdkLibVersionMajor = in.readInt(); - this.staticSharedLibraryName = sForInternedString.unparcel(in); - this.staticSharedLibVersion = in.readLong(); - this.libraryNames = sForInternedStringList.unparcel(in); - this.usesLibraries = sForInternedStringList.unparcel(in); - this.usesOptionalLibraries = sForInternedStringList.unparcel(in); - this.usesNativeLibraries = sForInternedStringList.unparcel(in); - this.usesOptionalNativeLibraries = sForInternedStringList.unparcel(in); - - this.usesStaticLibraries = sForInternedStringList.unparcel(in); - this.usesStaticLibrariesVersions = in.createLongArray(); - { - int digestsSize = in.readInt(); - if (digestsSize >= 0) { - this.usesStaticLibrariesCertDigests = new String[digestsSize][]; - for (int index = 0; index < digestsSize; index++) { - this.usesStaticLibrariesCertDigests[index] = sForInternedStringArray.unparcel( - in); - } - } - } - - this.usesSdkLibraries = sForInternedStringList.unparcel(in); - this.usesSdkLibrariesVersionsMajor = in.createLongArray(); - { - int digestsSize = in.readInt(); - if (digestsSize >= 0) { - this.usesSdkLibrariesCertDigests = new String[digestsSize][]; - for (int index = 0; index < digestsSize; index++) { - this.usesSdkLibrariesCertDigests[index] = sForInternedStringArray.unparcel(in); - } - } - } - this.usesSdkLibrariesOptional = in.createBooleanArray(); - - this.sharedUserId = sForInternedString.unparcel(in); - this.sharedUserLabel = in.readInt(); - this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR); - this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR); - this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR); - this.restrictUpdateHash = in.createByteArray(); - this.originalPackages = in.createStringArrayList(); - this.adoptPermissions = sForInternedStringList.unparcel(in); - this.requestedPermissions = sForInternedStringSet.unparcel(in); - this.usesPermissions = ParsingUtils.createTypedInterfaceList(in, - ParsedUsesPermissionImpl.CREATOR); - this.implicitPermissions = sForInternedStringSet.unparcel(in); - this.upgradeKeySets = sForStringSet.unparcel(in); - this.keySetMapping = ParsingPackageUtils.readKeySetMapping(in); - this.protectedBroadcasts = sForInternedStringList.unparcel(in); - - this.activities = ParsingUtils.createTypedInterfaceList(in, ParsedActivityImpl.CREATOR); - this.apexSystemServices = ParsingUtils.createTypedInterfaceList(in, - ParsedApexSystemServiceImpl.CREATOR); - this.receivers = ParsingUtils.createTypedInterfaceList(in, ParsedActivityImpl.CREATOR); - this.services = ParsingUtils.createTypedInterfaceList(in, ParsedServiceImpl.CREATOR); - this.providers = ParsingUtils.createTypedInterfaceList(in, ParsedProviderImpl.CREATOR); - this.attributions = ParsingUtils.createTypedInterfaceList(in, - ParsedAttributionImpl.CREATOR); - this.permissions = ParsingUtils.createTypedInterfaceList(in, ParsedPermissionImpl.CREATOR); - this.permissionGroups = ParsingUtils.createTypedInterfaceList(in, - ParsedPermissionGroupImpl.CREATOR); - this.instrumentations = ParsingUtils.createTypedInterfaceList(in, - ParsedInstrumentationImpl.CREATOR); - this.preferredActivityFilters = sForIntentInfoPairs.unparcel(in); - this.processes = in.readHashMap(ParsedProcessImpl.class.getClassLoader()); - this.metaData = in.readBundle(boot); - this.volumeUuid = sForInternedString.unparcel(in); - this.signingDetails = in.readParcelable(boot, android.content.pm.SigningDetails.class); - this.mPath = in.readString(); - this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); - this.queriesPackages = sForInternedStringList.unparcel(in); - this.queriesProviders = sForInternedStringSet.unparcel(in); - this.appComponentFactory = in.readString(); - this.backupAgentName = in.readString(); - this.banner = in.readInt(); - this.category = in.readInt(); - this.classLoaderName = in.readString(); - this.className = in.readString(); - this.compatibleWidthLimitDp = in.readInt(); - this.descriptionRes = in.readInt(); - this.fullBackupContent = in.readInt(); - this.dataExtractionRules = in.readInt(); - this.iconRes = in.readInt(); - this.installLocation = in.readInt(); - this.labelRes = in.readInt(); - this.largestWidthLimitDp = in.readInt(); - this.logo = in.readInt(); - this.manageSpaceActivityName = in.readString(); - this.maxAspectRatio = in.readFloat(); - this.minAspectRatio = in.readFloat(); - this.minSdkVersion = in.readInt(); - this.maxSdkVersion = in.readInt(); - this.networkSecurityConfigRes = in.readInt(); - this.nonLocalizedLabel = in.readCharSequence(); - this.permission = in.readString(); - this.processName = in.readString(); - this.requiresSmallestWidthDp = in.readInt(); - this.roundIconRes = in.readInt(); - this.targetSandboxVersion = in.readInt(); - this.targetSdkVersion = in.readInt(); - this.taskAffinity = in.readString(); - this.theme = in.readInt(); - this.uiOptions = in.readInt(); - this.zygotePreloadName = in.readString(); - this.splitClassLoaderNames = in.createStringArray(); - this.splitCodePaths = in.createStringArray(); - this.splitDependencies = in.readSparseArray(boot); - this.splitFlags = in.createIntArray(); - this.splitNames = in.createStringArray(); - this.splitRevisionCodes = in.createIntArray(); - this.resizeableActivity = sForBoolean.unparcel(in); - - this.autoRevokePermissions = in.readInt(); - this.mimeGroups = sForInternedStringSet.unparcel(in); - this.gwpAsanMode = in.readInt(); - this.minExtensionVersions = in.readSparseIntArray(); - this.mProperties = in.readHashMap(boot); - this.memtagMode = in.readInt(); - this.nativeHeapZeroInitialized = in.readInt(); - this.requestRawExternalStorageAccess = sForBoolean.unparcel(in); - this.mLocaleConfigRes = in.readInt(); - this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in); - this.manifestPackageName = sForInternedString.unparcel(in); - this.nativeLibraryDir = in.readString(); - this.nativeLibraryRootDir = in.readString(); - this.nativeLibraryRootRequiresIsa = in.readBoolean(); - this.primaryCpuAbi = sForInternedString.unparcel(in); - this.secondaryCpuAbi = sForInternedString.unparcel(in); - this.secondaryNativeLibraryDir = in.readString(); - this.uid = in.readInt(); - this.mBooleans = in.readLong(); - this.mBooleans2 = in.readLong(); - - assignDerivedFields(); - assignDerivedFields2(); - - // Do not call makeImmutable here as cached parsing will need - // to mutate this instance before it's finalized. - } - - @NonNull - public static final Creator CREATOR = new Creator() { - @Override - public PackageImpl createFromParcel(Parcel source) { - return new PackageImpl(source); - } - - @Override - public PackageImpl[] newArray(int size) { - return new PackageImpl[size]; - } - }; - - @NonNull - @Override - public String getManifestPackageName() { - return manifestPackageName; - } - - public boolean isStub() { - return getBoolean2(Booleans2.STUB); - } - - @Nullable - @Override - public String getNativeLibraryDir() { - return nativeLibraryDir; - } - - @Nullable - @Override - public String getNativeLibraryRootDir() { - return nativeLibraryRootDir; - } - - @Override - public boolean isNativeLibraryRootRequiresIsa() { - return nativeLibraryRootRequiresIsa; - } - - @Nullable - @Override - public String getPrimaryCpuAbi() { - return primaryCpuAbi; - } - - @Nullable - @Override - public String getSecondaryCpuAbi() { - return secondaryCpuAbi; - } - - @Nullable - @Override - public String getSecondaryNativeLibraryDir() { - return secondaryNativeLibraryDir; - } - - @Override - public boolean isCoreApp() { - return getBoolean(Booleans.CORE_APP); - } - - @Override - public boolean isSystem() { - return getBoolean(Booleans.SYSTEM); - } - - @Override - public boolean isUpdatableSystem() { - return getBoolean2(Booleans2.UPDATABLE_SYSTEM); - } - - @Override - public boolean isFactoryTest() { - return getBoolean(Booleans.FACTORY_TEST); - } - - @Override - public boolean isApex() { - return getBoolean2(Booleans2.APEX); - } - - @Override - public boolean isSystemExt() { - return getBoolean(Booleans.SYSTEM_EXT); - } - - @Override - public boolean isPrivileged() { - return getBoolean(Booleans.PRIVILEGED); - } - - @Override - public boolean isOem() { - return getBoolean(Booleans.OEM); - } - - @Override - public boolean isVendor() { - return getBoolean(Booleans.VENDOR); - } - - @Override - public boolean isProduct() { - return getBoolean(Booleans.PRODUCT); - } - - @Override - public boolean isOdm() { - return getBoolean(Booleans.ODM); - } - - @Override - public boolean isSignedWithPlatformKey() { - return getBoolean(Booleans.SIGNED_WITH_PLATFORM_KEY); - } - - /** - * This is an appId, the uid if the userId is == USER_SYSTEM - */ - @Override - public int getUid() { - return uid; - } - - @Override - public PackageImpl setStub(boolean value) { - setBoolean2(Booleans2.STUB, value); - return this; - } - - @Override - public PackageImpl setNativeLibraryRootRequiresIsa(boolean value) { - nativeLibraryRootRequiresIsa = value; - return this; - } - - @Override - public PackageImpl setSystem(boolean value) { - setBoolean(Booleans.SYSTEM, value); - return this; - } - - @Override - public PackageImpl setUpdatableSystem(boolean value) { - return setBoolean2(Booleans2.UPDATABLE_SYSTEM, value); - } - - @Override - public PackageImpl setFactoryTest(boolean value) { - setBoolean(Booleans.FACTORY_TEST, value); - return this; - } - - @Override - public PackageImpl setApex(boolean isApex) { - setBoolean2(Booleans2.APEX, isApex); - return this; - } - - @Override - public PackageImpl setSystemExt(boolean value) { - setBoolean(Booleans.SYSTEM_EXT, value); - return this; - } - - @Override - public PackageImpl setPrivileged(boolean value) { - setBoolean(Booleans.PRIVILEGED, value); - return this; - } - - @Override - public PackageImpl setOem(boolean value) { - setBoolean(Booleans.OEM, value); - return this; - } - - @Override - public PackageImpl setVendor(boolean value) { - setBoolean(Booleans.VENDOR, value); - return this; - } - - @Override - public PackageImpl setProduct(boolean value) { - setBoolean(Booleans.PRODUCT, value); - return this; - } - - @Override - public PackageImpl setOdm(boolean value) { - setBoolean(Booleans.ODM, value); - return this; - } - - @Override - public PackageImpl setSignedWithPlatformKey(boolean value) { - setBoolean(Booleans.SIGNED_WITH_PLATFORM_KEY, value); - return this; - } - - @Override - public PackageImpl setUid(int value) { - uid = value; - return this; - } - - // The following methods are explicitly not inside any interface. These are hidden under - // PackageImpl which is only accessible to the system server. This is to prevent/discourage - // usage of these fields outside of the utility classes. - public String getBaseAppDataCredentialProtectedDirForSystemUser() { - return mBaseAppDataCredentialProtectedDirForSystemUser; - } - - public String getBaseAppDataDeviceProtectedDirForSystemUser() { - return mBaseAppDataDeviceProtectedDirForSystemUser; - } - - /** - * Flags used for a internal bitset. These flags should never be persisted or exposed outside - * of this class. It is expected that PackageCacher explicitly clears itself whenever the - * Parcelable implementation changes such that all these flags can be re-ordered or invalidated. - */ - private static class Booleans { - @LongDef({ - EXTERNAL_STORAGE, - HARDWARE_ACCELERATED, - ALLOW_BACKUP, - KILL_AFTER_RESTORE, - RESTORE_ANY_VERSION, - FULL_BACKUP_ONLY, - PERSISTENT, - DEBUGGABLE, - VM_SAFE_MODE, - HAS_CODE, - ALLOW_TASK_REPARENTING, - ALLOW_CLEAR_USER_DATA, - LARGE_HEAP, - USES_CLEARTEXT_TRAFFIC, - SUPPORTS_RTL, - TEST_ONLY, - MULTI_ARCH, - EXTRACT_NATIVE_LIBS, - GAME, - STATIC_SHARED_LIBRARY, - OVERLAY, - ISOLATED_SPLIT_LOADING, - HAS_DOMAIN_URLS, - PROFILEABLE_BY_SHELL, - BACKUP_IN_FOREGROUND, - USE_EMBEDDED_DEX, - DEFAULT_TO_DEVICE_PROTECTED_STORAGE, - DIRECT_BOOT_AWARE, - PARTIALLY_DIRECT_BOOT_AWARE, - RESIZEABLE_ACTIVITY_VIA_SDK_VERSION, - ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, - ALLOW_AUDIO_PLAYBACK_CAPTURE, - REQUEST_LEGACY_EXTERNAL_STORAGE, - USES_NON_SDK_API, - HAS_FRAGILE_USER_DATA, - CANT_SAVE_STATE, - ALLOW_NATIVE_HEAP_POINTER_TAGGING, - PRESERVE_LEGACY_EXTERNAL_STORAGE, - REQUIRED_FOR_ALL_USERS, - OVERLAY_IS_STATIC, - USE_32_BIT_ABI, - VISIBLE_TO_INSTANT_APPS, - FORCE_QUERYABLE, - CROSS_PROFILE, - ENABLED, - DISALLOW_PROFILING, - REQUEST_FOREGROUND_SERVICE_EXEMPTION, - ATTRIBUTIONS_ARE_USER_VISIBLE, - RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED, - SDK_LIBRARY, - CORE_APP, - SYSTEM, - FACTORY_TEST, - SYSTEM_EXT, - PRIVILEGED, - OEM, - VENDOR, - PRODUCT, - ODM, - SIGNED_WITH_PLATFORM_KEY, - NATIVE_LIBRARY_ROOT_REQUIRES_ISA, - }) - public @interface Flags {} - - private static final long EXTERNAL_STORAGE = 1L; - private static final long HARDWARE_ACCELERATED = 1L << 1; - private static final long ALLOW_BACKUP = 1L << 2; - private static final long KILL_AFTER_RESTORE = 1L << 3; - private static final long RESTORE_ANY_VERSION = 1L << 4; - private static final long FULL_BACKUP_ONLY = 1L << 5; - private static final long PERSISTENT = 1L << 6; - private static final long DEBUGGABLE = 1L << 7; - private static final long VM_SAFE_MODE = 1L << 8; - private static final long HAS_CODE = 1L << 9; - private static final long ALLOW_TASK_REPARENTING = 1L << 10; - private static final long ALLOW_CLEAR_USER_DATA = 1L << 11; - private static final long LARGE_HEAP = 1L << 12; - private static final long USES_CLEARTEXT_TRAFFIC = 1L << 13; - private static final long SUPPORTS_RTL = 1L << 14; - private static final long TEST_ONLY = 1L << 15; - private static final long MULTI_ARCH = 1L << 16; - private static final long EXTRACT_NATIVE_LIBS = 1L << 17; - private static final long GAME = 1L << 18; - private static final long STATIC_SHARED_LIBRARY = 1L << 19; - private static final long OVERLAY = 1L << 20; - private static final long ISOLATED_SPLIT_LOADING = 1L << 21; - private static final long HAS_DOMAIN_URLS = 1L << 22; - private static final long PROFILEABLE_BY_SHELL = 1L << 23; - private static final long BACKUP_IN_FOREGROUND = 1L << 24; - private static final long USE_EMBEDDED_DEX = 1L << 25; - private static final long DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1L << 26; - private static final long DIRECT_BOOT_AWARE = 1L << 27; - private static final long PARTIALLY_DIRECT_BOOT_AWARE = 1L << 28; - private static final long RESIZEABLE_ACTIVITY_VIA_SDK_VERSION = 1L << 29; - private static final long ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1L << 30; - private static final long ALLOW_AUDIO_PLAYBACK_CAPTURE = 1L << 31; - private static final long REQUEST_LEGACY_EXTERNAL_STORAGE = 1L << 32; - private static final long USES_NON_SDK_API = 1L << 33; - private static final long HAS_FRAGILE_USER_DATA = 1L << 34; - private static final long CANT_SAVE_STATE = 1L << 35; - private static final long ALLOW_NATIVE_HEAP_POINTER_TAGGING = 1L << 36; - private static final long PRESERVE_LEGACY_EXTERNAL_STORAGE = 1L << 37; - private static final long REQUIRED_FOR_ALL_USERS = 1L << 38; - private static final long OVERLAY_IS_STATIC = 1L << 39; - private static final long USE_32_BIT_ABI = 1L << 40; - private static final long VISIBLE_TO_INSTANT_APPS = 1L << 41; - private static final long FORCE_QUERYABLE = 1L << 42; - private static final long CROSS_PROFILE = 1L << 43; - private static final long ENABLED = 1L << 44; - private static final long DISALLOW_PROFILING = 1L << 45; - private static final long REQUEST_FOREGROUND_SERVICE_EXEMPTION = 1L << 46; - private static final long ATTRIBUTIONS_ARE_USER_VISIBLE = 1L << 47; - private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48; - private static final long SDK_LIBRARY = 1L << 49; - private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 50; - private static final long LEAVING_SHARED_UID = 1L << 51; - private static final long CORE_APP = 1L << 52; - private static final long SYSTEM = 1L << 53; - private static final long FACTORY_TEST = 1L << 54; - private static final long SYSTEM_EXT = 1L << 56; - private static final long PRIVILEGED = 1L << 57; - private static final long OEM = 1L << 58; - private static final long VENDOR = 1L << 59; - private static final long PRODUCT = 1L << 60; - private static final long ODM = 1L << 61; - private static final long SIGNED_WITH_PLATFORM_KEY = 1L << 62; - private static final long NATIVE_LIBRARY_ROOT_REQUIRES_ISA = 1L << 63; - } - - private static class Booleans2 { - @LongDef({ - STUB, - APEX, - UPDATABLE_SYSTEM, - }) - public @interface Flags {} - - private static final long STUB = 1L; - private static final long APEX = 1L << 1; - private static final long UPDATABLE_SYSTEM = 1L << 2; - } -} diff --git a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java b/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java deleted file mode 100644 index d9625050d28c..000000000000 --- a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.permission; - -import android.Manifest; -import android.annotation.NonNull; - -import com.android.internal.util.DataClass; - -/** - * Implements compatibility support for permissions, and old applications - * will be automatically granted it. - * - * Compatibility permissions are permissions that are automatically granted to - * packages that target an SDK prior to when the permission was introduced. - * Sometimes the platform makes breaking behaviour changes and hides the legacy - * behaviour behind a permission. In these instances, we ensure applications - * targeting older platform versions are implicitly granted the correct set of - * permissions. - * - * @hide - */ -@DataClass(genGetters = true, genBuilder = false) -public class CompatibilityPermissionInfo { - - @NonNull - private final String mName; - private final int mSdkVersion; - - /** - * List of new permissions that have been added since 1.0. - * - * NOTE: These must be declared in SDK version order, with permissions - * added to newer SDKs appearing before those added to older SDKs. - * - * @hide - */ - public static final CompatibilityPermissionInfo[] COMPAT_PERMS = - new CompatibilityPermissionInfo[]{ - new CompatibilityPermissionInfo(Manifest.permission.POST_NOTIFICATIONS, - android.os.Build.VERSION_CODES.TIRAMISU), - new CompatibilityPermissionInfo(Manifest.permission.WRITE_EXTERNAL_STORAGE, - android.os.Build.VERSION_CODES.DONUT), - new CompatibilityPermissionInfo(Manifest.permission.READ_PHONE_STATE, - android.os.Build.VERSION_CODES.DONUT) - }; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public CompatibilityPermissionInfo( - @NonNull String name, - int sdkVersion) { - this.mName = name; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mName); - this.mSdkVersion = sdkVersion; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @NonNull String getName() { - return mName; - } - - @DataClass.Generated.Member - public int getSdkVersion() { - return mSdkVersion; - } - - @DataClass.Generated( - time = 1627674427184L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java", - inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final android.content.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java index 8bd2d94667f9..671e031b546b 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java @@ -120,8 +120,11 @@ import com.android.internal.compat.IPlatformCompat; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.os.RoSystemProperties; +import com.android.internal.pm.permission.CompatibilityPermissionInfo; +import com.android.internal.pm.pkg.component.ComponentMutateUtils; import com.android.internal.pm.pkg.component.ParsedPermission; import com.android.internal.pm.pkg.component.ParsedPermissionGroup; +import com.android.internal.pm.pkg.component.ParsedPermissionUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.IntPair; @@ -144,8 +147,6 @@ import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.SharedUserApi; -import com.android.server.pm.pkg.component.ComponentMutateUtils; -import com.android.server.pm.pkg.component.ParsedPermissionUtils; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.policy.SoftRestrictedPermissionPolicy; diff --git a/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java index 6cbc1de75010..6a156415982c 100644 --- a/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java +++ b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java @@ -16,6 +16,8 @@ package com.android.server.pm.pkg; +import com.android.internal.pm.pkg.SEInfoUtil; + /** * Utility methods that need to be used in application space. * @hide @@ -23,10 +25,10 @@ package com.android.server.pm.pkg; public final class SELinuxUtil { /** Append to existing seinfo label for instant apps @hide */ - private static final String INSTANT_APP_STR = ":ephemeralapp"; + private static final String INSTANT_APP_STR = SEInfoUtil.INSTANT_APP_STR; /** Append to existing seinfo when modifications are complete @hide */ - public static final String COMPLETE_STR = ":complete"; + public static final String COMPLETE_STR = SEInfoUtil.COMPLETE_STR; /** @hide */ public static String getSeinfoUser(PackageUserState userState) { diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java b/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java deleted file mode 100644 index 1964df0853fd..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import com.android.internal.pm.pkg.component.ParsedActivity; -import com.android.internal.pm.pkg.component.ParsedComponent; -import com.android.internal.pm.pkg.component.ParsedMainComponent; -import com.android.internal.pm.pkg.component.ParsedPermission; -import com.android.internal.pm.pkg.component.ParsedPermissionGroup; -import com.android.internal.pm.pkg.component.ParsedProcess; -import com.android.internal.pm.pkg.component.ParsedProvider; - -/** - * Contains mutation methods so that code doesn't have to cast to the Impl. Meant to eventually - * be removed once all post-parsing mutation is moved to parsing. - * - * @hide - */ -public class ComponentMutateUtils { - - public static void setMaxAspectRatio(@NonNull ParsedActivity activity, int resizeMode, - float maxAspectRatio) { - ((ParsedActivityImpl) activity).setMaxAspectRatio(resizeMode, maxAspectRatio); - } - - public static void setMinAspectRatio(@NonNull ParsedActivity activity, int resizeMode, - float minAspectRatio) { - ((ParsedActivityImpl) activity).setMinAspectRatio(resizeMode, minAspectRatio); - } - - public static void setSupportsSizeChanges(@NonNull ParsedActivity activity, - boolean supportsSizeChanges) { - ((ParsedActivityImpl) activity).setSupportsSizeChanges(supportsSizeChanges); - } - - public static void setResizeMode(@NonNull ParsedActivity activity, int resizeMode) { - ((ParsedActivityImpl) activity).setResizeMode(resizeMode); - } - - public static void setExactFlags(ParsedComponent component, int exactFlags) { - ((ParsedComponentImpl) component).setFlags(exactFlags); - } - - public static void setEnabled(@NonNull ParsedMainComponent component, boolean enabled) { - ((ParsedMainComponentImpl) component).setEnabled(enabled); - } - - public static void setPackageName(@NonNull ParsedComponent component, - @NonNull String packageName) { - ((ParsedComponentImpl) component).setPackageName(packageName); - } - - public static void setDirectBootAware(@NonNull ParsedMainComponent component, - boolean directBootAware) { - ((ParsedMainComponentImpl) component).setDirectBootAware(directBootAware); - } - - public static void setExported(@NonNull ParsedMainComponent component, boolean exported) { - ((ParsedMainComponentImpl) component).setExported(exported); - } - - public static void setAuthority(@NonNull ParsedProvider provider, @Nullable String authority) { - ((ParsedProviderImpl) provider).setAuthority(authority); - } - - public static void setSyncable(@NonNull ParsedProvider provider, boolean syncable) { - ((ParsedProviderImpl) provider).setSyncable(syncable); - } - - public static void setProtectionLevel(@NonNull ParsedPermission permission, - int protectionLevel) { - ((ParsedPermissionImpl) permission).setProtectionLevel(protectionLevel); - } - - public static void setParsedPermissionGroup(@NonNull ParsedPermission permission, - @NonNull ParsedPermissionGroup permissionGroup) { - ((ParsedPermissionImpl) permission).setParsedPermissionGroup(permissionGroup); - } - - public static void setPriority(@NonNull ParsedPermissionGroup parsedPermissionGroup, - int priority) { - ((ParsedPermissionGroupImpl) parsedPermissionGroup).setPriority(priority); - } - - public static void addStateFrom(@NonNull ParsedProcess oldProcess, - @NonNull ParsedProcess newProcess) { - ((ParsedProcessImpl) oldProcess).addStateFrom(newProcess); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java b/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java deleted file mode 100644 index 019ca1315af8..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.AttrRes; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.parsing.FrameworkParsingPackageUtils; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.text.TextUtils; - -import com.android.internal.pm.pkg.component.ParsedComponent; -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.pm.pkg.component.ParsedMainComponent; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.pkg.PackageUserState; -import com.android.server.pm.pkg.PackageUserStateUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; - -/** - * @hide - */ -public class ComponentParseUtils { - - public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) { - IntentFilter intentFilter = intentInfo.getIntentFilter(); - return intentFilter.hasCategory(Intent.CATEGORY_BROWSABLE) - || intentFilter.hasAction(Intent.ACTION_SEND) - || intentFilter.hasAction(Intent.ACTION_SENDTO) - || intentFilter.hasAction(Intent.ACTION_SEND_MULTIPLE); - } - - static ParseResult parseAllMetaData( - ParsingPackage pkg, Resources res, XmlResourceParser parser, String tag, - Component component, ParseInput input) throws XmlPullParserException, IOException { - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - final ParseResult result; - if ("meta-data".equals(parser.getName())) { - result = ParsedComponentUtils.addMetaData(component, pkg, res, parser, input); - } else { - result = ParsingUtils.unknownTag(tag, pkg, parser, input); - } - - if (result.isError()) { - return input.error(result); - } - } - - return input.success(component); - } - - @NonNull - public static ParseResult buildProcessName(@NonNull String pkg, String defProc, - CharSequence procSeq, int flags, String[] separateProcesses, ParseInput input) { - if ((flags & ParsingPackageUtils.PARSE_IGNORE_PROCESSES) != 0 && !"system".contentEquals( - procSeq)) { - return input.success(defProc != null ? defProc : pkg); - } - if (separateProcesses != null) { - for (int i = separateProcesses.length - 1; i >= 0; i--) { - String sp = separateProcesses[i]; - if (sp.equals(pkg) || sp.equals(defProc) || sp.contentEquals(procSeq)) { - return input.success(pkg); - } - } - } - if (procSeq == null || procSeq.length() <= 0) { - return input.success(defProc); - } - - ParseResult nameResult = ComponentParseUtils.buildCompoundName(pkg, procSeq, - "process", input); - return input.success(TextUtils.safeIntern(nameResult.getResult())); - } - - @NonNull - public static ParseResult buildTaskAffinityName(String pkg, String defProc, - CharSequence procSeq, ParseInput input) { - if (procSeq == null) { - return input.success(defProc); - } - if (procSeq.length() <= 0) { - return input.success(null); - } - return buildCompoundName(pkg, procSeq, "taskAffinity", input); - } - - public static ParseResult buildCompoundName(String pkg, CharSequence procSeq, - String type, ParseInput input) { - String proc = procSeq.toString(); - char c = proc.charAt(0); - if (pkg != null && c == ':') { - if (proc.length() < 2) { - return input.error("Bad " + type + " name " + proc + " in package " + pkg - + ": must be at least two characters"); - } - String subName = proc.substring(1); - final ParseResult nameResult = FrameworkParsingPackageUtils.validateName(input, - subName, false, false); - if (nameResult.isError()) { - return input.error("Invalid " + type + " name " + proc + " in package " + pkg - + ": " + nameResult.getErrorMessage()); - } - return input.success(pkg + proc); - } - if (!"system".equals(proc)) { - final ParseResult nameResult = FrameworkParsingPackageUtils.validateName(input, proc, - true, false); - if (nameResult.isError()) { - return input.error("Invalid " + type + " name " + proc + " in package " + pkg - + ": " + nameResult.getErrorMessage()); - } - } - return input.success(proc); - } - - public static int flag(int flag, @AttrRes int attribute, TypedArray typedArray) { - return typedArray.getBoolean(attribute, false) ? flag : 0; - } - - public static int flag(int flag, @AttrRes int attribute, boolean defaultValue, - TypedArray typedArray) { - return typedArray.getBoolean(attribute, defaultValue) ? flag : 0; - } - - /** - * This is not state aware. Avoid and access through PackageInfoUtils in the system server. - */ - @Nullable - public static CharSequence getNonLocalizedLabel( - ParsedComponent component) { - return component.getNonLocalizedLabel(); - } - - /** - * This is not state aware. Avoid and access through PackageInfoUtils in the system server. - *

- * This is a method of the utility class to discourage use. - */ - public static int getIcon(ParsedComponent component) { - return component.getIcon(); - } - - public static boolean isMatch(PackageUserState state, boolean isSystem, - boolean isPackageEnabled, ParsedMainComponent component, long flags) { - return PackageUserStateUtils.isMatch(state, isSystem, isPackageEnabled, - component.isEnabled(), component.isDirectBootAware(), component.getName(), flags); - } - - public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled, - ParsedMainComponent parsedComponent, long flags) { - return PackageUserStateUtils.isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(), - parsedComponent.getName(), flags); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java b/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java deleted file mode 100644 index dd54cfca6518..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - - -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Build; -import android.util.ArraySet; - -import com.android.internal.R; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.SystemConfig; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Set; - -/** - * Utility methods for handling the tag {@code } - * - * @hide - */ -public class InstallConstraintsTagParser { - - private static final String TAG_FINGERPRINT_PREFIX = "fingerprint-prefix"; - - /** - * @hide - */ - public static ParseResult parseInstallConstraints( - ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - Set allowlist = SystemConfig.getInstance().getInstallConstraintsAllowlist(); - if (!allowlist.contains(pkg.getPackageName())) { - return input.skip("install-constraints cannot be used by this package"); - } - - ParseResult> prefixes = parseFingerprintPrefixes(input, res, parser); - if (prefixes.isSuccess()) { - if (validateFingerprintPrefixes(prefixes.getResult())) { - return input.success(pkg); - } else { - return input.skip( - "Install of this package is restricted on this device; device fingerprint" - + " does not start with one of the allowed prefixes"); - } - } - return input.skip(prefixes.getErrorMessage()); - } - - private static ParseResult> parseFingerprintPrefixes( - ParseInput input, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - Set prefixes = new ArraySet<>(); - int type; - while (true) { - // move to the tag that contains the next prefix - type = parser.next(); - if (type == XmlPullParser.END_TAG) { - if (prefixes.size() == 0) { - return input.error("install-constraints must contain at least one constraint"); - } - return input.success(prefixes); - } else if (type == XmlPullParser.START_TAG) { - if (parser.getName().equals(TAG_FINGERPRINT_PREFIX)) { - ParseResult parsedPrefix = - readFingerprintPrefixValue(input, res, parser); - if (parsedPrefix.isSuccess()) { - prefixes.add(parsedPrefix.getResult()); - } else { - return input.error(parsedPrefix.getErrorMessage()); - } - } else { - return input.error("Unexpected tag: " + parser.getName()); - } - - // consume the end tag of this attribute - type = parser.next(); - if (type != XmlPullParser.END_TAG) { - return input.error("Expected end tag; instead got " + type); - } - } - } - } - - private static ParseResult readFingerprintPrefixValue(ParseInput input, Resources res, - XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestInstallConstraintsFingerprintPrefix); - try { - String value = sa.getString( - R.styleable.AndroidManifestInstallConstraintsFingerprintPrefix_value); - if (value == null) { - return input.error("Failed to specify prefix value"); - } - return input.success(value); - } finally { - sa.recycle(); - } - } - - private static boolean validateFingerprintPrefixes(Set prefixes) { - String fingerprint = Build.FINGERPRINT; - for (String prefix : prefixes) { - if (fingerprint.startsWith(prefix)) { - return true; - } - } - return false; - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java deleted file mode 100644 index f02790189cc0..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java +++ /dev/null @@ -1,710 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; - -import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString; -import static com.android.server.pm.parsing.pkg.PackageImpl.sForStringSet; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ActivityTaskManager; -import android.content.ComponentName; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.ArraySet; - -import com.android.internal.pm.pkg.component.ParsedActivity; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import java.util.Collections; -import java.util.Locale; -import java.util.Set; - -/** - * @hide - **/ -@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) -public class ParsedActivityImpl extends ParsedMainComponentImpl implements ParsedActivity, - Parcelable { - - private int theme; - private int uiOptions; - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String targetActivity; - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String parentActivityName; - @Nullable - private String taskAffinity; - private int privateFlags; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String permission; - @Nullable - private Set mKnownActivityEmbeddingCerts; - - private int launchMode; - private int documentLaunchMode; - private int maxRecents; - private int configChanges; - private int softInputMode; - private int persistableMode; - private int lockTaskLaunchMode; - - private int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - private int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; - - private float maxAspectRatio = ParsingUtils.NOT_SET; - private float minAspectRatio = ParsingUtils.NOT_SET; - - private boolean supportsSizeChanges; - - @Nullable - private String requestedVrComponent; - private int rotationAnimation = -1; - private int colorMode; - - @Nullable - private ActivityInfo.WindowLayout windowLayout; - - @Nullable - private String mRequiredDisplayCategory; - - public ParsedActivityImpl(ParsedActivityImpl other) { - super(other); - this.theme = other.theme; - this.uiOptions = other.uiOptions; - this.targetActivity = other.targetActivity; - this.parentActivityName = other.parentActivityName; - this.taskAffinity = other.taskAffinity; - this.privateFlags = other.privateFlags; - this.permission = other.permission; - this.launchMode = other.launchMode; - this.documentLaunchMode = other.documentLaunchMode; - this.maxRecents = other.maxRecents; - this.configChanges = other.configChanges; - this.softInputMode = other.softInputMode; - this.persistableMode = other.persistableMode; - this.lockTaskLaunchMode = other.lockTaskLaunchMode; - this.screenOrientation = other.screenOrientation; - this.resizeMode = other.resizeMode; - this.maxAspectRatio = other.maxAspectRatio; - this.minAspectRatio = other.minAspectRatio; - this.supportsSizeChanges = other.supportsSizeChanges; - this.requestedVrComponent = other.requestedVrComponent; - this.rotationAnimation = other.rotationAnimation; - this.colorMode = other.colorMode; - this.windowLayout = other.windowLayout; - this.mKnownActivityEmbeddingCerts = other.mKnownActivityEmbeddingCerts; - this.mRequiredDisplayCategory = other.mRequiredDisplayCategory; - } - - /** - * Generate activity object that forwards user to App Details page automatically. This activity - * should be invisible to user and user should not know or see it. - */ - @NonNull - public static ParsedActivityImpl makeAppDetailsActivity(String packageName, String processName, - int uiOptions, String taskAffinity, boolean hardwareAccelerated) { - ParsedActivityImpl activity = new ParsedActivityImpl(); - activity.setPackageName(packageName); - activity.theme = android.R.style.Theme_NoDisplay; - activity.setExported(true); - activity.setName(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME); - activity.setProcessName(processName); - activity.uiOptions = uiOptions; - activity.taskAffinity = taskAffinity; - activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE; - activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic(); - activity.configChanges = ParsedActivityUtils.getActivityConfigChanges(0, 0); - activity.softInputMode = 0; - activity.persistableMode = ActivityInfo.PERSIST_NEVER; - activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; - activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; - activity.lockTaskLaunchMode = 0; - activity.setDirectBootAware(false); - activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; - activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; - if (hardwareAccelerated) { - activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_HARDWARE_ACCELERATED); - } - return activity; - } - - @NonNull - static ParsedActivityImpl makeAlias(String targetActivityName, ParsedActivity target) { - ParsedActivityImpl alias = new ParsedActivityImpl(); - alias.setPackageName(target.getPackageName()); - alias.setTargetActivity(targetActivityName); - alias.configChanges = target.getConfigChanges(); - alias.setFlags(target.getFlags()); - alias.privateFlags = target.getPrivateFlags(); - alias.setIcon(target.getIcon()); - alias.setLogo(target.getLogo()); - alias.setBanner(target.getBanner()); - alias.setLabelRes(target.getLabelRes()); - alias.setNonLocalizedLabel(target.getNonLocalizedLabel()); - alias.launchMode = target.getLaunchMode(); - alias.lockTaskLaunchMode = target.getLockTaskLaunchMode(); - alias.documentLaunchMode = target.getDocumentLaunchMode(); - alias.setDescriptionRes(target.getDescriptionRes()); - alias.screenOrientation = target.getScreenOrientation(); - alias.taskAffinity = target.getTaskAffinity(); - alias.theme = target.getTheme(); - alias.softInputMode = target.getSoftInputMode(); - alias.uiOptions = target.getUiOptions(); - alias.parentActivityName = target.getParentActivityName(); - alias.maxRecents = target.getMaxRecents(); - alias.windowLayout = target.getWindowLayout(); - alias.resizeMode = target.getResizeMode(); - alias.maxAspectRatio = target.getMaxAspectRatio(); - alias.minAspectRatio = target.getMinAspectRatio(); - alias.supportsSizeChanges = target.isSupportsSizeChanges(); - alias.requestedVrComponent = target.getRequestedVrComponent(); - alias.setDirectBootAware(target.isDirectBootAware()); - alias.setProcessName(target.getProcessName()); - alias.setRequiredDisplayCategory(target.getRequiredDisplayCategory()); - return alias; - - // Not all attributes from the target ParsedActivity are copied to the alias. - // Careful when adding an attribute and determine whether or not it should be copied. -// alias.enabled = target.enabled; -// alias.exported = target.exported; -// alias.permission = target.permission; -// alias.splitName = target.splitName; -// alias.persistableMode = target.persistableMode; -// alias.rotationAnimation = target.rotationAnimation; -// alias.colorMode = target.colorMode; -// alias.intents.addAll(target.intents); -// alias.order = target.order; -// alias.metaData = target.metaData; - } - - public ParsedActivityImpl setMaxAspectRatio(int resizeMode, float maxAspectRatio) { - if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE - || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { - // Resizeable activities can be put in any aspect ratio. - return this; - } - - if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { - // Ignore any value lesser than 1.0. - return this; - } - - this.maxAspectRatio = maxAspectRatio; - return this; - } - - public ParsedActivityImpl setMinAspectRatio(int resizeMode, float minAspectRatio) { - if (resizeMode == RESIZE_MODE_RESIZEABLE - || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { - // Resizeable activities can be put in any aspect ratio. - return this; - } - - if (minAspectRatio < 1.0f && minAspectRatio != 0) { - // Ignore any value lesser than 1.0. - return this; - } - - this.minAspectRatio = minAspectRatio; - return this; - } - - public ParsedActivityImpl setTargetActivity(String targetActivity) { - this.targetActivity = TextUtils.safeIntern(targetActivity); - return this; - } - - public ParsedActivityImpl setPermission(String permission) { - // Empty string must be converted to null - this.permission = TextUtils.isEmpty(permission) ? null : permission.intern(); - return this; - } - - @NonNull - @Override - public Set getKnownActivityEmbeddingCerts() { - return mKnownActivityEmbeddingCerts == null ? Collections.emptySet() - : mKnownActivityEmbeddingCerts; - } - - /** - * Sets the trusted host certificates of apps that are allowed to embed this activity. - */ - public void setKnownActivityEmbeddingCerts(@NonNull Set knownActivityEmbeddingCerts) { - // Convert the provided digest to upper case for consistent Set membership - // checks when verifying the signing certificate digests of requesting apps. - this.mKnownActivityEmbeddingCerts = new ArraySet<>(); - for (String knownCert : knownActivityEmbeddingCerts) { - this.mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US)); - } - } - - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("Activity{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(' '); - ComponentName.appendShortString(sb, getPackageName(), getName()); - sb.append('}'); - return sb.toString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(this.theme); - dest.writeInt(this.uiOptions); - dest.writeString(this.targetActivity); - dest.writeString(this.parentActivityName); - dest.writeString(this.taskAffinity); - dest.writeInt(this.privateFlags); - sForInternedString.parcel(this.permission, dest, flags); - dest.writeInt(this.launchMode); - dest.writeInt(this.documentLaunchMode); - dest.writeInt(this.maxRecents); - dest.writeInt(this.configChanges); - dest.writeInt(this.softInputMode); - dest.writeInt(this.persistableMode); - dest.writeInt(this.lockTaskLaunchMode); - dest.writeInt(this.screenOrientation); - dest.writeInt(this.resizeMode); - dest.writeValue(this.maxAspectRatio); - dest.writeValue(this.minAspectRatio); - dest.writeBoolean(this.supportsSizeChanges); - dest.writeString(this.requestedVrComponent); - dest.writeInt(this.rotationAnimation); - dest.writeInt(this.colorMode); - dest.writeBundle(this.getMetaData()); - - if (windowLayout != null) { - dest.writeInt(1); - windowLayout.writeToParcel(dest); - } else { - dest.writeBoolean(false); - } - sForStringSet.parcel(this.mKnownActivityEmbeddingCerts, dest, flags); - dest.writeString8(this.mRequiredDisplayCategory); - } - - public ParsedActivityImpl() { - } - - protected ParsedActivityImpl(Parcel in) { - super(in); - this.theme = in.readInt(); - this.uiOptions = in.readInt(); - this.targetActivity = in.readString(); - this.parentActivityName = in.readString(); - this.taskAffinity = in.readString(); - this.privateFlags = in.readInt(); - this.permission = sForInternedString.unparcel(in); - this.launchMode = in.readInt(); - this.documentLaunchMode = in.readInt(); - this.maxRecents = in.readInt(); - this.configChanges = in.readInt(); - this.softInputMode = in.readInt(); - this.persistableMode = in.readInt(); - this.lockTaskLaunchMode = in.readInt(); - this.screenOrientation = in.readInt(); - this.resizeMode = in.readInt(); - this.maxAspectRatio = (Float) in.readValue(Float.class.getClassLoader()); - this.minAspectRatio = (Float) in.readValue(Float.class.getClassLoader()); - this.supportsSizeChanges = in.readBoolean(); - this.requestedVrComponent = in.readString(); - this.rotationAnimation = in.readInt(); - this.colorMode = in.readInt(); - this.setMetaData(in.readBundle()); - if (in.readBoolean()) { - windowLayout = new ActivityInfo.WindowLayout(in); - } - this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in); - this.mRequiredDisplayCategory = in.readString8(); - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ParsedActivityImpl createFromParcel(Parcel source) { - return new ParsedActivityImpl(source); - } - - @Override - public ParsedActivityImpl[] newArray(int size) { - return new ParsedActivityImpl[size]; - } - }; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedActivityImpl( - int theme, - int uiOptions, - @Nullable String targetActivity, - @Nullable String parentActivityName, - @Nullable String taskAffinity, - int privateFlags, - @Nullable String permission, - @Nullable Set knownActivityEmbeddingCerts, - int launchMode, - int documentLaunchMode, - int maxRecents, - int configChanges, - int softInputMode, - int persistableMode, - int lockTaskLaunchMode, - int screenOrientation, - int resizeMode, - float maxAspectRatio, - float minAspectRatio, - boolean supportsSizeChanges, - @Nullable String requestedVrComponent, - int rotationAnimation, - int colorMode, - @Nullable ActivityInfo.WindowLayout windowLayout, - @Nullable String requiredDisplayCategory) { - this.theme = theme; - this.uiOptions = uiOptions; - this.targetActivity = targetActivity; - this.parentActivityName = parentActivityName; - this.taskAffinity = taskAffinity; - this.privateFlags = privateFlags; - this.permission = permission; - this.mKnownActivityEmbeddingCerts = knownActivityEmbeddingCerts; - this.launchMode = launchMode; - this.documentLaunchMode = documentLaunchMode; - this.maxRecents = maxRecents; - this.configChanges = configChanges; - this.softInputMode = softInputMode; - this.persistableMode = persistableMode; - this.lockTaskLaunchMode = lockTaskLaunchMode; - this.screenOrientation = screenOrientation; - this.resizeMode = resizeMode; - this.maxAspectRatio = maxAspectRatio; - this.minAspectRatio = minAspectRatio; - this.supportsSizeChanges = supportsSizeChanges; - this.requestedVrComponent = requestedVrComponent; - this.rotationAnimation = rotationAnimation; - this.colorMode = colorMode; - this.windowLayout = windowLayout; - this.mRequiredDisplayCategory = requiredDisplayCategory; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public int getTheme() { - return theme; - } - - @DataClass.Generated.Member - public int getUiOptions() { - return uiOptions; - } - - @DataClass.Generated.Member - public @Nullable String getTargetActivity() { - return targetActivity; - } - - @DataClass.Generated.Member - public @Nullable String getParentActivityName() { - return parentActivityName; - } - - @DataClass.Generated.Member - public @Nullable String getTaskAffinity() { - return taskAffinity; - } - - @DataClass.Generated.Member - public int getPrivateFlags() { - return privateFlags; - } - - @DataClass.Generated.Member - public @Nullable String getPermission() { - return permission; - } - - @DataClass.Generated.Member - public int getLaunchMode() { - return launchMode; - } - - @DataClass.Generated.Member - public int getDocumentLaunchMode() { - return documentLaunchMode; - } - - @DataClass.Generated.Member - public int getMaxRecents() { - return maxRecents; - } - - @DataClass.Generated.Member - public int getConfigChanges() { - return configChanges; - } - - @DataClass.Generated.Member - public int getSoftInputMode() { - return softInputMode; - } - - @DataClass.Generated.Member - public int getPersistableMode() { - return persistableMode; - } - - @DataClass.Generated.Member - public int getLockTaskLaunchMode() { - return lockTaskLaunchMode; - } - - @DataClass.Generated.Member - public int getScreenOrientation() { - return screenOrientation; - } - - @DataClass.Generated.Member - public int getResizeMode() { - return resizeMode; - } - - @DataClass.Generated.Member - public float getMaxAspectRatio() { - return maxAspectRatio; - } - - @DataClass.Generated.Member - public float getMinAspectRatio() { - return minAspectRatio; - } - - @DataClass.Generated.Member - public boolean isSupportsSizeChanges() { - return supportsSizeChanges; - } - - @DataClass.Generated.Member - public @Nullable String getRequestedVrComponent() { - return requestedVrComponent; - } - - @DataClass.Generated.Member - public int getRotationAnimation() { - return rotationAnimation; - } - - @DataClass.Generated.Member - public int getColorMode() { - return colorMode; - } - - @DataClass.Generated.Member - public @Nullable ActivityInfo.WindowLayout getWindowLayout() { - return windowLayout; - } - - @DataClass.Generated.Member - public @Nullable String getRequiredDisplayCategory() { - return mRequiredDisplayCategory; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setTheme( int value) { - theme = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setUiOptions( int value) { - uiOptions = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setParentActivityName(@NonNull String value) { - parentActivityName = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setTaskAffinity(@NonNull String value) { - taskAffinity = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setPrivateFlags( int value) { - privateFlags = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setLaunchMode( int value) { - launchMode = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setDocumentLaunchMode( int value) { - documentLaunchMode = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setMaxRecents( int value) { - maxRecents = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setConfigChanges( int value) { - configChanges = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setSoftInputMode( int value) { - softInputMode = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setPersistableMode( int value) { - persistableMode = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setLockTaskLaunchMode( int value) { - lockTaskLaunchMode = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setScreenOrientation( int value) { - screenOrientation = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setResizeMode( int value) { - resizeMode = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setMaxAspectRatio( float value) { - maxAspectRatio = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setMinAspectRatio( float value) { - minAspectRatio = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setSupportsSizeChanges( boolean value) { - supportsSizeChanges = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setRequestedVrComponent(@NonNull String value) { - requestedVrComponent = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setRotationAnimation( int value) { - rotationAnimation = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setColorMode( int value) { - colorMode = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setWindowLayout(@NonNull ActivityInfo.WindowLayout value) { - windowLayout = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedActivityImpl setRequiredDisplayCategory(@NonNull String value) { - mRequiredDisplayCategory = value; - return this; - } - - @DataClass.Generated( - time = 1669437519576L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java", - inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java deleted file mode 100644 index 64985bdfd54f..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - -import static com.android.server.pm.pkg.component.ComponentParseUtils.flag; -import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET; -import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ActivityTaskManager; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.parsing.FrameworkParsingPackageUtils; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseInput.DeferredError; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Build; -import android.util.ArraySet; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.WindowManager; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedActivity; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.internal.util.ArrayUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * @hide - */ -public class ParsedActivityUtils { - - private static final String TAG = ParsingUtils.TAG; - - public static final boolean LOG_UNSAFE_BROADCASTS = false; - - // Set of broadcast actions that are safe for manifest receivers - public static final Set SAFE_BROADCASTS = new ArraySet<>(); - static { - SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED); - } - - /** - * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. - */ - private static final int RECREATE_ON_CONFIG_CHANGES_MASK = - ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; - - @NonNull - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public static ParseResult parseActivityOrReceiver(String[] separateProcesses, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, - boolean useRoundIcon, @Nullable String defaultSplitName, ParseInput input) - throws XmlPullParserException, IOException { - final String packageName = pkg.getPackageName(); - final ParsedActivityImpl activity = new ParsedActivityImpl(); - - boolean receiver = "receiver".equals(parser.getName()); - String tag = "<" + parser.getName() + ">"; - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); - try { - ParseResult result = - ParsedMainComponentUtils.parseMainComponent(activity, tag, separateProcesses, - pkg, sa, flags, useRoundIcon, defaultSplitName, input, - R.styleable.AndroidManifestActivity_banner, - R.styleable.AndroidManifestActivity_description, - R.styleable.AndroidManifestActivity_directBootAware, - R.styleable.AndroidManifestActivity_enabled, - R.styleable.AndroidManifestActivity_icon, - R.styleable.AndroidManifestActivity_label, - R.styleable.AndroidManifestActivity_logo, - R.styleable.AndroidManifestActivity_name, - R.styleable.AndroidManifestActivity_process, - R.styleable.AndroidManifestActivity_roundIcon, - R.styleable.AndroidManifestActivity_splitName, - R.styleable.AndroidManifestActivity_attributionTags); - if (result.isError()) { - return input.error(result); - } - - if (receiver && pkg.isSaveStateDisallowed()) { - // A heavy-weight application can not have receivers in its main process - if (Objects.equals(activity.getProcessName(), packageName)) { - return input.error("Heavy-weight applications can not have receivers " - + "in main process"); - } - } - - // The following section has formatting off to make it easier to read the flags. - // Multi-lining them to fit within the column restriction makes it hard to tell what - // field is assigned where. - // @formatter:off - activity.setTheme(sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0)) - .setUiOptions(sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions())); - - activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isTaskReparentingAllowed(), sa) - | flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa) - | flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa) - | flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa) - | flag(ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS, R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, sa) - | flag(ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH, R.styleable.AndroidManifestActivity_finishOnTaskLaunch, sa) - | flag(ActivityInfo.FLAG_IMMERSIVE, R.styleable.AndroidManifestActivity_immersive, sa) - | flag(ActivityInfo.FLAG_MULTIPROCESS, R.styleable.AndroidManifestActivity_multiprocess, sa) - | flag(ActivityInfo.FLAG_NO_HISTORY, R.styleable.AndroidManifestActivity_noHistory, sa) - | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showForAllUsers, sa) - | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showOnLockScreen, sa) - | flag(ActivityInfo.FLAG_STATE_NOT_NEEDED, R.styleable.AndroidManifestActivity_stateNotNeeded, sa) - | flag(ActivityInfo.FLAG_SYSTEM_USER_ONLY, R.styleable.AndroidManifestActivity_systemUserOnly, sa))); - - if (!receiver) { - activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_HARDWARE_ACCELERATED, R.styleable.AndroidManifestActivity_hardwareAccelerated, pkg.isHardwareAccelerated(), sa) - | flag(ActivityInfo.FLAG_ALLOW_EMBEDDED, R.styleable.AndroidManifestActivity_allowEmbedded, sa) - | flag(ActivityInfo.FLAG_ALWAYS_FOCUSABLE, R.styleable.AndroidManifestActivity_alwaysFocusable, sa) - | flag(ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS, R.styleable.AndroidManifestActivity_autoRemoveFromRecents, sa) - | flag(ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY, R.styleable.AndroidManifestActivity_relinquishTaskIdentity, sa) - | flag(ActivityInfo.FLAG_RESUME_WHILE_PAUSING, R.styleable.AndroidManifestActivity_resumeWhilePausing, sa) - | flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa) - | flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa) - | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa) - | flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa)) - | flag(ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING, R.styleable.AndroidManifestActivity_allowUntrustedActivityEmbedding, sa)); - - activity.setPrivateFlags(activity.getPrivateFlags() | (flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED, - R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa) - | flag(ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND, - R.styleable.AndroidManifestActivity_playHomeTransitionSound, true, sa))); - - activity.setColorMode(sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT)) - .setDocumentLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE)) - .setLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE)) - .setLockTaskLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0)) - .setMaxRecents(sa.getInt(R.styleable.AndroidManifestActivity_maxRecents, ActivityTaskManager.getDefaultAppRecentsLimitStatic())) - .setPersistableMode(sa.getInteger(R.styleable.AndroidManifestActivity_persistableMode, ActivityInfo.PERSIST_ROOT_ONLY)) - .setRequestedVrComponent(sa.getString(R.styleable.AndroidManifestActivity_enableVrMode)) - .setRotationAnimation(sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED)) - .setSoftInputMode(sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0)) - .setConfigChanges(getActivityConfigChanges( - sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), - sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)) - ); - - int screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED); - int resizeMode = getActivityResizeMode(pkg, sa, screenOrientation); - activity.setScreenOrientation(screenOrientation) - .setResizeMode(resizeMode); - - if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio) - && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio) - == TypedValue.TYPE_FLOAT) { - activity.setMaxAspectRatio(resizeMode, - sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio, - 0 /*default*/)); - } - - if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio) - && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio) - == TypedValue.TYPE_FLOAT) { - activity.setMinAspectRatio(resizeMode, - sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio, - 0 /*default*/)); - } - - if (sa.hasValue(R.styleable.AndroidManifestActivity_enableOnBackInvokedCallback)) { - boolean enable = sa.getBoolean( - R.styleable.AndroidManifestActivity_enableOnBackInvokedCallback, - false); - activity.setPrivateFlags(activity.getPrivateFlags() - | (enable ? ActivityInfo.PRIVATE_FLAG_ENABLE_ON_BACK_INVOKED_CALLBACK - : ActivityInfo.PRIVATE_FLAG_DISABLE_ON_BACK_INVOKED_CALLBACK)); - } - } else { - activity.setLaunchMode(ActivityInfo.LAUNCH_MULTIPLE) - .setConfigChanges(0) - .setFlags(activity.getFlags()|flag(ActivityInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestActivity_singleUser, sa)); - } - // @formatter:on - - String taskAffinity = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivity_taskAffinity, - Configuration.NATIVE_CONFIG_VERSION); - - ParseResult affinityNameResult = ComponentParseUtils.buildTaskAffinityName( - packageName, pkg.getTaskAffinity(), taskAffinity, input); - if (affinityNameResult.isError()) { - return input.error(affinityNameResult); - } - - activity.setTaskAffinity(affinityNameResult.getResult()); - - boolean visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false); - if (visibleToEphemeral) { - activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP); - pkg.setVisibleToInstantApps(true); - } - - String requiredDisplayCategory = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivity_requiredDisplayCategory, 0); - - if (requiredDisplayCategory != null - && FrameworkParsingPackageUtils.validateName(requiredDisplayCategory, - false /* requireSeparator */, false /* requireFilename */) != null) { - return input.error("requiredDisplayCategory attribute can only consist " - + "of alphanumeric characters, '_', and '.'"); - } - - activity.setRequiredDisplayCategory(requiredDisplayCategory); - - return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver, - false /*isAlias*/, visibleToEphemeral, input, - R.styleable.AndroidManifestActivity_parentActivityName, - R.styleable.AndroidManifestActivity_permission, - R.styleable.AndroidManifestActivity_exported - ); - } finally { - sa.recycle(); - } - } - - @NonNull - public static ParseResult parseActivityAlias(ParsingPackage pkg, Resources res, - XmlResourceParser parser, boolean useRoundIcon, @Nullable String defaultSplitName, - @NonNull ParseInput input) throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivityAlias); - try { - String targetActivity = sa.getNonConfigurationString( - R.styleable.AndroidManifestActivityAlias_targetActivity, - Configuration.NATIVE_CONFIG_VERSION); - if (targetActivity == null) { - return input.error(" does not specify android:targetActivity"); - } - - String packageName = pkg.getPackageName(); - targetActivity = ParsingUtils.buildClassName(packageName, targetActivity); - if (targetActivity == null) { - return input.error("Empty class name in package " + packageName); - } - - ParsedActivity target = null; - - List activities = pkg.getActivities(); - final int activitiesSize = ArrayUtils.size(activities); - for (int i = 0; i < activitiesSize; i++) { - ParsedActivity t = activities.get(i); - if (targetActivity.equals(t.getName())) { - target = t; - break; - } - } - - if (target == null) { - return input.error(" target activity " + targetActivity - + " not found in manifest with activities = " - + pkg.getActivities() - + ", parsedActivities = " + activities); - } - - ParsedActivityImpl activity = ParsedActivityImpl.makeAlias(targetActivity, target); - String tag = "<" + parser.getName() + ">"; - - ParseResult result = ParsedMainComponentUtils.parseMainComponent( - activity, tag, null, pkg, sa, 0, useRoundIcon, defaultSplitName, input, - R.styleable.AndroidManifestActivityAlias_banner, - R.styleable.AndroidManifestActivityAlias_description, - NOT_SET /*directBootAwareAttr*/, - R.styleable.AndroidManifestActivityAlias_enabled, - R.styleable.AndroidManifestActivityAlias_icon, - R.styleable.AndroidManifestActivityAlias_label, - R.styleable.AndroidManifestActivityAlias_logo, - R.styleable.AndroidManifestActivityAlias_name, - NOT_SET /*processAttr*/, - R.styleable.AndroidManifestActivityAlias_roundIcon, - NOT_SET /*splitNameAttr*/, - R.styleable.AndroidManifestActivityAlias_attributionTags); - if (result.isError()) { - return input.error(result); - } - - // TODO add visibleToInstantApps attribute to activity alias - final boolean visibleToEphemeral = - ((activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0); - - return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, false /*isReceiver*/, true /*isAlias*/, - visibleToEphemeral, input, - R.styleable.AndroidManifestActivityAlias_parentActivityName, - R.styleable.AndroidManifestActivityAlias_permission, - R.styleable.AndroidManifestActivityAlias_exported); - } finally { - sa.recycle(); - } - } - - /** - * This method shares parsing logic between Activity/Receiver/alias instances, but requires - * passing in booleans for isReceiver/isAlias, since there's no indicator in the other - * parameters. - * - * They're used to filter the parsed tags and their behavior. This makes the method rather - * messy, but it's more maintainable than writing 3 separate methods for essentially the same - * type of logic. - */ - @NonNull - private static ParseResult parseActivityOrAlias(ParsedActivityImpl activity, - ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources, - TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral, - ParseInput input, int parentActivityNameAttr, int permissionAttr, - int exportedAttr) throws IOException, XmlPullParserException { - String parentActivityName = array.getNonConfigurationString(parentActivityNameAttr, Configuration.NATIVE_CONFIG_VERSION); - if (parentActivityName != null) { - String packageName = pkg.getPackageName(); - String parentClassName = ParsingUtils.buildClassName(packageName, parentActivityName); - if (parentClassName == null) { - Log.e(TAG, "Activity " + activity.getName() - + " specified invalid parentActivityName " + parentActivityName); - } else { - activity.setParentActivityName(parentClassName); - } - } - - String permission = array.getNonConfigurationString(permissionAttr, 0); - if (isAlias) { - // An alias will override permissions to allow referencing an Activity through its alias - // without needing the original permission. If an alias needs the same permission, - // it must be re-declared. - activity.setPermission(permission); - } else { - activity.setPermission(permission != null ? permission : pkg.getPermission()); - } - - final ParseResult> knownActivityEmbeddingCertsResult = - parseKnownActivityEmbeddingCerts(array, resources, isAlias - ? R.styleable.AndroidManifestActivityAlias_knownActivityEmbeddingCerts - : R.styleable.AndroidManifestActivity_knownActivityEmbeddingCerts, input); - if (knownActivityEmbeddingCertsResult.isError()) { - return input.error(knownActivityEmbeddingCertsResult); - } else { - final Set knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult - .getResult(); - if (knownActivityEmbeddingCerts != null) { - activity.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts); - } - } - - final boolean setExported = array.hasValue(exportedAttr); - if (setExported) { - activity.setExported(array.getBoolean(exportedAttr, false)); - } - - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - final ParseResult result; - if (parser.getName().equals("intent-filter")) { - ParseResult intentResult = parseIntentFilter(pkg, activity, - !isReceiver, visibleToEphemeral, resources, parser, input); - if (intentResult.isSuccess()) { - ParsedIntentInfoImpl intentInfo = intentResult.getResult(); - if (intentInfo != null) { - IntentFilter intentFilter = intentInfo.getIntentFilter(); - activity.setOrder(Math.max(intentFilter.getOrder(), activity.getOrder())); - activity.addIntent(intentInfo); - if (LOG_UNSAFE_BROADCASTS && isReceiver - && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) { - int actionCount = intentFilter.countActions(); - for (int i = 0; i < actionCount; i++) { - final String action = intentFilter.getAction(i); - if (action == null || !action.startsWith("android.")) { - continue; - } - - if (!SAFE_BROADCASTS.contains(action)) { - Slog.w(TAG, - "Broadcast " + action + " may never be delivered to " - + pkg.getPackageName() + " as requested at: " - + parser.getPositionDescription()); - } - } - } - } - } - result = intentResult; - } else if (parser.getName().equals("meta-data")) { - result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input); - } else if (parser.getName().equals("property")) { - result = ParsedComponentUtils.addProperty(activity, pkg, resources, parser, input); - } else if (!isReceiver && !isAlias && parser.getName().equals("preferred")) { - ParseResult intentResult = parseIntentFilter(pkg, activity, - true /*allowImplicitEphemeralVisibility*/, visibleToEphemeral, - resources, parser, input); - if (intentResult.isSuccess()) { - ParsedIntentInfoImpl intent = intentResult.getResult(); - if (intent != null) { - pkg.addPreferredActivityFilter(activity.getClassName(), intent); - } - } - result = intentResult; - } else if (!isReceiver && !isAlias && parser.getName().equals("layout")) { - ParseResult layoutResult = - parseActivityWindowLayout(resources, parser, input); - if (layoutResult.isSuccess()) { - activity.setWindowLayout(layoutResult.getResult()); - } - result = layoutResult; - } else { - result = ParsingUtils.unknownTag(tag, pkg, parser, input); - } - - if (result.isError()) { - return input.error(result); - } - } - - if (!isAlias && activity.getLaunchMode() != LAUNCH_SINGLE_INSTANCE_PER_TASK - && activity.getMetaData().containsKey( - ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE)) { - final String launchMode = activity.getMetaData().getString( - ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE); - if (launchMode != null && launchMode.equals("singleInstancePerTask")) { - activity.setLaunchMode(LAUNCH_SINGLE_INSTANCE_PER_TASK); - } - } - - if (!isAlias) { - // Default allow the activity to be displayed on a remote device unless it explicitly - // set to false. - boolean canDisplayOnRemoteDevices = array.getBoolean( - R.styleable.AndroidManifestActivity_canDisplayOnRemoteDevices, true); - if (!activity.getMetaData().getBoolean( - ParsingPackageUtils.METADATA_CAN_DISPLAY_ON_REMOTE_DEVICES, true)) { - canDisplayOnRemoteDevices = false; - } - if (canDisplayOnRemoteDevices) { - activity.setFlags(activity.getFlags() - | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES); - } - } - - ParseResult layoutResult = - resolveActivityWindowLayout(activity, input); - if (layoutResult.isError()) { - return input.error(layoutResult); - } - activity.setWindowLayout(layoutResult.getResult()); - - if (!setExported) { - boolean hasIntentFilters = activity.getIntents().size() > 0; - if (hasIntentFilters) { - final ParseResult exportedCheckResult = input.deferError( - activity.getName() + ": Targeting S+ (version " + Build.VERSION_CODES.S - + " and above) requires that an explicit value for android:exported be" - + " defined when intent filters are present", - DeferredError.MISSING_EXPORTED_FLAG); - if (exportedCheckResult.isError()) { - return input.error(exportedCheckResult); - } - } - activity.setExported(hasIntentFilters); - } - - return input.success(activity); - } - - @NonNull - private static ParseResult parseIntentFilter(ParsingPackage pkg, - ParsedActivityImpl activity, boolean allowImplicitEphemeralVisibility, - boolean visibleToEphemeral, Resources resources, XmlResourceParser parser, - ParseInput input) throws IOException, XmlPullParserException { - ParseResult result = ParsedMainComponentUtils.parseIntentFilter(activity, - pkg, resources, parser, visibleToEphemeral, true /*allowGlobs*/, - true /*allowAutoVerify*/, allowImplicitEphemeralVisibility, - true /*failOnNoActions*/, input); - if (result.isError()) { - return input.error(result); - } - - ParsedIntentInfoImpl intent = result.getResult(); - if (intent != null) { - final IntentFilter intentFilter = intent.getIntentFilter(); - if (intentFilter.isVisibleToInstantApp()) { - activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP); - } - if (intentFilter.isImplicitlyVisibleToInstantApp()) { - activity.setFlags( - activity.getFlags() | ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP); - } - } - - return input.success(intent); - } - - private static int getActivityResizeMode(ParsingPackage pkg, TypedArray sa, - int screenOrientation) { - Boolean resizeableActivity = pkg.getResizeableActivity(); - - if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) - || resizeableActivity != null) { - // Activity or app explicitly set if it is resizeable or not; - if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, - resizeableActivity != null && resizeableActivity)) { - return ActivityInfo.RESIZE_MODE_RESIZEABLE; - } else { - return ActivityInfo.RESIZE_MODE_UNRESIZEABLE; - } - } - - if (pkg.isResizeableActivityViaSdkVersion()) { - // The activity or app didn't explicitly set the resizing option, however we want to - // make it resize due to the sdk version it is targeting. - return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; - } - - // resize preference isn't set and target sdk version doesn't support resizing apps by - // default. For the app to be resizeable if it isn't fixed orientation or immersive. - if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; - } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; - } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; - } else { - return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; - } - } - - @NonNull - private static ParseResult parseActivityWindowLayout(Resources res, - AttributeSet attrs, ParseInput input) { - TypedArray sw = res.obtainAttributes(attrs, R.styleable.AndroidManifestLayout); - try { - int width = -1; - float widthFraction = -1f; - int height = -1; - float heightFraction = -1f; - final int widthType = sw.getType(R.styleable.AndroidManifestLayout_defaultWidth); - if (widthType == TypedValue.TYPE_FRACTION) { - widthFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultWidth, 1, 1, - -1); - } else if (widthType == TypedValue.TYPE_DIMENSION) { - width = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultWidth, - -1); - } - final int heightType = sw.getType(R.styleable.AndroidManifestLayout_defaultHeight); - if (heightType == TypedValue.TYPE_FRACTION) { - heightFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultHeight, 1, - 1, -1); - } else if (heightType == TypedValue.TYPE_DIMENSION) { - height = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultHeight, - -1); - } - int gravity = sw.getInt(R.styleable.AndroidManifestLayout_gravity, Gravity.CENTER); - int minWidth = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minWidth, -1); - int minHeight = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minHeight, - -1); - String windowLayoutAffinity = - sw.getNonConfigurationString( - R.styleable.AndroidManifestLayout_windowLayoutAffinity, 0); - final ActivityInfo.WindowLayout windowLayout = new ActivityInfo.WindowLayout(width, - widthFraction, height, heightFraction, gravity, minWidth, minHeight, - windowLayoutAffinity); - return input.success(windowLayout); - } finally { - sw.recycle(); - } - } - - /** - * Resolves values in {@link ActivityInfo.WindowLayout}. - * - *

{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in - * Android R and some variants of pre-R. - */ - private static ParseResult resolveActivityWindowLayout( - ParsedActivity activity, ParseInput input) { - // There isn't a metadata for us to fall back. Whatever is in layout is correct. - if (!activity.getMetaData().containsKey( - ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) { - return input.success(activity.getWindowLayout()); - } - - // Layout already specifies a value. We should just use that one. - if (activity.getWindowLayout() != null && activity.getWindowLayout().windowLayoutAffinity != null) { - return input.success(activity.getWindowLayout()); - } - - String windowLayoutAffinity = activity.getMetaData().getString( - ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY); - ActivityInfo.WindowLayout layout = activity.getWindowLayout(); - if (layout == null) { - layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */, - -1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY, - -1 /* minWidth */, -1 /* minHeight */, windowLayoutAffinity); - } else { - layout.windowLayoutAffinity = windowLayoutAffinity; - } - return input.success(layout); - } - - /** - * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml. - * @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from - * AndroidManifest.xml. - * @hide - */ - public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) { - return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java deleted file mode 100644 index cfed19aa0934..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedApexSystemService; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling; - -/** - * @hide - **/ -@DataClass(genGetters = true, genAidl = false, genSetters = true, genParcelable = true) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedApexSystemServiceImpl implements ParsedApexSystemService, Parcelable { - - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) - @NonNull - private String name; - - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) - @Nullable - private String jarPath; - - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) - @Nullable - private String minSdkVersion; - - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) - @Nullable - private String maxSdkVersion; - - private int initOrder; - - public ParsedApexSystemServiceImpl() { - } - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedApexSystemServiceImpl( - @NonNull String name, - @Nullable String jarPath, - @Nullable String minSdkVersion, - @Nullable String maxSdkVersion, - int initOrder) { - this.name = name; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - this.jarPath = jarPath; - this.minSdkVersion = minSdkVersion; - this.maxSdkVersion = maxSdkVersion; - this.initOrder = initOrder; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @NonNull String getName() { - return name; - } - - @DataClass.Generated.Member - public @Nullable String getJarPath() { - return jarPath; - } - - @DataClass.Generated.Member - public @Nullable String getMinSdkVersion() { - return minSdkVersion; - } - - @DataClass.Generated.Member - public @Nullable String getMaxSdkVersion() { - return maxSdkVersion; - } - - @DataClass.Generated.Member - public int getInitOrder() { - return initOrder; - } - - @DataClass.Generated.Member - public @NonNull ParsedApexSystemServiceImpl setName(@NonNull String value) { - name = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedApexSystemServiceImpl setJarPath(@NonNull String value) { - jarPath = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedApexSystemServiceImpl setMinSdkVersion(@NonNull String value) { - minSdkVersion = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedApexSystemServiceImpl setMaxSdkVersion(@NonNull String value) { - maxSdkVersion = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedApexSystemServiceImpl setInitOrder( int value) { - initOrder = value; - return this; - } - - @DataClass.Generated.Member - static Parcelling sParcellingForName = - Parcelling.Cache.get( - Parcelling.BuiltIn.ForInternedString.class); - static { - if (sParcellingForName == null) { - sParcellingForName = Parcelling.Cache.put( - new Parcelling.BuiltIn.ForInternedString()); - } - } - - @DataClass.Generated.Member - static Parcelling sParcellingForJarPath = - Parcelling.Cache.get( - Parcelling.BuiltIn.ForInternedString.class); - static { - if (sParcellingForJarPath == null) { - sParcellingForJarPath = Parcelling.Cache.put( - new Parcelling.BuiltIn.ForInternedString()); - } - } - - @DataClass.Generated.Member - static Parcelling sParcellingForMinSdkVersion = - Parcelling.Cache.get( - Parcelling.BuiltIn.ForInternedString.class); - static { - if (sParcellingForMinSdkVersion == null) { - sParcellingForMinSdkVersion = Parcelling.Cache.put( - new Parcelling.BuiltIn.ForInternedString()); - } - } - - @DataClass.Generated.Member - static Parcelling sParcellingForMaxSdkVersion = - Parcelling.Cache.get( - Parcelling.BuiltIn.ForInternedString.class); - static { - if (sParcellingForMaxSdkVersion == null) { - sParcellingForMaxSdkVersion = Parcelling.Cache.put( - new Parcelling.BuiltIn.ForInternedString()); - } - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - byte flg = 0; - if (jarPath != null) flg |= 0x2; - if (minSdkVersion != null) flg |= 0x4; - if (maxSdkVersion != null) flg |= 0x8; - dest.writeByte(flg); - sParcellingForName.parcel(name, dest, flags); - sParcellingForJarPath.parcel(jarPath, dest, flags); - sParcellingForMinSdkVersion.parcel(minSdkVersion, dest, flags); - sParcellingForMaxSdkVersion.parcel(maxSdkVersion, dest, flags); - dest.writeInt(initOrder); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - protected ParsedApexSystemServiceImpl(@NonNull android.os.Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - byte flg = in.readByte(); - String _name = sParcellingForName.unparcel(in); - String _jarPath = sParcellingForJarPath.unparcel(in); - String _minSdkVersion = sParcellingForMinSdkVersion.unparcel(in); - String _maxSdkVersion = sParcellingForMaxSdkVersion.unparcel(in); - int _initOrder = in.readInt(); - - this.name = _name; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - this.jarPath = _jarPath; - this.minSdkVersion = _minSdkVersion; - this.maxSdkVersion = _maxSdkVersion; - this.initOrder = _initOrder; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public ParsedApexSystemServiceImpl[] newArray(int size) { - return new ParsedApexSystemServiceImpl[size]; - } - - @Override - public ParsedApexSystemServiceImpl createFromParcel(@NonNull android.os.Parcel in) { - return new ParsedApexSystemServiceImpl(in); - } - }; - - @DataClass.Generated( - time = 1643723578605L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java", - inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedApexSystemService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java deleted file mode 100644 index d3fb29b8aa66..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.R; -import android.annotation.NonNull; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.text.TextUtils; - -import com.android.internal.pm.pkg.component.ParsedApexSystemService; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; - -/** @hide */ -public class ParsedApexSystemServiceUtils { - - @NonNull - public static ParseResult parseApexSystemService( - Resources res, XmlResourceParser parser, ParseInput input) - throws XmlPullParserException, IOException { - final ParsedApexSystemServiceImpl systemService = - new ParsedApexSystemServiceImpl(); - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestApexSystemService); - try { - String className = sa.getString( - R.styleable.AndroidManifestApexSystemService_name); - if (TextUtils.isEmpty(className)) { - return input.error(" does not have name attribute"); - } - - String jarPath = sa.getString( - R.styleable.AndroidManifestApexSystemService_path); - String minSdkVersion = sa.getString( - R.styleable.AndroidManifestApexSystemService_minSdkVersion); - String maxSdkVersion = sa.getString( - R.styleable.AndroidManifestApexSystemService_maxSdkVersion); - int initOrder = sa.getInt(R.styleable.AndroidManifestApexSystemService_initOrder, 0); - - systemService.setName(className) - .setMinSdkVersion(minSdkVersion) - .setMaxSdkVersion(maxSdkVersion) - .setInitOrder(initOrder); - - if (!TextUtils.isEmpty(jarPath)) { - systemService.setJarPath(jarPath); - } - - return input.success(systemService); - } finally { - sa.recycle(); - } - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java deleted file mode 100644 index 62b994724346..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.annotation.StringRes; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedAttribution; -import com.android.internal.util.DataClass; - -import java.util.ArrayList; -import java.util.List; - -/** - * A {@link android.R.styleable#AndroidManifestAttribution <attribution>} tag parsed from the - * manifest. - * - * @hide - */ -@DataClass(genAidl = false, genSetters = true, genBuilder = false, genParcelable = true) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedAttributionImpl implements ParsedAttribution, Parcelable { - - /** Maximum amount of attributions per package */ - static final int MAX_NUM_ATTRIBUTIONS = 10000; - - /** Tag of the attribution */ - private @NonNull String tag; - - /** User visible label fo the attribution */ - private @StringRes int label; - - /** Ids of previously declared attributions this attribution inherits from */ - private @NonNull List inheritFrom; - - public ParsedAttributionImpl() {} - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - /** - * Creates a new ParsedAttributionImpl. - * - * @param tag - * Tag of the attribution - * @param label - * User visible label fo the attribution - * @param inheritFrom - * Ids of previously declared attributions this attribution inherits from - */ - @DataClass.Generated.Member - public ParsedAttributionImpl( - @NonNull String tag, - @StringRes int label, - @NonNull List inheritFrom) { - this.tag = tag; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, tag); - this.label = label; - com.android.internal.util.AnnotationValidations.validate( - StringRes.class, null, label); - this.inheritFrom = inheritFrom; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, inheritFrom); - - // onConstructed(); // You can define this method to get a callback - } - - /** - * Tag of the attribution - */ - @DataClass.Generated.Member - public @NonNull String getTag() { - return tag; - } - - /** - * User visible label fo the attribution - */ - @DataClass.Generated.Member - public @StringRes int getLabel() { - return label; - } - - /** - * Ids of previously declared attributions this attribution inherits from - */ - @DataClass.Generated.Member - public @NonNull List getInheritFrom() { - return inheritFrom; - } - - /** - * Tag of the attribution - */ - @DataClass.Generated.Member - public @NonNull ParsedAttributionImpl setTag(@NonNull String value) { - tag = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, tag); - return this; - } - - /** - * User visible label fo the attribution - */ - @DataClass.Generated.Member - public @NonNull ParsedAttributionImpl setLabel(@StringRes int value) { - label = value; - com.android.internal.util.AnnotationValidations.validate( - StringRes.class, null, label); - return this; - } - - /** - * Ids of previously declared attributions this attribution inherits from - */ - @DataClass.Generated.Member - public @NonNull ParsedAttributionImpl setInheritFrom(@NonNull List value) { - inheritFrom = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, inheritFrom); - return this; - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - dest.writeString(tag); - dest.writeInt(label); - dest.writeStringList(inheritFrom); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - protected ParsedAttributionImpl(@NonNull Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - String _tag = in.readString(); - int _label = in.readInt(); - List _inheritFrom = new ArrayList<>(); - in.readStringList(_inheritFrom); - - this.tag = _tag; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, tag); - this.label = _label; - com.android.internal.util.AnnotationValidations.validate( - StringRes.class, null, label); - this.inheritFrom = _inheritFrom; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, inheritFrom); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public ParsedAttributionImpl[] newArray(int size) { - return new ParsedAttributionImpl[size]; - } - - @Override - public ParsedAttributionImpl createFromParcel(@NonNull Parcel in) { - return new ParsedAttributionImpl(in); - } - }; - - @DataClass.Generated( - time = 1641431950829L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java", - inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java deleted file mode 100644 index 411220ae42e8..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.util.ArraySet; - -import com.android.internal.R; -import com.android.internal.pm.pkg.component.ParsedAttribution; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** @hide */ -public class ParsedAttributionUtils { - - @NonNull - public static ParseResult parseAttribution(Resources res, - XmlResourceParser parser, ParseInput input) - throws IOException, XmlPullParserException { - String attributionTag; - int label; - List inheritFrom = null; - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAttribution); - if (sa == null) { - return input.error(" could not be parsed"); - } - - try { - attributionTag = sa.getNonConfigurationString( - R.styleable.AndroidManifestAttribution_tag, 0); - if (attributionTag == null) { - return input.error(" does not specify android:tag"); - } - if (attributionTag.length() > ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN) { - return input.error("android:tag is too long. Max length is " - + ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN); - } - - label = sa.getResourceId(R.styleable.AndroidManifestAttribution_label, 0); - if (label == Resources.ID_NULL) { - return input.error(" does not specify android:label"); - } - } finally { - sa.recycle(); - } - - int type; - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("inherit-from")) { - sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestAttributionInheritFrom); - if (sa == null) { - return input.error(" could not be parsed"); - } - - try { - String inheritFromId = sa.getNonConfigurationString( - R.styleable.AndroidManifestAttributionInheritFrom_tag, 0); - - if (inheritFrom == null) { - inheritFrom = new ArrayList<>(); - } - inheritFrom.add(inheritFromId); - } finally { - sa.recycle(); - } - } else { - return input.error("Bad element under : " + tagName); - } - } - - if (inheritFrom == null) { - inheritFrom = Collections.emptyList(); - } else { - ((ArrayList) inheritFrom).trimToSize(); - } - - return input.success(new ParsedAttributionImpl(attributionTag, label, inheritFrom)); - } - - /** - * @return Is this set of attributions a valid combination for a single package? - */ - public static boolean isCombinationValid(@Nullable List attributions) { - if (attributions == null) { - return true; - } - - ArraySet attributionTags = new ArraySet<>(attributions.size()); - ArraySet inheritFromAttributionTags = new ArraySet<>(); - - int numAttributions = attributions.size(); - if (numAttributions > ParsedAttributionImpl.MAX_NUM_ATTRIBUTIONS) { - return false; - } - - for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) { - boolean wasAdded = attributionTags.add(attributions.get(attributionNum).getTag()); - if (!wasAdded) { - // feature id is not unique - return false; - } - } - - for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) { - ParsedAttribution feature = attributions.get(attributionNum); - - final List inheritFromList = feature.getInheritFrom(); - int numInheritFrom = inheritFromList.size(); - for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) { - String inheritFrom = inheritFromList.get(inheritFromNum); - - if (attributionTags.contains(inheritFrom)) { - // Cannot inherit from a attribution that is still defined - return false; - } - - boolean wasAdded = inheritFromAttributionTags.add(inheritFrom); - if (!wasAdded) { - // inheritFrom is not unique - return false; - } - } - } - - return true; - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java deleted file mode 100644 index 512e5c7023c7..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString; - -import static java.util.Collections.emptyMap; - -import android.annotation.CallSuper; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.content.pm.PackageManager.Property; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.ArrayMap; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedComponent; -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.util.CollectionUtils; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * @hide - */ -@DataClass(genGetters = true, genSetters = true, genConstructor = false, genBuilder = false, - genParcelable = false) -@DataClass.Suppress({"setComponentName", "setProperties", "setIntents"}) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable { - - @NonNull - @DataClass.ParcelWith(ForInternedString.class) - private String name; - private int icon; - private int labelRes; - @Nullable - private CharSequence nonLocalizedLabel; - private int logo; - private int banner; - private int descriptionRes; - - // TODO(b/135203078): Replace flags with individual booleans, scoped by subclass - private int flags; - - @NonNull - @DataClass.ParcelWith(ForInternedString.class) - private String packageName; - - @NonNull - @DataClass.PluralOf("intent") - private List intents = Collections.emptyList(); - - @Nullable - private ComponentName componentName; - - @Nullable - private Bundle metaData; - - @NonNull - private Map mProperties = emptyMap(); - - public ParsedComponentImpl() { - - } - - protected ParsedComponentImpl(ParsedComponent other) { - this.metaData = other.getMetaData(); - this.name = other.getName(); - this.icon = other.getIcon(); - this.labelRes = other.getLabelRes(); - this.nonLocalizedLabel = other.getNonLocalizedLabel(); - this.logo = other.getLogo(); - this.banner = other.getBanner(); - this.descriptionRes = other.getDescriptionRes(); - this.flags = other.getFlags(); - this.packageName = other.getPackageName(); - this.componentName = other.getComponentName(); - this.intents = new ArrayList<>(((ParsedComponentImpl) other).intents); - this.mProperties = new ArrayMap<>(); - this.mProperties.putAll(other.getProperties()); - } - - public void addIntent(ParsedIntentInfoImpl intent) { - this.intents = CollectionUtils.add(this.intents, intent); - } - - /** - * Add a property to the component - */ - public void addProperty(@NonNull Property property) { - this.mProperties = CollectionUtils.add(this.mProperties, property.getName(), property); - } - - public ParsedComponentImpl setName(String name) { - this.name = TextUtils.safeIntern(name); - return this; - } - - @CallSuper - public void setPackageName(@NonNull String packageName) { - this.packageName = TextUtils.safeIntern(packageName); - //noinspection ConstantConditions - this.componentName = null; - - // Note: this method does not edit name (which can point to a class), because this package - // name change is not changing the package in code, but the identifier used by the system. - } - - @Override - @NonNull - public ComponentName getComponentName() { - if (componentName == null) { - componentName = new ComponentName(getPackageName(), getName()); - } - return componentName; - } - - @NonNull - @Override - public Bundle getMetaData() { - return metaData == null ? Bundle.EMPTY : metaData; - } - - @NonNull - @Override - public List getIntents() { - return new ArrayList<>(intents); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(this.name); - dest.writeInt(this.getIcon()); - dest.writeInt(this.getLabelRes()); - dest.writeCharSequence(this.getNonLocalizedLabel()); - dest.writeInt(this.getLogo()); - dest.writeInt(this.getBanner()); - dest.writeInt(this.getDescriptionRes()); - dest.writeInt(this.getFlags()); - sForInternedString.parcel(this.packageName, dest, flags); - dest.writeTypedList(this.intents); - dest.writeBundle(this.metaData); - dest.writeMap(this.mProperties); - } - - protected ParsedComponentImpl(Parcel in) { - // We use the boot classloader for all classes that we load. - final ClassLoader boot = Object.class.getClassLoader(); - //noinspection ConstantConditions - this.name = in.readString(); - this.icon = in.readInt(); - this.labelRes = in.readInt(); - this.nonLocalizedLabel = in.readCharSequence(); - this.logo = in.readInt(); - this.banner = in.readInt(); - this.descriptionRes = in.readInt(); - this.flags = in.readInt(); - //noinspection ConstantConditions - this.packageName = sForInternedString.unparcel(in); - this.intents = ParsingUtils.createTypedInterfaceList(in, ParsedIntentInfoImpl.CREATOR); - this.metaData = in.readBundle(boot); - this.mProperties = in.readHashMap(boot); - } - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public @NonNull String getName() { - return name; - } - - @DataClass.Generated.Member - public int getIcon() { - return icon; - } - - @DataClass.Generated.Member - public int getLabelRes() { - return labelRes; - } - - @DataClass.Generated.Member - public @Nullable CharSequence getNonLocalizedLabel() { - return nonLocalizedLabel; - } - - @DataClass.Generated.Member - public int getLogo() { - return logo; - } - - @DataClass.Generated.Member - public int getBanner() { - return banner; - } - - @DataClass.Generated.Member - public int getDescriptionRes() { - return descriptionRes; - } - - @DataClass.Generated.Member - public int getFlags() { - return flags; - } - - @DataClass.Generated.Member - public @NonNull String getPackageName() { - return packageName; - } - - @DataClass.Generated.Member - public @NonNull Map getProperties() { - return mProperties; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setIcon( int value) { - icon = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setLabelRes( int value) { - labelRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setNonLocalizedLabel(@NonNull CharSequence value) { - nonLocalizedLabel = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setLogo( int value) { - logo = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setBanner( int value) { - banner = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setDescriptionRes( int value) { - descriptionRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setFlags( int value) { - flags = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedComponentImpl setMetaData(@NonNull Bundle value) { - metaData = value; - return this; - } - - @DataClass.Generated( - time = 1641414207885L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java", - inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map mProperties\n void addIntent(android.content.pm.parsing.component.ParsedIntentInfoImpl)\n void addProperty(android.content.pm.PackageManager.Property)\npublic android.content.pm.parsing.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java deleted file mode 100644 index 9322cf0e90f6..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET; - -import android.annotation.NonNull; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.Property; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.TypedValue; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -/** @hide */ -class ParsedComponentUtils { - - @NonNull - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - static ParseResult parseComponent( - Component component, String tag, ParsingPackage pkg, TypedArray array, - boolean useRoundIcon, ParseInput input, int bannerAttr, int descriptionAttr, - int iconAttr, int labelAttr, int logoAttr, int nameAttr, int roundIconAttr) { - String name = array.getNonConfigurationString(nameAttr, 0); - if (TextUtils.isEmpty(name)) { - return input.error(tag + " does not specify android:name"); - } - - String packageName = pkg.getPackageName(); - String className = ParsingUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { - return input.error(tag + " invalid android:name"); - } - - //noinspection ConstantConditions; null check done above with isEmpty - component.setName(className) - .setPackageName(packageName); - - int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0; - if (roundIconVal != 0) { - component.setIcon(roundIconVal) - .setNonLocalizedLabel(null); - } else { - int iconVal = array.getResourceId(iconAttr, 0); - if (iconVal != 0) { - component.setIcon(iconVal); - component.setNonLocalizedLabel(null); - } - } - - int logoVal = array.getResourceId(logoAttr, 0); - if (logoVal != 0) { - component.setLogo(logoVal); - } - - int bannerVal = array.getResourceId(bannerAttr, 0); - if (bannerVal != 0) { - component.setBanner(bannerVal); - } - - if (descriptionAttr != NOT_SET) { - component.setDescriptionRes(array.getResourceId(descriptionAttr, 0)); - } - - TypedValue v = array.peekValue(labelAttr); - if (v != null) { - component.setLabelRes(v.resourceId); - if (v.resourceId == 0) { - component.setNonLocalizedLabel(v.coerceToString()); - } - } - - return input.success(component); - } - - static ParseResult addMetaData(ParsedComponentImpl component, ParsingPackage pkg, - Resources resources, XmlResourceParser parser, ParseInput input) { - ParseResult result = ParsingPackageUtils.parseMetaData(pkg, component, - resources, parser, "", input); - if (result.isError()) { - return input.error(result); - } - final Property property = result.getResult(); - if (property != null) { - component.setMetaData(property.toBundle(component.getMetaData())); - } - return input.success(component.getMetaData()); - } - - static ParseResult addProperty(ParsedComponentImpl component, ParsingPackage pkg, - Resources resources, XmlResourceParser parser, ParseInput input) { - ParseResult result = ParsingPackageUtils.parseMetaData(pkg, component, - resources, parser, "", input); - if (result.isError()) { - return input.error(result); - } - final Property property = result.getResult(); - if (property != null) { - component.addProperty(property); - } - return input.success(property); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java deleted file mode 100644 index 7bfad14d669a..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedInstrumentation; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; - -/** @hide */ -@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedInstrumentationImpl extends ParsedComponentImpl implements - ParsedInstrumentation, Parcelable { - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String targetPackage; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String targetProcesses; - private boolean handleProfiling; - private boolean functionalTest; - - public ParsedInstrumentationImpl() { - } - - public ParsedInstrumentationImpl setTargetPackage(@Nullable String targetPackage) { - this.targetPackage = TextUtils.safeIntern(targetPackage); - return this; - } - - public ParsedInstrumentationImpl setTargetProcesses(@Nullable String targetProcesses) { - this.targetProcesses = TextUtils.safeIntern(targetProcesses); - return this; - } - - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("Instrumentation{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(' '); - ComponentName.appendShortString(sb, getPackageName(), getName()); - sb.append('}'); - return sb.toString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - sForInternedString.parcel(this.targetPackage, dest, flags); - sForInternedString.parcel(this.targetProcesses, dest, flags); - dest.writeBoolean(this.handleProfiling); - dest.writeBoolean(this.functionalTest); - } - - protected ParsedInstrumentationImpl(Parcel in) { - super(in); - this.targetPackage = sForInternedString.unparcel(in); - this.targetProcesses = sForInternedString.unparcel(in); - this.handleProfiling = in.readByte() != 0; - this.functionalTest = in.readByte() != 0; - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ParsedInstrumentationImpl createFromParcel(Parcel source) { - return new ParsedInstrumentationImpl(source); - } - - @Override - public ParsedInstrumentationImpl[] newArray(int size) { - return new ParsedInstrumentationImpl[size]; - } - }; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedInstrumentationImpl( - @Nullable String targetPackage, - @Nullable String targetProcesses, - boolean handleProfiling, - boolean functionalTest) { - this.targetPackage = targetPackage; - this.targetProcesses = targetProcesses; - this.handleProfiling = handleProfiling; - this.functionalTest = functionalTest; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @Nullable String getTargetPackage() { - return targetPackage; - } - - @DataClass.Generated.Member - public @Nullable String getTargetProcesses() { - return targetProcesses; - } - - @DataClass.Generated.Member - public boolean isHandleProfiling() { - return handleProfiling; - } - - @DataClass.Generated.Member - public boolean isFunctionalTest() { - return functionalTest; - } - - @DataClass.Generated.Member - public @NonNull ParsedInstrumentationImpl setHandleProfiling( boolean value) { - handleProfiling = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedInstrumentationImpl setFunctionalTest( boolean value) { - functionalTest = value; - return this; - } - - @DataClass.Generated( - time = 1641431951575L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java", - inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java deleted file mode 100644 index a7116949b911..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET; - -import android.annotation.NonNull; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; - -import com.android.internal.R; -import com.android.internal.pm.pkg.component.ParsedInstrumentation; -import com.android.internal.pm.pkg.parsing.ParsingPackage; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; - -/** - * @hide - */ -public class ParsedInstrumentationUtils { - - @NonNull - public static ParseResult parseInstrumentation(ParsingPackage pkg, - Resources res, XmlResourceParser parser, boolean useRoundIcon, - ParseInput input) throws IOException, XmlPullParserException { - ParsedInstrumentationImpl - instrumentation = new ParsedInstrumentationImpl(); - String tag = "<" + parser.getName() + ">"; - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation); - try { - ParseResult result = ParsedComponentUtils.parseComponent( - instrumentation, tag, pkg, sa, useRoundIcon, input, - R.styleable.AndroidManifestInstrumentation_banner, - NOT_SET /*descriptionAttr*/, - R.styleable.AndroidManifestInstrumentation_icon, - R.styleable.AndroidManifestInstrumentation_label, - R.styleable.AndroidManifestInstrumentation_logo, - R.styleable.AndroidManifestInstrumentation_name, - R.styleable.AndroidManifestInstrumentation_roundIcon); - if (result.isError()) { - return input.error(result); - } - - // @formatter:off - // Note: don't allow this value to be a reference to a resource - // that may change. - instrumentation.setTargetPackage(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage)) - .setTargetProcesses(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetProcesses)) - .setHandleProfiling(sa.getBoolean(R.styleable.AndroidManifestInstrumentation_handleProfiling, false)) - .setFunctionalTest(sa.getBoolean(R.styleable.AndroidManifestInstrumentation_functionalTest, false)); - // @formatter:on - } finally { - sa.recycle(); - } - - ParseResult result = - ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, instrumentation, input); - - if (result.isError()) { - return input.error(result); - } - - return input.success(result.getResult()); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java deleted file mode 100644 index ab9404310078..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.IntentFilter; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.util.DataClass; - -/** - * @hide - **/ -@DataClass(genGetters = true, genSetters = true, genParcelable = true, genAidl = false, - genBuilder = false, genConstructor = false) -@DataClass.Suppress({"setIntentFilter"}) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedIntentInfoImpl implements ParsedIntentInfo, Parcelable { - - private boolean mHasDefault; - private int mLabelRes; - @Nullable - private CharSequence mNonLocalizedLabel; - private int mIcon; - - @NonNull - private IntentFilter mIntentFilter = new IntentFilter(); - - public ParsedIntentInfoImpl() {} - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public boolean isHasDefault() { - return mHasDefault; - } - - @DataClass.Generated.Member - public int getLabelRes() { - return mLabelRes; - } - - @DataClass.Generated.Member - public @Nullable CharSequence getNonLocalizedLabel() { - return mNonLocalizedLabel; - } - - @DataClass.Generated.Member - public int getIcon() { - return mIcon; - } - - @DataClass.Generated.Member - public @NonNull IntentFilter getIntentFilter() { - return mIntentFilter; - } - - @DataClass.Generated.Member - public @NonNull ParsedIntentInfoImpl setHasDefault( boolean value) { - mHasDefault = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedIntentInfoImpl setLabelRes( int value) { - mLabelRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedIntentInfoImpl setNonLocalizedLabel(@NonNull CharSequence value) { - mNonLocalizedLabel = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedIntentInfoImpl setIcon( int value) { - mIcon = value; - return this; - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - byte flg = 0; - if (mHasDefault) flg |= 0x1; - if (mNonLocalizedLabel != null) flg |= 0x4; - dest.writeByte(flg); - dest.writeInt(mLabelRes); - if (mNonLocalizedLabel != null) dest.writeCharSequence(mNonLocalizedLabel); - dest.writeInt(mIcon); - dest.writeTypedObject(mIntentFilter, flags); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - protected ParsedIntentInfoImpl(@NonNull Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - byte flg = in.readByte(); - boolean hasDefault = (flg & 0x1) != 0; - int labelRes = in.readInt(); - CharSequence nonLocalizedLabel = (flg & 0x4) == 0 ? null : (CharSequence) in.readCharSequence(); - int icon = in.readInt(); - IntentFilter intentFilter = (IntentFilter) in.readTypedObject(IntentFilter.CREATOR); - - this.mHasDefault = hasDefault; - this.mLabelRes = labelRes; - this.mNonLocalizedLabel = nonLocalizedLabel; - this.mIcon = icon; - this.mIntentFilter = intentFilter; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mIntentFilter); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public ParsedIntentInfoImpl[] newArray(int size) { - return new ParsedIntentInfoImpl[size]; - } - - @Override - public ParsedIntentInfoImpl createFromParcel(@NonNull Parcel in) { - return new ParsedIntentInfoImpl(in); - } - }; - - @DataClass.Generated( - time = 1641431952314L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java", - inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java deleted file mode 100644 index e5e214d2292b..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE; - -import android.annotation.NonNull; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.PatternMatcher; -import android.util.Slog; -import android.util.TypedValue; - -import com.android.internal.R; -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Iterator; - -/** @hide */ -public class ParsedIntentInfoUtils { - - private static final String TAG = ParsingUtils.TAG; - - public static final boolean DEBUG = false; - - @NonNull - public static ParseResult parseIntentInfo(String className, - ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs, - boolean allowAutoVerify, ParseInput input) - throws XmlPullParserException, IOException { - ParsedIntentInfoImpl intentInfo = new ParsedIntentInfoImpl(); - IntentFilter intentFilter = intentInfo.getIntentFilter(); - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestIntentFilter); - try { - intentFilter.setPriority( - sa.getInt(R.styleable.AndroidManifestIntentFilter_priority, 0)); - intentFilter.setOrder(sa.getInt(R.styleable.AndroidManifestIntentFilter_order, 0)); - - TypedValue v = sa.peekValue(R.styleable.AndroidManifestIntentFilter_label); - if (v != null) { - intentInfo.setLabelRes(v.resourceId); - if (v.resourceId == 0) { - intentInfo.setNonLocalizedLabel(v.coerceToString()); - } - } - - if (ParsingPackageUtils.sUseRoundIcon) { - intentInfo.setIcon(sa.getResourceId( - R.styleable.AndroidManifestIntentFilter_roundIcon, 0)); - } - - if (intentInfo.getIcon() == 0) { - intentInfo.setIcon( - sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0)); - } - - if (allowAutoVerify) { - intentFilter.setAutoVerify(sa.getBoolean( - R.styleable.AndroidManifestIntentFilter_autoVerify, - false)); - } - } finally { - sa.recycle(); - } - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - final ParseResult result; - String nodeName = parser.getName(); - switch (nodeName) { - case "action": { - String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name"); - if (value == null) { - result = input.error("No value supplied for "); - } else if (value.isEmpty()) { - intentFilter.addAction(value); - // Prior to R, this was not a failure - result = input.deferError("No value supplied for ", - ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY); - } else { - intentFilter.addAction(value); - result = input.success(null); - } - break; - } - case "category": { - String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name"); - if (value == null) { - result = input.error("No value supplied for "); - } else if (value.isEmpty()) { - intentFilter.addCategory(value); - // Prior to R, this was not a failure - result = input.deferError("No value supplied for ", - ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY); - } else { - intentFilter.addCategory(value); - result = input.success(null); - } - break; - } - case "data": - result = parseData(intentInfo, res, parser, allowGlobs, input); - break; - default: - result = ParsingUtils.unknownTag("", pkg, parser, input); - break; - } - - if (result.isError()) { - return input.error(result); - } - } - - intentInfo.setHasDefault(intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)); - - if (DEBUG) { - final StringBuilder cats = new StringBuilder("Intent d="); - cats.append(intentInfo.isHasDefault()); - cats.append(", cat="); - - final Iterator it = intentFilter.categoriesIterator(); - if (it != null) { - while (it.hasNext()) { - cats.append(' '); - cats.append(it.next()); - } - } - Slog.d(TAG, cats.toString()); - } - - return input.success(intentInfo); - } - - @NonNull - private static ParseResult parseData(ParsedIntentInfo intentInfo, - Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) { - IntentFilter intentFilter = intentInfo.getIntentFilter(); - TypedArray sa = resources.obtainAttributes(parser, R.styleable.AndroidManifestData); - try { - String str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_mimeType, 0); - if (str != null) { - try { - intentFilter.addDataType(str); - } catch (IntentFilter.MalformedMimeTypeException e) { - return input.error(e.toString()); - } - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_mimeGroup, 0); - if (str != null) { - intentFilter.addMimeGroup(str); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_scheme, 0); - if (str != null) { - intentFilter.addDataScheme(str); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_ssp, 0); - if (str != null) { - intentFilter.addDataSchemeSpecificPart(str, - PatternMatcher.PATTERN_LITERAL); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_sspPrefix, 0); - if (str != null) { - intentFilter.addDataSchemeSpecificPart(str, - PatternMatcher.PATTERN_PREFIX); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_sspPattern, 0); - if (str != null) { - if (!allowGlobs) { - return input.error( - "sspPattern not allowed here; ssp must be literal"); - } - intentFilter.addDataSchemeSpecificPart(str, - PatternMatcher.PATTERN_SIMPLE_GLOB); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_sspAdvancedPattern, 0); - if (str != null) { - if (!allowGlobs) { - return input.error( - "sspAdvancedPattern not allowed here; ssp must be literal"); - } - intentFilter.addDataSchemeSpecificPart(str, - PatternMatcher.PATTERN_ADVANCED_GLOB); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_sspSuffix, 0); - if (str != null) { - intentFilter.addDataSchemeSpecificPart(str, - PatternMatcher.PATTERN_SUFFIX); - } - - - String host = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_host, 0); - String port = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_port, 0); - if (host != null) { - intentFilter.addDataAuthority(host, port); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_path, 0); - if (str != null) { - intentFilter.addDataPath(str, PatternMatcher.PATTERN_LITERAL); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_pathPrefix, 0); - if (str != null) { - intentFilter.addDataPath(str, PatternMatcher.PATTERN_PREFIX); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_pathPattern, 0); - if (str != null) { - if (!allowGlobs) { - return input.error( - "pathPattern not allowed here; path must be literal"); - } - intentFilter.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_pathAdvancedPattern, 0); - if (str != null) { - if (!allowGlobs) { - return input.error( - "pathAdvancedPattern not allowed here; path must be literal"); - } - intentFilter.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB); - } - - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestData_pathSuffix, 0); - if (str != null) { - intentFilter.addDataPath(str, PatternMatcher.PATTERN_SUFFIX); - } - - - return input.success(null); - } finally { - sa.recycle(); - } - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java deleted file mode 100644 index f322eef8c3a3..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedMainComponent; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; - -import libcore.util.EmptyArray; - -/** - * @hide - */ -@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedMainComponentImpl extends ParsedComponentImpl implements ParsedMainComponent, - Parcelable { - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String processName; - private boolean directBootAware; - private boolean enabled = true; - private boolean exported; - private int order; - - @Nullable - private String splitName; - @Nullable - private String[] attributionTags; - - public ParsedMainComponentImpl() { - } - - public ParsedMainComponentImpl(ParsedMainComponent other) { - super(other); - this.processName = other.getProcessName(); - this.directBootAware = other.isDirectBootAware(); - this.enabled = other.isEnabled(); - this.exported = other.isExported(); - this.order = other.getOrder(); - this.splitName = other.getSplitName(); - this.attributionTags = other.getAttributionTags(); - } - - public ParsedMainComponentImpl setProcessName(String processName) { - this.processName = TextUtils.safeIntern(processName); - return this; - } - - /** - * A main component's name is a class name. This makes code slightly more readable. - */ - public String getClassName() { - return getName(); - } - - @NonNull - @Override - public String[] getAttributionTags() { - return attributionTags == null ? EmptyArray.STRING : attributionTags; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - sForInternedString.parcel(this.processName, dest, flags); - dest.writeBoolean(this.directBootAware); - dest.writeBoolean(this.enabled); - dest.writeBoolean(this.exported); - dest.writeInt(this.order); - dest.writeString(this.splitName); - dest.writeString8Array(this.attributionTags); - } - - protected ParsedMainComponentImpl(Parcel in) { - super(in); - this.processName = sForInternedString.unparcel(in); - this.directBootAware = in.readBoolean(); - this.enabled = in.readBoolean(); - this.exported = in.readBoolean(); - this.order = in.readInt(); - this.splitName = in.readString(); - this.attributionTags = in.createString8Array(); - } - - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ParsedMainComponentImpl createFromParcel(Parcel source) { - return new ParsedMainComponentImpl(source); - } - - @Override - public ParsedMainComponentImpl[] newArray(int size) { - return new ParsedMainComponentImpl[size]; - } - }; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedMainComponentImpl( - @Nullable String processName, - boolean directBootAware, - boolean enabled, - boolean exported, - int order, - @Nullable String splitName, - @Nullable String[] attributionTags) { - this.processName = processName; - this.directBootAware = directBootAware; - this.enabled = enabled; - this.exported = exported; - this.order = order; - this.splitName = splitName; - this.attributionTags = attributionTags; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @Nullable String getProcessName() { - return processName; - } - - @DataClass.Generated.Member - public boolean isDirectBootAware() { - return directBootAware; - } - - @DataClass.Generated.Member - public boolean isEnabled() { - return enabled; - } - - @DataClass.Generated.Member - public boolean isExported() { - return exported; - } - - @DataClass.Generated.Member - public int getOrder() { - return order; - } - - @DataClass.Generated.Member - public @Nullable String getSplitName() { - return splitName; - } - - @DataClass.Generated.Member - public @NonNull ParsedMainComponentImpl setDirectBootAware( boolean value) { - directBootAware = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedMainComponentImpl setEnabled( boolean value) { - enabled = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedMainComponentImpl setExported( boolean value) { - exported = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedMainComponentImpl setOrder( int value) { - order = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedMainComponentImpl setSplitName(@NonNull String value) { - splitName = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedMainComponentImpl setAttributionTags(@NonNull String... value) { - attributionTags = value; - return this; - } - - @DataClass.Generated( - time = 1641414540422L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java", - inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java deleted file mode 100644 index 8268f0fdfa3e..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.IntentFilter; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Build; -import android.util.Slog; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.pm.pkg.component.ParsedMainComponent; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; - -/** @hide */ -class ParsedMainComponentUtils { - - private static final String TAG = ParsingUtils.TAG; - - @NonNull - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - static ParseResult parseMainComponent( - Component component, String tag, String[] separateProcesses, ParsingPackage pkg, - TypedArray array, int flags, boolean useRoundIcon, @Nullable String defaultSplitName, - @NonNull ParseInput input, int bannerAttr, int descriptionAttr, int directBootAwareAttr, - int enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, - int processAttr, int roundIconAttr, int splitNameAttr, int attributionTagsAttr) { - ParseResult result = ParsedComponentUtils.parseComponent(component, tag, pkg, - array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr, - logoAttr, nameAttr, roundIconAttr); - if (result.isError()) { - return result; - } - - if (directBootAwareAttr != NOT_SET) { - component.setDirectBootAware(array.getBoolean(directBootAwareAttr, false)); - if (component.isDirectBootAware()) { - pkg.setPartiallyDirectBootAware(true); - } - } - - if (enabledAttr != NOT_SET) { - component.setEnabled(array.getBoolean(enabledAttr, true)); - } - - if (processAttr != NOT_SET) { - CharSequence processName; - if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { - processName = array.getNonConfigurationString(processAttr, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - processName = array.getNonResourceString(processAttr); - } - - // Backwards-compat, ignore error - ParseResult processNameResult = ComponentParseUtils.buildProcessName( - pkg.getPackageName(), pkg.getProcessName(), processName, flags, - separateProcesses, input); - if (processNameResult.isError()) { - return input.error(processNameResult); - } - - component.setProcessName(processNameResult.getResult()); - } - - if (splitNameAttr != NOT_SET) { - component.setSplitName(array.getNonConfigurationString(splitNameAttr, 0)); - } - - if (defaultSplitName != null && component.getSplitName() == null) { - component.setSplitName(defaultSplitName); - } - - if (attributionTagsAttr != NOT_SET) { - final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0); - if (attributionTags != null) { - component.setAttributionTags(attributionTags.split("\\|")); - } - } - - return input.success(component); - } - - static ParseResult parseIntentFilter( - ParsedMainComponent mainComponent, - ParsingPackage pkg, Resources resources, XmlResourceParser parser, - boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify, - boolean allowImplicitEphemeralVisibility, boolean failOnNoActions, - ParseInput input) throws IOException, XmlPullParserException { - ParseResult intentResult = ParsedIntentInfoUtils.parseIntentInfo( - mainComponent.getName(), pkg, resources, parser, allowGlobs, - allowAutoVerify, input); - if (intentResult.isError()) { - return input.error(intentResult); - } - - ParsedIntentInfo intent = intentResult.getResult(); - IntentFilter intentFilter = intent.getIntentFilter(); - int actionCount = intentFilter.countActions(); - if (actionCount == 0 && failOnNoActions) { - Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseApkPath() + " " - + parser.getPositionDescription()); - // Backward-compat, do not actually fail - return input.success(null); - } - - int intentVisibility; - if (visibleToEphemeral) { - intentVisibility = IntentFilter.VISIBILITY_EXPLICIT; - } else if (allowImplicitEphemeralVisibility - && ComponentParseUtils.isImplicitlyExposedIntent(intent)){ - intentVisibility = IntentFilter.VISIBILITY_IMPLICIT; - } else { - intentVisibility = IntentFilter.VISIBILITY_NONE; - } - intentFilter.setVisibilityToInstantApp(intentVisibility); - - return input.success(intentResult.getResult()); - } - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java deleted file mode 100644 index afe37bc3274c..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedPermissionGroup; -import com.android.internal.util.DataClass; - -/** - * @hide - */ -@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = true, - genAidl = false) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedPermissionGroupImpl extends ParsedComponentImpl implements - ParsedPermissionGroup, Parcelable { - - private int requestDetailRes; - private int backgroundRequestRes; - private int backgroundRequestDetailRes; - private int requestRes; - private int priority; - - public String toString() { - return "PermissionGroup{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + getName() + "}"; - } - - public ParsedPermissionGroupImpl() { - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(requestDetailRes); - dest.writeInt(backgroundRequestRes); - dest.writeInt(backgroundRequestDetailRes); - dest.writeInt(requestRes); - dest.writeInt(priority); - } - - protected ParsedPermissionGroupImpl(@NonNull Parcel in) { - super(in); - this.requestDetailRes = in.readInt(); - this.backgroundRequestRes = in.readInt(); - this.backgroundRequestDetailRes = in.readInt(); - this.requestRes = in.readInt(); - this.priority = in.readInt(); - } - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedPermissionGroupImpl( - int requestDetailRes, - int backgroundRequestRes, - int backgroundRequestDetailRes, - int requestRes, - int priority) { - this.requestDetailRes = requestDetailRes; - this.backgroundRequestRes = backgroundRequestRes; - this.backgroundRequestDetailRes = backgroundRequestDetailRes; - this.requestRes = requestRes; - this.priority = priority; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public int getRequestDetailRes() { - return requestDetailRes; - } - - @DataClass.Generated.Member - public int getBackgroundRequestRes() { - return backgroundRequestRes; - } - - @DataClass.Generated.Member - public int getBackgroundRequestDetailRes() { - return backgroundRequestDetailRes; - } - - @DataClass.Generated.Member - public int getRequestRes() { - return requestRes; - } - - @DataClass.Generated.Member - public int getPriority() { - return priority; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionGroupImpl setRequestDetailRes( int value) { - requestDetailRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionGroupImpl setBackgroundRequestRes( int value) { - backgroundRequestRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionGroupImpl setBackgroundRequestDetailRes( int value) { - backgroundRequestDetailRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionGroupImpl setRequestRes( int value) { - requestRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionGroupImpl setPriority( int value) { - priority = value; - return this; - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public ParsedPermissionGroupImpl[] newArray(int size) { - return new ParsedPermissionGroupImpl[size]; - } - - @Override - public ParsedPermissionGroupImpl createFromParcel(@NonNull Parcel in) { - return new ParsedPermissionGroupImpl(in); - } - }; - - @DataClass.Generated( - time = 1642132854167L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java", - inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override @com.android.internal.util.DataClass.Generated.Member void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.server.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java deleted file mode 100644 index 69e33c8f281e..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.ArraySet; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedPermission; -import com.android.internal.pm.pkg.component.ParsedPermissionGroup; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; -import com.android.internal.util.Parcelling.BuiltIn.ForStringSet; - -import java.util.Collections; -import java.util.Locale; -import java.util.Set; - -/** - * @hide - */ -@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = false) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedPermission, - Parcelable { - - private static final ForStringSet sForStringSet = - Parcelling.Cache.getOrCreate(ForStringSet.class); - - @Nullable - private String backgroundPermission; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String group; - private int requestRes; - private int protectionLevel; - private boolean tree; - @Nullable - private ParsedPermissionGroup parsedPermissionGroup; - @Nullable - private Set knownCerts; - - @VisibleForTesting - public ParsedPermissionImpl() { - } - - public ParsedPermissionGroup getParsedPermissionGroup() { - return parsedPermissionGroup; - } - - public ParsedPermissionImpl setGroup(String group) { - this.group = TextUtils.safeIntern(group); - return this; - } - - protected void setKnownCert(String knownCert) { - // Convert the provided digest to upper case for consistent Set membership - // checks when verifying the signing certificate digests of requesting apps. - this.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); - } - - protected void setKnownCerts(String[] knownCerts) { - this.knownCerts = new ArraySet<>(); - for (String knownCert : knownCerts) { - this.knownCerts.add(knownCert.toUpperCase(Locale.US)); - } - } - - @NonNull - @Override - public Set getKnownCerts() { - return knownCerts == null ? Collections.emptySet() : knownCerts; - } - - public String toString() { - return "Permission{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + getName() + "}"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(this.backgroundPermission); - dest.writeString(this.group); - dest.writeInt(this.requestRes); - dest.writeInt(this.protectionLevel); - dest.writeBoolean(this.tree); - dest.writeParcelable((ParsedPermissionGroupImpl) this.parsedPermissionGroup, flags); - sForStringSet.parcel(knownCerts, dest, flags); - } - - protected ParsedPermissionImpl(Parcel in) { - super(in); - this.backgroundPermission = in.readString(); - this.group = TextUtils.safeIntern(in.readString()); - this.requestRes = in.readInt(); - this.protectionLevel = in.readInt(); - this.tree = in.readBoolean(); - this.parsedPermissionGroup = in.readParcelable( - ParsedPermissionGroupImpl.class.getClassLoader(), ParsedPermissionGroupImpl.class); - this.knownCerts = sForStringSet.unparcel(in); - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ParsedPermissionImpl createFromParcel(Parcel source) { - return new ParsedPermissionImpl(source); - } - - @Override - public ParsedPermissionImpl[] newArray(int size) { - return new ParsedPermissionImpl[size]; - } - }; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedPermissionImpl( - @Nullable String backgroundPermission, - @Nullable String group, - int requestRes, - int protectionLevel, - boolean tree, - @Nullable ParsedPermissionGroupImpl parsedPermissionGroup, - @Nullable Set knownCerts) { - this.backgroundPermission = backgroundPermission; - this.group = group; - this.requestRes = requestRes; - this.protectionLevel = protectionLevel; - this.tree = tree; - this.parsedPermissionGroup = parsedPermissionGroup; - this.knownCerts = knownCerts; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @Nullable String getBackgroundPermission() { - return backgroundPermission; - } - - @DataClass.Generated.Member - public @Nullable String getGroup() { - return group; - } - - @DataClass.Generated.Member - public int getRequestRes() { - return requestRes; - } - - @DataClass.Generated.Member - public int getProtectionLevel() { - return protectionLevel; - } - - @DataClass.Generated.Member - public boolean isTree() { - return tree; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionImpl setBackgroundPermission(@NonNull String value) { - backgroundPermission = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionImpl setRequestRes( int value) { - requestRes = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionImpl setProtectionLevel( int value) { - protectionLevel = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionImpl setTree( boolean value) { - tree = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionImpl setParsedPermissionGroup(@NonNull ParsedPermissionGroup value) { - parsedPermissionGroup = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedPermissionImpl setKnownCerts(@NonNull Set value) { - knownCerts = value; - return this; - } - - @DataClass.Generated( - time = 1641414649731L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java", - inputSignatures = "private static com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable android.content.pm.parsing.component.ParsedPermissionGroupImpl parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic android.content.pm.parsing.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic android.content.pm.parsing.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java deleted file mode 100644 index 4b45d3742a2a..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET; - -import android.annotation.NonNull; -import android.content.pm.PermissionInfo; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Build; -import android.util.ArrayMap; -import android.util.EventLog; -import android.util.Slog; - -import com.android.internal.R; -import com.android.internal.pm.pkg.component.ParsedPermission; -import com.android.internal.pm.pkg.component.ParsedPermissionGroup; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.List; -import java.util.Objects; - -/** - * @hide - */ -public class ParsedPermissionUtils { - - private static final String TAG = ParsingUtils.TAG; - - @NonNull - public static ParseResult parsePermission(ParsingPackage pkg, Resources res, - XmlResourceParser parser, boolean useRoundIcon, ParseInput input) - throws IOException, XmlPullParserException { - String packageName = pkg.getPackageName(); - ParsedPermissionImpl permission = new ParsedPermissionImpl(); - String tag = "<" + parser.getName() + ">"; - ParseResult result; - - try (TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission)) { - result = ParsedComponentUtils.parseComponent( - permission, tag, pkg, sa, useRoundIcon, input, - R.styleable.AndroidManifestPermission_banner, - R.styleable.AndroidManifestPermission_description, - R.styleable.AndroidManifestPermission_icon, - R.styleable.AndroidManifestPermission_label, - R.styleable.AndroidManifestPermission_logo, - R.styleable.AndroidManifestPermission_name, - R.styleable.AndroidManifestPermission_roundIcon); - if (result.isError()) { - return input.error(result); - } - - int maxSdkVersion = sa.getInt(R.styleable.AndroidManifestPermission_maxSdkVersion, -1); - if ((maxSdkVersion != -1) && (maxSdkVersion < Build.VERSION.SDK_INT)) { - return input.success(null); - } - - if (sa.hasValue( - R.styleable.AndroidManifestPermission_backgroundPermission)) { - if ("android".equals(packageName)) { - permission.setBackgroundPermission(sa.getNonResourceString( - R.styleable.AndroidManifestPermission_backgroundPermission)); - } else { - Slog.w(TAG, packageName + " defines a background permission. Only the " - + "'android' package can do that."); - } - } - - // Note: don't allow this value to be a reference to a resource - // that may change. - permission.setGroup(sa.getNonResourceString( - R.styleable.AndroidManifestPermission_permissionGroup)) - .setRequestRes(sa.getResourceId( - R.styleable.AndroidManifestPermission_request, 0)) - .setProtectionLevel(sa.getInt( - R.styleable.AndroidManifestPermission_protectionLevel, - PermissionInfo.PROTECTION_NORMAL)) - .setFlags(sa.getInt( - R.styleable.AndroidManifestPermission_permissionFlags, 0)); - - final int knownCertsResource = sa.getResourceId( - R.styleable.AndroidManifestPermission_knownCerts, 0); - if (knownCertsResource != 0) { - // The knownCerts attribute supports both a string array resource as well as a - // string resource for the case where the permission should only be granted to a - // single known signer. - final String resourceType = res.getResourceTypeName(knownCertsResource); - if (resourceType.equals("array")) { - final String[] knownCerts = res.getStringArray(knownCertsResource); - if (knownCerts != null) { - permission.setKnownCerts(knownCerts); - } - } else { - final String knownCert = res.getString(knownCertsResource); - if (knownCert != null) { - permission.setKnownCert(knownCert); - } - } - if (permission.getKnownCerts().isEmpty()) { - Slog.w(TAG, packageName + " defines a knownSigner permission but" - + " the provided knownCerts resource is null"); - } - } else { - // If the knownCerts resource ID is null check if the app specified a string - // value for the attribute representing a single trusted signer. - final String knownCert = sa.getString( - R.styleable.AndroidManifestPermission_knownCerts); - if (knownCert != null) { - permission.setKnownCert(knownCert); - } - } - - // For now only platform runtime permissions can be restricted - if (!isRuntime(permission) || !"android".equals(permission.getPackageName())) { - permission.setFlags(permission.getFlags() & ~PermissionInfo.FLAG_HARD_RESTRICTED); - permission.setFlags(permission.getFlags() & ~PermissionInfo.FLAG_SOFT_RESTRICTED); - } else { - // The platform does not get to specify conflicting permissions - if ((permission.getFlags() & PermissionInfo.FLAG_HARD_RESTRICTED) != 0 - && (permission.getFlags() & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) { - throw new IllegalStateException("Permission cannot be both soft and hard" - + " restricted: " + permission.getName()); - } - } - } - - permission.setProtectionLevel( - PermissionInfo.fixProtectionLevel(permission.getProtectionLevel())); - - final int otherProtectionFlags = getProtectionFlags(permission) - & ~(PermissionInfo.PROTECTION_FLAG_APPOP | PermissionInfo.PROTECTION_FLAG_INSTANT - | PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY); - if (otherProtectionFlags != 0 - && getProtection(permission) != PermissionInfo.PROTECTION_SIGNATURE - && getProtection(permission) != PermissionInfo.PROTECTION_INTERNAL) { - return input.error(" protectionLevel specifies a non-instant, non-appop," - + " non-runtimeOnly flag but is not based on signature or internal type"); - } - - result = ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, input); - if (result.isError()) { - return input.error(result); - } - - return input.success(result.getResult()); - } - - @NonNull - public static ParseResult parsePermissionTree(ParsingPackage pkg, Resources res, - XmlResourceParser parser, boolean useRoundIcon, ParseInput input) - throws IOException, XmlPullParserException { - ParsedPermissionImpl permission = new ParsedPermissionImpl(); - String tag = "<" + parser.getName() + ">"; - ParseResult result; - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree); - try { - result = ParsedComponentUtils.parseComponent( - permission, tag, pkg, sa, useRoundIcon, input, - R.styleable.AndroidManifestPermissionTree_banner, - NOT_SET /*descriptionAttr*/, - R.styleable.AndroidManifestPermissionTree_icon, - R.styleable.AndroidManifestPermissionTree_label, - R.styleable.AndroidManifestPermissionTree_logo, - R.styleable.AndroidManifestPermissionTree_name, - R.styleable.AndroidManifestPermissionTree_roundIcon); - if (result.isError()) { - return input.error(result); - } - } finally { - sa.recycle(); - } - - int index = permission.getName().indexOf('.'); - if (index > 0) { - index = permission.getName().indexOf('.', index + 1); - } - if (index < 0) { - return input.error(" name has less than three segments: " - + permission.getName()); - } - - permission.setProtectionLevel(PermissionInfo.PROTECTION_NORMAL) - .setTree(true); - - result = ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, input); - if (result.isError()) { - return input.error(result); - } - - return input.success(result.getResult()); - } - - @NonNull - public static ParseResult parsePermissionGroup(ParsingPackage pkg, - Resources res, XmlResourceParser parser, boolean useRoundIcon, ParseInput input) - throws IOException, XmlPullParserException { - ParsedPermissionGroupImpl - permissionGroup = new ParsedPermissionGroupImpl(); - String tag = "<" + parser.getName() + ">"; - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup); - try { - ParseResult result = ParsedComponentUtils.parseComponent( - permissionGroup, tag, pkg, sa, useRoundIcon, input, - R.styleable.AndroidManifestPermissionGroup_banner, - R.styleable.AndroidManifestPermissionGroup_description, - R.styleable.AndroidManifestPermissionGroup_icon, - R.styleable.AndroidManifestPermissionGroup_label, - R.styleable.AndroidManifestPermissionGroup_logo, - R.styleable.AndroidManifestPermissionGroup_name, - R.styleable.AndroidManifestPermissionGroup_roundIcon); - if (result.isError()) { - return input.error(result); - } - - // @formatter:off - permissionGroup.setRequestDetailRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_requestDetail, 0)) - .setBackgroundRequestRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequest, 0)) - .setBackgroundRequestDetailRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequestDetail, 0)) - .setRequestRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_request, 0)) - .setPriority(sa.getInt(R.styleable.AndroidManifestPermissionGroup_priority, 0)) - .setFlags(sa.getInt(R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,0)); - // @formatter:on - } finally { - sa.recycle(); - } - - ParseResult result = ComponentParseUtils.parseAllMetaData(pkg, - res, parser, tag, permissionGroup, input); - if (result.isError()) { - return input.error(result); - } - - return input.success(result.getResult()); - } - - public static boolean isRuntime(@NonNull ParsedPermission permission) { - return getProtection(permission) == PermissionInfo.PROTECTION_DANGEROUS; - } - - public static boolean isAppOp(@NonNull ParsedPermission permission) { - return (permission.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; - } - - @PermissionInfo.Protection - public static int getProtection(@NonNull ParsedPermission permission) { - return permission.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE; - } - - public static int getProtectionFlags(@NonNull ParsedPermission permission) { - return permission.getProtectionLevel() & ~PermissionInfo.PROTECTION_MASK_BASE; - } - - public static int calculateFootprint(@NonNull ParsedPermission permission) { - int size = permission.getName().length(); - CharSequence nonLocalizedLabel = permission.getNonLocalizedLabel(); - if (nonLocalizedLabel != null) { - size += nonLocalizedLabel.length(); - } - return size; - } - - /** - * Determines if a duplicate permission is malformed .i.e. defines different protection level - * or group. - */ - private static boolean isMalformedDuplicate(ParsedPermission p1, ParsedPermission p2) { - // Since a permission tree is also added as a permission with normal protection - // level, we need to skip if the parsedPermission is a permission tree. - if (p1 == null || p2 == null || p1.isTree() || p2.isTree()) { - return false; - } - - if (p1.getProtectionLevel() != p2.getProtectionLevel()) { - return true; - } - if (!Objects.equals(p1.getGroup(), p2.getGroup())) { - return true; - } - - return false; - } - - /** - * @return {@code true} if the package declares malformed duplicate permissions. - */ - public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) { - final List permissions = pkg.getPermissions(); - final int size = permissions.size(); - if (size > 0) { - final ArrayMap checkDuplicatePerm = new ArrayMap<>(size); - for (int i = 0; i < size; i++) { - final ParsedPermission parsedPermission = permissions.get(i); - final String name = parsedPermission.getName(); - final ParsedPermission perm = checkDuplicatePerm.get(name); - if (isMalformedDuplicate(parsedPermission, perm)) { - // Fix for b/213323615 - EventLog.writeEvent(0x534e4554, "213323615"); - return true; - } - checkDuplicatePerm.put(name, parsedPermission); - } - } - return false; - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java deleted file mode 100644 index 40e3670b9261..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static java.util.Collections.emptySet; - -import android.annotation.NonNull; -import android.content.pm.ApplicationInfo; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.ArrayMap; -import android.util.ArraySet; - -import com.android.internal.pm.pkg.component.ParsedProcess; -import com.android.internal.util.CollectionUtils; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling; - -import java.util.Set; - -/** @hide */ -@DataClass(genGetters = true, genSetters = true, genParcelable = true, genAidl = false, - genBuilder = false) -public class ParsedProcessImpl implements ParsedProcess, Parcelable { - - @NonNull - private String name; - - /** @see ParsedProcess#getAppClassNamesByPackage() */ - @NonNull - private ArrayMap appClassNamesByPackage = ArrayMap.EMPTY; - - @NonNull - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) - private Set deniedPermissions = emptySet(); - - @ApplicationInfo.GwpAsanMode - private int gwpAsanMode = ApplicationInfo.GWP_ASAN_DEFAULT; - @ApplicationInfo.MemtagMode - private int memtagMode = ApplicationInfo.MEMTAG_DEFAULT; - @ApplicationInfo.NativeHeapZeroInitialized - private int nativeHeapZeroInitialized = ApplicationInfo.ZEROINIT_DEFAULT; - - public ParsedProcessImpl() { - } - - public ParsedProcessImpl(@NonNull ParsedProcess other) { - name = other.getName(); - appClassNamesByPackage = (other.getAppClassNamesByPackage().size() == 0) - ? ArrayMap.EMPTY : new ArrayMap<>(other.getAppClassNamesByPackage()); - deniedPermissions = new ArraySet<>(other.getDeniedPermissions()); - gwpAsanMode = other.getGwpAsanMode(); - memtagMode = other.getMemtagMode(); - nativeHeapZeroInitialized = other.getNativeHeapZeroInitialized(); - } - - public void addStateFrom(@NonNull ParsedProcess other) { - deniedPermissions = CollectionUtils.addAll(deniedPermissions, other.getDeniedPermissions()); - gwpAsanMode = other.getGwpAsanMode(); - memtagMode = other.getMemtagMode(); - nativeHeapZeroInitialized = other.getNativeHeapZeroInitialized(); - - final ArrayMap oacn = other.getAppClassNamesByPackage(); - for (int i = 0; i < oacn.size(); i++) { - appClassNamesByPackage.put(oacn.keyAt(i), oacn.valueAt(i)); - } - } - - /** - * Sets a custom application name used in this process for a given package. - */ - public void putAppClassNameForPackage(String packageName, String className) { - if (appClassNamesByPackage.size() == 0) { - appClassNamesByPackage = new ArrayMap<>(4); - } - appClassNamesByPackage.put(packageName, className); - } - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - /** - * Creates a new ParsedProcessImpl. - * - */ - @DataClass.Generated.Member - public ParsedProcessImpl( - @NonNull String name, - @NonNull ArrayMap appClassNamesByPackage, - @NonNull Set deniedPermissions, - @ApplicationInfo.GwpAsanMode int gwpAsanMode, - @ApplicationInfo.MemtagMode int memtagMode, - @ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized) { - this.name = name; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - this.appClassNamesByPackage = appClassNamesByPackage; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, appClassNamesByPackage); - this.deniedPermissions = deniedPermissions; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, deniedPermissions); - this.gwpAsanMode = gwpAsanMode; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); - this.memtagMode = memtagMode; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.MemtagMode.class, null, memtagMode); - this.nativeHeapZeroInitialized = nativeHeapZeroInitialized; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.NativeHeapZeroInitialized.class, null, nativeHeapZeroInitialized); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @NonNull String getName() { - return name; - } - - /** - * @see ParsedProcess#getAppClassNamesByPackage() - */ - @DataClass.Generated.Member - public @NonNull ArrayMap getAppClassNamesByPackage() { - return appClassNamesByPackage; - } - - @DataClass.Generated.Member - public @NonNull Set getDeniedPermissions() { - return deniedPermissions; - } - - @DataClass.Generated.Member - public @ApplicationInfo.GwpAsanMode int getGwpAsanMode() { - return gwpAsanMode; - } - - @DataClass.Generated.Member - public @ApplicationInfo.MemtagMode int getMemtagMode() { - return memtagMode; - } - - @DataClass.Generated.Member - public @ApplicationInfo.NativeHeapZeroInitialized int getNativeHeapZeroInitialized() { - return nativeHeapZeroInitialized; - } - - @DataClass.Generated.Member - public @NonNull ParsedProcessImpl setName(@NonNull String value) { - name = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - return this; - } - - /** - * @see ParsedProcess#getAppClassNamesByPackage() - */ - @DataClass.Generated.Member - public @NonNull ParsedProcessImpl setAppClassNamesByPackage(@NonNull ArrayMap value) { - appClassNamesByPackage = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, appClassNamesByPackage); - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProcessImpl setDeniedPermissions(@NonNull Set value) { - deniedPermissions = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, deniedPermissions); - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProcessImpl setGwpAsanMode(@ApplicationInfo.GwpAsanMode int value) { - gwpAsanMode = value; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProcessImpl setMemtagMode(@ApplicationInfo.MemtagMode int value) { - memtagMode = value; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.MemtagMode.class, null, memtagMode); - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProcessImpl setNativeHeapZeroInitialized(@ApplicationInfo.NativeHeapZeroInitialized int value) { - nativeHeapZeroInitialized = value; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.NativeHeapZeroInitialized.class, null, nativeHeapZeroInitialized); - return this; - } - - @DataClass.Generated.Member - static Parcelling> sParcellingForDeniedPermissions = - Parcelling.Cache.get( - Parcelling.BuiltIn.ForInternedStringSet.class); - static { - if (sParcellingForDeniedPermissions == null) { - sParcellingForDeniedPermissions = Parcelling.Cache.put( - new Parcelling.BuiltIn.ForInternedStringSet()); - } - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - dest.writeString(name); - dest.writeMap(appClassNamesByPackage); - sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); - dest.writeInt(gwpAsanMode); - dest.writeInt(memtagMode); - dest.writeInt(nativeHeapZeroInitialized); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - protected ParsedProcessImpl(@NonNull Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - String _name = in.readString(); - ArrayMap _appClassNamesByPackage = new ArrayMap(); - in.readMap(_appClassNamesByPackage, String.class.getClassLoader()); - Set _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); - int _gwpAsanMode = in.readInt(); - int _memtagMode = in.readInt(); - int _nativeHeapZeroInitialized = in.readInt(); - - this.name = _name; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - this.appClassNamesByPackage = _appClassNamesByPackage; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, appClassNamesByPackage); - this.deniedPermissions = _deniedPermissions; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, deniedPermissions); - this.gwpAsanMode = _gwpAsanMode; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); - this.memtagMode = _memtagMode; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.MemtagMode.class, null, memtagMode); - this.nativeHeapZeroInitialized = _nativeHeapZeroInitialized; - com.android.internal.util.AnnotationValidations.validate( - ApplicationInfo.NativeHeapZeroInitialized.class, null, nativeHeapZeroInitialized); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public ParsedProcessImpl[] newArray(int size) { - return new ParsedProcessImpl[size]; - } - - @Override - public ParsedProcessImpl createFromParcel(@NonNull Parcel in) { - return new ParsedProcessImpl(in); - } - }; - - @DataClass.Generated( - time = 1641431953775L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java", - inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java deleted file mode 100644 index a84954950f44..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.content.pm.ApplicationInfo; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.util.ArrayMap; -import android.util.ArraySet; - -import com.android.internal.R; -import com.android.internal.pm.pkg.component.ParsedProcess; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.internal.util.CollectionUtils; -import com.android.internal.util.XmlUtils; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Set; - -/** @hide */ -public class ParsedProcessUtils { - - @NonNull - private static ParseResult> parseDenyPermission(Set perms, - Resources res, XmlResourceParser parser, ParseInput input) - throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission); - try { - String perm = sa.getNonConfigurationString( - R.styleable.AndroidManifestDenyPermission_name, 0); - if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { - perms = CollectionUtils.add(perms, perm); - } - } finally { - sa.recycle(); - } - XmlUtils.skipCurrentTag(parser); - return input.success(perms); - } - - @NonNull - private static ParseResult> parseAllowPermission(Set perms, Resources res, - XmlResourceParser parser, ParseInput input) - throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission); - try { - String perm = sa.getNonConfigurationString( - R.styleable.AndroidManifestAllowPermission_name, 0); - if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { - perms = CollectionUtils.remove(perms, perm); - } - } finally { - sa.recycle(); - } - XmlUtils.skipCurrentTag(parser); - return input.success(perms); - } - - @NonNull - private static ParseResult parseProcess(Set perms, String[] separateProcesses, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, - ParseInput input) throws IOException, XmlPullParserException { - ParsedProcessImpl proc = new ParsedProcessImpl(); - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess); - try { - if (perms != null) { - proc.setDeniedPermissions(new ArraySet<>(perms)); - } - - String processName = sa.getNonConfigurationString( - R.styleable.AndroidManifestProcess_process, 0); - ParseResult processNameResult = ComponentParseUtils.buildProcessName( - pkg.getPackageName(), pkg.getPackageName(), processName, flags, separateProcesses, - input); - if (processNameResult.isError()) { - return input.error(processNameResult); - } - - String packageName = pkg.getPackageName(); - String className = ParsingUtils.buildClassName(packageName, - sa.getNonConfigurationString(R.styleable.AndroidManifestProcess_name, 0)); - - proc.setName(processNameResult.getResult()); - proc.putAppClassNameForPackage(packageName, className); - proc.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1)); - proc.setMemtagMode(sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1)); - if (sa.hasValue(R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized)) { - final boolean v = sa.getBoolean( - R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized, false); - proc.setNativeHeapZeroInitialized( - v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED); - } - } finally { - sa.recycle(); - } - - int type; - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - ParseResult result; - - String tagName = parser.getName(); - switch (tagName) { - case "deny-permission": - ParseResult> denyResult = parseDenyPermission( - proc.getDeniedPermissions(), res, parser, input); - result = denyResult; - if (denyResult.isSuccess()) { - proc.setDeniedPermissions(denyResult.getResult()); - } - break; - case "allow-permission": - ParseResult> allowResult = parseAllowPermission( - proc.getDeniedPermissions(), res, parser, input); - result = allowResult; - if (allowResult.isSuccess()) { - proc.setDeniedPermissions(allowResult.getResult()); - } - break; - default: - result = ParsingUtils.unknownTag("", pkg, parser, input); - break; - } - - if (result.isError()) { - return input.error(result); - } - } - - return input.success(proc); - } - - @NonNull - public static ParseResult> parseProcesses( - String[] separateProcesses, ParsingPackage pkg, Resources res, - XmlResourceParser parser, int flags, ParseInput input) - throws IOException, XmlPullParserException { - Set deniedPerms = null; - ArrayMap processes = new ArrayMap<>(); - - int type; - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - ParseResult result; - - String tagName = parser.getName(); - switch (tagName) { - case "deny-permission": - ParseResult> denyResult = parseDenyPermission(deniedPerms, res, - parser, input); - result = denyResult; - if (denyResult.isSuccess()) { - deniedPerms = denyResult.getResult(); - } - break; - case "allow-permission": - ParseResult> allowResult = parseAllowPermission(deniedPerms, res, - parser, input); - result = allowResult; - if (allowResult.isSuccess()) { - deniedPerms = allowResult.getResult(); - } - break; - case "process": - ParseResult processResult = parseProcess(deniedPerms, - separateProcesses, pkg, res, parser, flags, input); - result = processResult; - if (processResult.isSuccess()) { - ParsedProcess process = processResult.getResult(); - if (processes.put(process.getName(), process) != null) { - result = input.error( - " specified existing name '" + process.getName() + "'"); - } - } - break; - default: - result = ParsingUtils.unknownTag("", pkg, parser, input); - break; - } - - if (result.isError()) { - return input.error(result); - } - - } - - return input.success(processes); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java deleted file mode 100644 index 81a3c17e2bb4..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.content.pm.PathPermission; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.PatternMatcher; -import android.text.TextUtils; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedProvider; -import com.android.internal.util.CollectionUtils; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * @hide - **/ -@DataClass(genSetters = true, genGetters = true, genParcelable = false, genBuilder = false) -@DataClass.Suppress({"setUriPermissionPatterns", "setPathPermissions"}) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedProviderImpl extends ParsedMainComponentImpl implements ParsedProvider, - Parcelable { - - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String authority; - private boolean syncable; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String readPermission; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String writePermission; - private boolean grantUriPermissions; - private boolean forceUriPermissions; - private boolean multiProcess; - private int initOrder; - @NonNull - private List uriPermissionPatterns = Collections.emptyList(); - @NonNull - private List pathPermissions = Collections.emptyList(); - - public ParsedProviderImpl(ParsedProvider other) { - super(other); - - this.authority = other.getAuthority(); - this.syncable = other.isSyncable(); - this.readPermission = other.getReadPermission(); - this.writePermission = other.getWritePermission(); - this.grantUriPermissions = other.isGrantUriPermissions(); - this.forceUriPermissions = other.isForceUriPermissions(); - this.multiProcess = other.isMultiProcess(); - this.initOrder = other.getInitOrder(); - this.uriPermissionPatterns = new ArrayList<>(other.getUriPermissionPatterns()); - this.pathPermissions = new ArrayList<>(other.getPathPermissions()); - } - - public ParsedProviderImpl setReadPermission(String readPermission) { - // Empty string must be converted to null - this.readPermission = TextUtils.isEmpty(readPermission) - ? null : readPermission.intern(); - return this; - } - - public ParsedProviderImpl setWritePermission(String writePermission) { - // Empty string must be converted to null - this.writePermission = TextUtils.isEmpty(writePermission) - ? null : writePermission.intern(); - return this; - } - - @NonNull - public ParsedProviderImpl addUriPermissionPattern(@NonNull PatternMatcher value) { - uriPermissionPatterns = CollectionUtils.add(uriPermissionPatterns, value); - return this; - } - - @NonNull - public ParsedProviderImpl addPathPermission(@NonNull PathPermission value) { - pathPermissions = CollectionUtils.add(pathPermissions, value); - return this; - } - - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("Provider{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(' '); - ComponentName.appendShortString(sb, getPackageName(), getName()); - sb.append('}'); - return sb.toString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(this.authority); - dest.writeBoolean(this.syncable); - sForInternedString.parcel(this.readPermission, dest, flags); - sForInternedString.parcel(this.writePermission, dest, flags); - dest.writeBoolean(this.grantUriPermissions); - dest.writeBoolean(this.forceUriPermissions); - dest.writeBoolean(this.multiProcess); - dest.writeInt(this.initOrder); - dest.writeTypedList(this.uriPermissionPatterns, flags); - dest.writeTypedList(this.pathPermissions, flags); - } - - public ParsedProviderImpl() { - } - - protected ParsedProviderImpl(Parcel in) { - super(in); - this.authority = in.readString(); - this.syncable = in.readBoolean(); - this.readPermission = sForInternedString.unparcel(in); - this.writePermission = sForInternedString.unparcel(in); - this.grantUriPermissions = in.readBoolean(); - this.forceUriPermissions = in.readBoolean(); - this.multiProcess = in.readBoolean(); - this.initOrder = in.readInt(); - this.uriPermissionPatterns = in.createTypedArrayList(PatternMatcher.CREATOR); - this.pathPermissions = in.createTypedArrayList(PathPermission.CREATOR); - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ParsedProviderImpl createFromParcel(Parcel source) { - return new ParsedProviderImpl(source); - } - - @Override - public ParsedProviderImpl[] newArray(int size) { - return new ParsedProviderImpl[size]; - } - }; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedProviderImpl( - @Nullable String authority, - boolean syncable, - @Nullable String readPermission, - @Nullable String writePermission, - boolean grantUriPermissions, - boolean forceUriPermissions, - boolean multiProcess, - int initOrder, - @NonNull List uriPermissionPatterns, - @NonNull List pathPermissions) { - this.authority = authority; - this.syncable = syncable; - this.readPermission = readPermission; - this.writePermission = writePermission; - this.grantUriPermissions = grantUriPermissions; - this.forceUriPermissions = forceUriPermissions; - this.multiProcess = multiProcess; - this.initOrder = initOrder; - this.uriPermissionPatterns = uriPermissionPatterns; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, uriPermissionPatterns); - this.pathPermissions = pathPermissions; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, pathPermissions); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @Nullable String getAuthority() { - return authority; - } - - @DataClass.Generated.Member - public boolean isSyncable() { - return syncable; - } - - @DataClass.Generated.Member - public @Nullable String getReadPermission() { - return readPermission; - } - - @DataClass.Generated.Member - public @Nullable String getWritePermission() { - return writePermission; - } - - @DataClass.Generated.Member - public boolean isGrantUriPermissions() { - return grantUriPermissions; - } - - @DataClass.Generated.Member - public boolean isForceUriPermissions() { - return forceUriPermissions; - } - - @DataClass.Generated.Member - public boolean isMultiProcess() { - return multiProcess; - } - - @DataClass.Generated.Member - public int getInitOrder() { - return initOrder; - } - - @DataClass.Generated.Member - public @NonNull List getUriPermissionPatterns() { - return uriPermissionPatterns; - } - - @DataClass.Generated.Member - public @NonNull List getPathPermissions() { - return pathPermissions; - } - - @DataClass.Generated.Member - public @NonNull ParsedProviderImpl setAuthority(@NonNull String value) { - authority = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProviderImpl setSyncable( boolean value) { - syncable = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProviderImpl setGrantUriPermissions( boolean value) { - grantUriPermissions = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProviderImpl setForceUriPermissions( boolean value) { - forceUriPermissions = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProviderImpl setMultiProcess( boolean value) { - multiProcess = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedProviderImpl setInitOrder( int value) { - initOrder = value; - return this; - } - - @DataClass.Generated( - time = 1642560323360L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java", - inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java deleted file mode 100644 index 0b28a1214072..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.pkg.component.ComponentParseUtils.flag; -import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.IntentFilter; -import android.content.pm.PathPermission; -import android.content.pm.ProviderInfo; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Build; -import android.os.PatternMatcher; -import android.util.Slog; - -import com.android.internal.R; -import com.android.internal.pm.pkg.component.ParsedProvider; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Objects; - -/** @hide */ -public class ParsedProviderUtils { - - private static final String TAG = ParsingUtils.TAG; - - @NonNull - public static ParseResult parseProvider(String[] separateProcesses, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, - boolean useRoundIcon, @Nullable String defaultSplitName, @NonNull ParseInput input) - throws IOException, XmlPullParserException { - String authority; - boolean visibleToEphemeral; - - final int targetSdkVersion = pkg.getTargetSdkVersion(); - final String packageName = pkg.getPackageName(); - final ParsedProviderImpl provider = new ParsedProviderImpl(); - final String tag = parser.getName(); - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProvider); - try { - ParseResult result = - ParsedMainComponentUtils.parseMainComponent(provider, tag, separateProcesses, - pkg, sa, flags, useRoundIcon, defaultSplitName, input, - R.styleable.AndroidManifestProvider_banner, - R.styleable.AndroidManifestProvider_description, - R.styleable.AndroidManifestProvider_directBootAware, - R.styleable.AndroidManifestProvider_enabled, - R.styleable.AndroidManifestProvider_icon, - R.styleable.AndroidManifestProvider_label, - R.styleable.AndroidManifestProvider_logo, - R.styleable.AndroidManifestProvider_name, - R.styleable.AndroidManifestProvider_process, - R.styleable.AndroidManifestProvider_roundIcon, - R.styleable.AndroidManifestProvider_splitName, - R.styleable.AndroidManifestProvider_attributionTags); - if (result.isError()) { - return input.error(result); - } - - authority = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_authorities, 0); - - // For compatibility, applications targeting API level 16 or lower - // should have their content providers exported by default, unless they - // specify otherwise. - provider.setSyncable(sa.getBoolean( - R.styleable.AndroidManifestProvider_syncable, false)) - .setExported(sa.getBoolean(R.styleable.AndroidManifestProvider_exported, - targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1)); - - String permission = sa.getNonConfigurationString( - R.styleable.AndroidManifestProvider_permission, 0); - String readPermission = sa.getNonConfigurationString( - R.styleable.AndroidManifestProvider_readPermission, 0); - if (readPermission == null) { - readPermission = permission; - } - if (readPermission == null) { - provider.setReadPermission(pkg.getPermission()); - } else { - provider.setReadPermission(readPermission); - } - String writePermission = sa.getNonConfigurationString( - R.styleable.AndroidManifestProvider_writePermission, 0); - if (writePermission == null) { - writePermission = permission; - } - if (writePermission == null) { - provider.setWritePermission(pkg.getPermission()); - } else { - provider.setWritePermission(writePermission); - } - - provider.setGrantUriPermissions( - sa.getBoolean(R.styleable.AndroidManifestProvider_grantUriPermissions, false)) - .setForceUriPermissions( - sa.getBoolean(R.styleable.AndroidManifestProvider_forceUriPermissions, - false)) - .setMultiProcess( - sa.getBoolean(R.styleable.AndroidManifestProvider_multiprocess, false)) - .setInitOrder(sa.getInt(R.styleable.AndroidManifestProvider_initOrder, 0)) - .setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SINGLE_USER, - R.styleable.AndroidManifestProvider_singleUser, sa)); - - visibleToEphemeral = sa.getBoolean( - R.styleable.AndroidManifestProvider_visibleToInstantApps, false); - if (visibleToEphemeral) { - provider.setFlags(provider.getFlags() | ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP); - pkg.setVisibleToInstantApps(true); - } - } finally { - sa.recycle(); - } - - if (pkg.isSaveStateDisallowed()) { - // A heavy-weight application can not have providers in its main process - if (Objects.equals(provider.getProcessName(), packageName)) { - return input.error("Heavy-weight applications can not have providers" - + " in main process"); - } - } - - if (authority == null) { - return input.error(" does not include authorities attribute"); - } - if (authority.length() <= 0) { - return input.error(" has empty authorities attribute"); - } - provider.setAuthority(authority); - - return parseProviderTags(pkg, tag, res, parser, visibleToEphemeral, provider, input); - } - - @NonNull - private static ParseResult parseProviderTags(ParsingPackage pkg, String tag, - Resources res, XmlResourceParser parser, boolean visibleToEphemeral, - ParsedProviderImpl provider, ParseInput input) - throws XmlPullParserException, IOException { - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - String name = parser.getName(); - final ParseResult result; - switch (name) { - case "intent-filter": - ParseResult intentResult = ParsedMainComponentUtils - .parseIntentFilter(provider, pkg, res, parser, visibleToEphemeral, - true /*allowGlobs*/, false /*allowAutoVerify*/, - false /*allowImplicitEphemeralVisibility*/, - false /*failOnNoActions*/, input); - result = intentResult; - if (intentResult.isSuccess()) { - ParsedIntentInfoImpl intent = intentResult.getResult(); - IntentFilter intentFilter = intent.getIntentFilter(); - provider.setOrder(Math.max(intentFilter.getOrder(), provider.getOrder())); - provider.addIntent(intent); - } - break; - case "meta-data": - result = ParsedComponentUtils.addMetaData(provider, pkg, res, parser, input); - break; - case "property": - result = ParsedComponentUtils.addProperty(provider, pkg, res, parser, input); - break; - case "grant-uri-permission": { - result = parseGrantUriPermission(provider, pkg, res, parser, input); - break; - } - case "path-permission": { - result = parsePathPermission(provider, pkg, res, parser, input); - break; - } - default: - result = ParsingUtils.unknownTag(tag, pkg, parser, input); - break; - } - - if (result.isError()) { - return input.error(result); - } - } - - return input.success(provider); - } - - @NonNull - private static ParseResult parseGrantUriPermission(ParsedProviderImpl provider, - ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) { - TypedArray sa = resources.obtainAttributes(parser, - R.styleable.AndroidManifestGrantUriPermission); - try { - String name = parser.getName(); - // Pattern has priority over pre/suffix over literal path - PatternMatcher pa = null; - String str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_pathAdvancedPattern, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_ADVANCED_GLOB); - } else { - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); - } else { - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); - } else { - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_pathSuffix, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_SUFFIX); - } else { - str = sa.getNonConfigurationString( - R.styleable.AndroidManifestGrantUriPermission_path, 0); - if (str != null) { - pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); - } - } - } - } - } - - if (pa != null) { - provider.addUriPermissionPattern(pa); - provider.setGrantUriPermissions(true); - } else { - if (RIGID_PARSER) { - return input.error("No path, pathPrefix, or pathPattern for "); - } - - Slog.w(TAG, "Unknown element under : " + name + " at " - + pkg.getBaseApkPath() + " " + parser.getPositionDescription()); - } - - return input.success(provider); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parsePathPermission(ParsedProviderImpl provider, - ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) { - TypedArray sa = resources.obtainAttributes(parser, - R.styleable.AndroidManifestPathPermission); - try { - String name = parser.getName(); - - String permission = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_permission, 0); - String readPermission = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_readPermission, 0); - if (readPermission == null) { - readPermission = permission; - } - String writePermission = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_writePermission, 0); - if (writePermission == null) { - writePermission = permission; - } - - boolean havePerm = false; - if (readPermission != null) { - readPermission = readPermission.intern(); - havePerm = true; - } - if (writePermission != null) { - writePermission = writePermission.intern(); - havePerm = true; - } - - if (!havePerm) { - if (RIGID_PARSER) { - return input.error( - "No readPermission or writePermission for "); - } - Slog.w(TAG, "No readPermission or writePermission for : " - + name + " at " + pkg.getBaseApkPath() + " " - + parser.getPositionDescription()); - return input.success(provider); - } - - // Advanced has priority over simply over prefix over literal - PathPermission pa = null; - String path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0); - if (path != null) { - pa = new PathPermission(path, PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, - writePermission); - } else { - path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathPattern, 0); - if (path != null) { - pa = new PathPermission(path, PatternMatcher.PATTERN_SIMPLE_GLOB, - readPermission, writePermission); - } else { - path = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_pathPrefix, 0); - if (path != null) { - pa = new PathPermission(path, PatternMatcher.PATTERN_PREFIX, readPermission, - writePermission); - } else { - path = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_pathSuffix, 0); - if (path != null) { - pa = new PathPermission(path, PatternMatcher.PATTERN_SUFFIX, - readPermission, writePermission); - } else { - path = sa.getNonConfigurationString( - R.styleable.AndroidManifestPathPermission_path, 0); - if (path != null) { - pa = new PathPermission(path, PatternMatcher.PATTERN_LITERAL, - readPermission, writePermission); - } - } - } - } - } - - if (pa != null) { - provider.addPathPermission(pa); - } else { - if (RIGID_PARSER) { - return input.error( - "No path, pathPrefix, or pathPattern for "); - } - - Slog.w(TAG, "No path, pathPrefix, or pathPattern for : " - + name + " at " + pkg.getBaseApkPath() - + " " - + parser.getPositionDescription()); - } - - return input.success(provider); - } finally { - sa.recycle(); - } - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java deleted file mode 100644 index ca8c45d1383c..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedMainComponent; -import com.android.internal.pm.pkg.component.ParsedService; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; - -/** @hide **/ -@DataClass(genSetters = true, genGetters = true, genParcelable = false, genBuilder = false) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedServiceImpl extends ParsedMainComponentImpl implements ParsedService, - Parcelable { - - private int foregroundServiceType; - @Nullable - @DataClass.ParcelWith(ForInternedString.class) - private String permission; - - public ParsedServiceImpl(ParsedServiceImpl other) { - super(other); - this.foregroundServiceType = other.foregroundServiceType; - this.permission = other.permission; - } - - public ParsedMainComponent setPermission(String permission) { - // Empty string must be converted to null - this.permission = TextUtils.isEmpty(permission) ? null : permission.intern(); - return this; - } - - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("Service{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(' '); - ComponentName.appendShortString(sb, getPackageName(), getName()); - sb.append('}'); - return sb.toString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(this.foregroundServiceType); - sForInternedString.parcel(this.permission, dest, flags); - } - - public ParsedServiceImpl() { - } - - protected ParsedServiceImpl(Parcel in) { - super(in); - this.foregroundServiceType = in.readInt(); - this.permission = sForInternedString.unparcel(in); - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ParsedServiceImpl createFromParcel(Parcel source) { - return new ParsedServiceImpl(source); - } - - @Override - public ParsedServiceImpl[] newArray(int size) { - return new ParsedServiceImpl[size]; - } - }; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedServiceImpl( - int foregroundServiceType, - @Nullable String permission) { - this.foregroundServiceType = foregroundServiceType; - this.permission = permission; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public int getForegroundServiceType() { - return foregroundServiceType; - } - - @DataClass.Generated.Member - public @Nullable String getPermission() { - return permission; - } - - @DataClass.Generated.Member - public @NonNull ParsedServiceImpl setForegroundServiceType( int value) { - foregroundServiceType = value; - return this; - } - - @DataClass.Generated( - time = 1641431954479L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java", - inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends android.content.pm.parsing.component.ParsedMainComponentImpl implements [android.content.pm.parsing.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java deleted file mode 100644 index 171ef594f6fd..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import static com.android.server.pm.pkg.component.ComponentParseUtils.flag; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.ServiceInfo; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseInput.DeferredError; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Build; - -import com.android.internal.R; -import com.android.internal.pm.pkg.component.ParsedService; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.pkg.parsing.ParsingUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Objects; - -/** @hide */ -public class ParsedServiceUtils { - - @NonNull - public static ParseResult parseService(String[] separateProcesses, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, - boolean useRoundIcon, @Nullable String defaultSplitName, @NonNull ParseInput input) - throws XmlPullParserException, IOException { - boolean visibleToEphemeral; - boolean setExported; - - final String packageName = pkg.getPackageName(); - final ParsedServiceImpl service = new ParsedServiceImpl(); - String tag = parser.getName(); - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestService); - try { - ParseResult result = ParsedMainComponentUtils.parseMainComponent( - service, tag, separateProcesses, pkg, sa, flags, useRoundIcon, defaultSplitName, - input, - R.styleable.AndroidManifestService_banner, - R.styleable.AndroidManifestService_description, - R.styleable.AndroidManifestService_directBootAware, - R.styleable.AndroidManifestService_enabled, - R.styleable.AndroidManifestService_icon, - R.styleable.AndroidManifestService_label, - R.styleable.AndroidManifestService_logo, - R.styleable.AndroidManifestService_name, - R.styleable.AndroidManifestService_process, - R.styleable.AndroidManifestService_roundIcon, - R.styleable.AndroidManifestService_splitName, - R.styleable.AndroidManifestService_attributionTags - ); - - if (result.isError()) { - return input.error(result); - } - - setExported = sa.hasValue(R.styleable.AndroidManifestService_exported); - if (setExported) { - service.setExported(sa.getBoolean(R.styleable.AndroidManifestService_exported, - false)); - } - - String permission = sa.getNonConfigurationString( - R.styleable.AndroidManifestService_permission, 0); - service.setPermission(permission != null ? permission : pkg.getPermission()); - - service.setForegroundServiceType(sa.getInt( - R.styleable.AndroidManifestService_foregroundServiceType, - ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE)) - .setFlags(service.getFlags() | (flag(ServiceInfo.FLAG_STOP_WITH_TASK, - R.styleable.AndroidManifestService_stopWithTask, sa) - | flag(ServiceInfo.FLAG_ISOLATED_PROCESS, - R.styleable.AndroidManifestService_isolatedProcess, sa) - | flag(ServiceInfo.FLAG_EXTERNAL_SERVICE, - R.styleable.AndroidManifestService_externalService, sa) - | flag(ServiceInfo.FLAG_USE_APP_ZYGOTE, - R.styleable.AndroidManifestService_useAppZygote, sa) - | flag(ServiceInfo.FLAG_ALLOW_SHARED_ISOLATED_PROCESS, - R.styleable.AndroidManifestService_allowSharedIsolatedProcess, sa) - | flag(ServiceInfo.FLAG_SINGLE_USER, - R.styleable.AndroidManifestService_singleUser, sa))); - - visibleToEphemeral = sa.getBoolean( - R.styleable.AndroidManifestService_visibleToInstantApps, false); - if (visibleToEphemeral) { - service.setFlags(service.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP); - pkg.setVisibleToInstantApps(true); - } - } finally { - sa.recycle(); - } - - if (pkg.isSaveStateDisallowed()) { - // A heavy-weight application can not have services in its main process - // We can do direct compare because we intern all strings. - if (Objects.equals(service.getProcessName(), packageName)) { - return input.error("Heavy-weight applications can not have services " - + "in main process"); - } - } - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - final ParseResult parseResult; - switch (parser.getName()) { - case "intent-filter": - ParseResult intentResult = ParsedMainComponentUtils - .parseIntentFilter(service, pkg, res, parser, visibleToEphemeral, - true /*allowGlobs*/, false /*allowAutoVerify*/, - false /*allowImplicitEphemeralVisibility*/, - false /*failOnNoActions*/, input); - parseResult = intentResult; - if (intentResult.isSuccess()) { - ParsedIntentInfoImpl intent = intentResult.getResult(); - IntentFilter intentFilter = intent.getIntentFilter(); - service.setOrder(Math.max(intentFilter.getOrder(), service.getOrder())); - service.addIntent(intent); - } - break; - case "meta-data": - parseResult = ParsedComponentUtils.addMetaData(service, pkg, res, parser, input); - break; - case "property": - parseResult = - ParsedComponentUtils.addProperty(service, pkg, res, parser, input); - break; - default: - parseResult = ParsingUtils.unknownTag(tag, pkg, parser, input); - break; - } - - if (parseResult.isError()) { - return input.error(parseResult); - } - } - - if (!setExported) { - boolean hasIntentFilters = service.getIntents().size() > 0; - if (hasIntentFilters) { - final ParseResult exportedCheckResult = input.deferError( - service.getName() + ": Targeting S+ (version " + Build.VERSION_CODES.S - + " and above) requires that an explicit value for android:exported be" - + " defined when intent filters are present", - DeferredError.MISSING_EXPORTED_FLAG); - if (exportedCheckResult.isError()) { - return input.error(exportedCheckResult); - } - } - service.setExported(hasIntentFilters); - } - - return input.success(service); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java deleted file mode 100644 index 78377a836651..000000000000 --- a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.component; - -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.pm.pkg.component.ParsedUsesPermission; -import com.android.internal.util.DataClass; -import com.android.internal.util.Parcelling; - -/** - * A {@link android.R.styleable#AndroidManifestUsesPermission - * <uses-permission>} tag parsed from the manifest. - * - * @hide - */ -@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = true, - genAidl = false) -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) -public class ParsedUsesPermissionImpl implements ParsedUsesPermission, Parcelable { - - @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class) - @NonNull - private String name; - - @ParsedUsesPermission.UsesPermissionFlags - private int usesPermissionFlags; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - public ParsedUsesPermissionImpl( - @NonNull String name, - @ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags) { - this.name = name; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - this.usesPermissionFlags = usesPermissionFlags; - com.android.internal.util.AnnotationValidations.validate( - ParsedUsesPermission.UsesPermissionFlags.class, null, usesPermissionFlags); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @NonNull String getName() { - return name; - } - - @DataClass.Generated.Member - public @ParsedUsesPermission.UsesPermissionFlags int getUsesPermissionFlags() { - return usesPermissionFlags; - } - - @DataClass.Generated.Member - public @NonNull ParsedUsesPermissionImpl setName(@NonNull String value) { - name = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - return this; - } - - @DataClass.Generated.Member - public @NonNull ParsedUsesPermissionImpl setUsesPermissionFlags(@ParsedUsesPermission.UsesPermissionFlags int value) { - usesPermissionFlags = value; - com.android.internal.util.AnnotationValidations.validate( - ParsedUsesPermission.UsesPermissionFlags.class, null, usesPermissionFlags); - return this; - } - - @DataClass.Generated.Member - static Parcelling sParcellingForName = - Parcelling.Cache.get( - Parcelling.BuiltIn.ForInternedString.class); - static { - if (sParcellingForName == null) { - sParcellingForName = Parcelling.Cache.put( - new Parcelling.BuiltIn.ForInternedString()); - } - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - sParcellingForName.parcel(name, dest, flags); - dest.writeInt(usesPermissionFlags); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - protected ParsedUsesPermissionImpl(@NonNull Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - String _name = sParcellingForName.unparcel(in); - int _usesPermissionFlags = in.readInt(); - - this.name = _name; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, name); - this.usesPermissionFlags = _usesPermissionFlags; - com.android.internal.util.AnnotationValidations.validate( - ParsedUsesPermission.UsesPermissionFlags.class, null, usesPermissionFlags); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public ParsedUsesPermissionImpl[] newArray(int size) { - return new ParsedUsesPermissionImpl[size]; - } - - @Override - public ParsedUsesPermissionImpl createFromParcel(@NonNull Parcel in) { - return new ParsedUsesPermissionImpl(in); - } - }; - - @DataClass.Generated( - time = 1641431955242L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java", - inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @android.content.pm.parsing.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java deleted file mode 100644 index aa0fb2734382..000000000000 --- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java +++ /dev/null @@ -1,3489 +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.server.pm.pkg.parsing; - -import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.Flags.disallowSdkLibsToBeApps; -import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; -import static android.os.Build.VERSION_CODES.DONUT; -import static android.os.Build.VERSION_CODES.O; -import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; - -import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts; - -import android.annotation.AnyRes; -import android.annotation.CheckResult; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.StyleableRes; -import android.app.ActivityThread; -import android.app.ResourcesManager; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.ConfigurationInfo; -import android.content.pm.FeatureGroupInfo; -import android.content.pm.FeatureInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.Property; -import android.content.pm.Signature; -import android.content.pm.SigningDetails; -import android.content.pm.parsing.ApkLiteParseUtils; -import android.content.pm.parsing.FrameworkParsingPackageUtils; -import android.content.pm.parsing.PackageLite; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseInput.DeferredError; -import android.content.pm.parsing.result.ParseResult; -import android.content.pm.parsing.result.ParseTypeImpl; -import android.content.res.ApkAssets; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.os.Parcel; -import android.os.RemoteException; -import android.os.SystemProperties; -import android.os.Trace; -import android.os.UserHandle; -import android.os.ext.SdkExtensions; -import android.permission.PermissionManager; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.Pair; -import android.util.Slog; -import android.util.SparseArray; -import android.util.SparseIntArray; -import android.util.TypedValue; -import android.util.apk.ApkSignatureVerifier; - -import com.android.internal.R; -import com.android.internal.os.ClassLoaderFactory; -import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.internal.pm.pkg.component.ParsedActivity; -import com.android.internal.pm.pkg.component.ParsedApexSystemService; -import com.android.internal.pm.pkg.component.ParsedAttribution; -import com.android.internal.pm.pkg.component.ParsedComponent; -import com.android.internal.pm.pkg.component.ParsedInstrumentation; -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.pm.pkg.component.ParsedMainComponent; -import com.android.internal.pm.pkg.component.ParsedPermission; -import com.android.internal.pm.pkg.component.ParsedPermissionGroup; -import com.android.internal.pm.pkg.component.ParsedProcess; -import com.android.internal.pm.pkg.component.ParsedProvider; -import com.android.internal.pm.pkg.component.ParsedService; -import com.android.internal.pm.pkg.component.ParsedUsesPermission; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.XmlUtils; -import com.android.server.pm.SharedUidMigration; -import com.android.server.pm.parsing.pkg.PackageImpl; -import com.android.server.pm.permission.CompatibilityPermissionInfo; -import com.android.server.pm.pkg.component.ComponentMutateUtils; -import com.android.server.pm.pkg.component.ComponentParseUtils; -import com.android.server.pm.pkg.component.InstallConstraintsTagParser; -import com.android.server.pm.pkg.component.ParsedActivityImpl; -import com.android.server.pm.pkg.component.ParsedActivityUtils; -import com.android.server.pm.pkg.component.ParsedApexSystemServiceUtils; -import com.android.server.pm.pkg.component.ParsedAttributionUtils; -import com.android.server.pm.pkg.component.ParsedInstrumentationUtils; -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl; -import com.android.server.pm.pkg.component.ParsedIntentInfoUtils; -import com.android.server.pm.pkg.component.ParsedPermissionUtils; -import com.android.server.pm.pkg.component.ParsedProcessUtils; -import com.android.server.pm.pkg.component.ParsedProviderUtils; -import com.android.server.pm.pkg.component.ParsedServiceUtils; -import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl; -import com.android.server.pm.split.DefaultSplitAssetLoader; -import com.android.server.pm.split.SplitAssetDependencyLoader; -import com.android.server.pm.split.SplitAssetLoader; - -import libcore.io.IoUtils; -import libcore.util.EmptyArray; -import libcore.util.HexEncoding; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.PublicKey; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.StringTokenizer; - -/** - * TODO(b/135203078): Differentiate between parse_ methods and some add_ method for whether it - * mutates the passed-in component or not. Or consolidate so all parse_ methods mutate. - * - * @hide - */ -public class ParsingPackageUtils { - - private static final String TAG = ParsingUtils.TAG; - - public static final boolean DEBUG_JAR = false; - public static final boolean DEBUG_BACKUP = false; - public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; - public static final float ASPECT_RATIO_NOT_SET = -1f; - - /** - * File name in an APK for the Android manifest. - */ - public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; - - /** - * Path prefix for apps on expanded storage - */ - public static final String MNT_EXPAND = "/mnt/expand/"; - - public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; - public static final String TAG_APPLICATION = "application"; - public static final String TAG_ATTRIBUTION = "attribution"; - public static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; - public static final String TAG_EAT_COMMENT = "eat-comment"; - public static final String TAG_FEATURE_GROUP = "feature-group"; - public static final String TAG_INSTALL_CONSTRAINTS = "install-constraints"; - public static final String TAG_INSTRUMENTATION = "instrumentation"; - public static final String TAG_KEY_SETS = "key-sets"; - public static final String TAG_MANIFEST = "manifest"; - public static final String TAG_ORIGINAL_PACKAGE = "original-package"; - public static final String TAG_OVERLAY = "overlay"; - public static final String TAG_PACKAGE = "package"; - public static final String TAG_PACKAGE_VERIFIER = "package-verifier"; - public static final String TAG_PERMISSION = "permission"; - public static final String TAG_PERMISSION_GROUP = "permission-group"; - public static final String TAG_PERMISSION_TREE = "permission-tree"; - public static final String TAG_PROFILEABLE = "profileable"; - public static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; - public static final String TAG_QUERIES = "queries"; - public static final String TAG_RECEIVER = "receiver"; - public static final String TAG_RESTRICT_UPDATE = "restrict-update"; - public static final String TAG_SUPPORTS_INPUT = "supports-input"; - public static final String TAG_SUPPORT_SCREENS = "supports-screens"; - public static final String TAG_USES_CONFIGURATION = "uses-configuration"; - public static final String TAG_USES_FEATURE = "uses-feature"; - public static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; - public static final String TAG_USES_PERMISSION = "uses-permission"; - public static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; - public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; - public static final String TAG_USES_SDK = "uses-sdk"; - public static final String TAG_USES_SPLIT = "uses-split"; - - public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; - public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes"; - public static final String METADATA_CAN_DISPLAY_ON_REMOTE_DEVICES = - "android.can_display_on_remote_devices"; - public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY = - "android.activity_window_layout_affinity"; - public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode"; - - public static final int SDK_VERSION = Build.VERSION.SDK_INT; - public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; - - public static boolean sCompatibilityModeEnabled = true; - public static boolean sUseRoundIcon = false; - - public static final int PARSE_DEFAULT_INSTALL_LOCATION = - PackageInfo.INSTALL_LOCATION_UNSPECIFIED; - public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; - - /** - * If set to true, we will only allow package files that exactly match the DTD. Otherwise, we - * try to get as much from the package as we can without failing. This should normally be set to - * false, to support extensions to the DTD in future versions. - */ - public static final boolean RIGID_PARSER = false; - - public static final int PARSE_MUST_BE_APK = 1 << 0; - public static final int PARSE_IGNORE_PROCESSES = 1 << 1; - public static final int PARSE_EXTERNAL_STORAGE = 1 << 3; - public static final int PARSE_IS_SYSTEM_DIR = 1 << 4; - public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5; - public static final int PARSE_ENFORCE_CODE = 1 << 6; - /** - * This flag is applied in the ApkLiteParser. Used by OverlayConfigParser to ignore the checks - * of required system property within the overlay tag. - */ - public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7; - public static final int PARSE_APK_IN_APEX = 1 << 9; - - public static final int PARSE_CHATTY = 1 << 31; - - /** The total maximum number of activities, services, providers and activity-aliases */ - private static final int MAX_NUM_COMPONENTS = 30000; - private static final String MAX_NUM_COMPONENTS_ERR_MSG = - "Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS; - - /** The maximum permission name length. */ - private static final int MAX_PERMISSION_NAME_LENGTH = 512; - - @IntDef(flag = true, prefix = { "PARSE_" }, value = { - PARSE_CHATTY, - PARSE_COLLECT_CERTIFICATES, - PARSE_ENFORCE_CODE, - PARSE_EXTERNAL_STORAGE, - PARSE_IGNORE_PROCESSES, - PARSE_IS_SYSTEM_DIR, - PARSE_MUST_BE_APK, - PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ParseFlags {} - - /** - * @see #parseDefault(ParseInput, File, int, List, boolean) - */ - @NonNull - public static ParseResult parseDefaultOneTime(File file, - @ParseFlags int parseFlags, - @NonNull List splitPermissions, - boolean collectCertificates) { - ParseInput input = ParseTypeImpl.forDefaultParsing().reset(); - return parseDefault(input, file, parseFlags, splitPermissions, collectCertificates); - } - - /** - * For cases outside of PackageManagerService when an APK needs to be parsed as a one-off - * request, without caching the input object and without querying the internal system state for - * feature support. - */ - @NonNull - public static ParseResult parseDefault(ParseInput input, File file, - @ParseFlags int parseFlags, - @NonNull List splitPermissions, - boolean collectCertificates) { - ParseResult result; - - ParsingPackageUtils parser = new ParsingPackageUtils(null /*separateProcesses*/, - null /*displayMetrics*/, splitPermissions, new Callback() { - @Override - public boolean hasFeature(String feature) { - // Assume the device doesn't support anything. This will affect permission - // parsing and will force declarations to include all - // requiredNotFeature permissions and exclude all requiredFeature - // permissions. This mirrors the old behavior. - return false; - } - - @Override - public ParsingPackage startParsingPackage( - @NonNull String packageName, - @NonNull String baseApkPath, - @NonNull String path, - @NonNull TypedArray manifestArray, boolean isCoreApp) { - return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray, - isCoreApp); - } - }); - var parseResult = parser.parsePackage(input, file, parseFlags); - if (parseResult.isError()) { - return input.error(parseResult); - } - - var pkg = parseResult.getResult().hideAsParsed(); - - if (collectCertificates) { - final ParseResult ret = - ParsingPackageUtils.getSigningDetails(input, pkg, false /*skipVerify*/); - if (ret.isError()) { - return input.error(ret); - } - pkg.setSigningDetails(ret.getResult()); - } - - return input.success(pkg); - } - - private final String[] mSeparateProcesses; - private final DisplayMetrics mDisplayMetrics; - @NonNull - private final List mSplitPermissionInfos; - private final Callback mCallback; - - public ParsingPackageUtils(String[] separateProcesses, DisplayMetrics displayMetrics, - @NonNull List splitPermissions, - @NonNull Callback callback) { - mSeparateProcesses = separateProcesses; - mDisplayMetrics = displayMetrics; - mSplitPermissionInfos = splitPermissions; - mCallback = callback; - } - - /** - * Parse the package at the given location. Automatically detects if the package is a monolithic - * style (single APK file) or cluster style (directory of APKs). - *

- * This performs validity checking on cluster style packages, such as requiring identical - * package name and version codes, a single base APK, and unique split names. - *

- * Note that this does not perform signature verification; that must be done separately - * in {@link #getSigningDetails(ParseInput, ParsedPackage, boolean)}. - *

- * If {@code useCaches} is true, the package parser might return a cached result from a previous - * parse of the same {@code packageFile} with the same {@code flags}. Note that this method does - * not check whether {@code packageFile} has changed since the last parse, it's up to callers to - * do so. - */ - public ParseResult parsePackage(ParseInput input, File packageFile, int flags) { - if (packageFile.isDirectory()) { - return parseClusterPackage(input, packageFile, flags); - } else { - return parseMonolithicPackage(input, packageFile, flags); - } - } - - /** - * Parse all APKs contained in the given directory, treating them as a - * single package. This also performs validity checking, such as requiring - * identical package name and version codes, a single base APK, and unique - * split names. - *

- * Note that this does not perform signature verification; that must be done separately - * in {@link #getSigningDetails(ParseInput, ParsedPackage, boolean)}. - */ - private ParseResult parseClusterPackage(ParseInput input, File packageDir, - int flags) { - int liteParseFlags = 0; - if ((flags & PARSE_APK_IN_APEX) != 0) { - liteParseFlags |= PARSE_APK_IN_APEX; - } - final ParseResult liteResult = - ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags); - if (liteResult.isError()) { - return input.error(liteResult); - } - - final PackageLite lite = liteResult.getResult(); - // Build the split dependency tree. - SparseArray splitDependencies = null; - final SplitAssetLoader assetLoader; - if (lite.isIsolatedSplits() && !ArrayUtils.isEmpty(lite.getSplitNames())) { - try { - splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); - assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); - } catch (SplitAssetDependencyLoader.IllegalDependencyException e) { - return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage()); - } - } else { - assetLoader = new DefaultSplitAssetLoader(lite, flags); - } - - try { - final File baseApk = new File(lite.getBaseApkPath()); - boolean shouldSkipComponents = lite.isIsSdkLibrary() && disallowSdkLibsToBeApps(); - final ParseResult result = parseBaseApk(input, baseApk, - lite.getPath(), assetLoader, flags, shouldSkipComponents); - if (result.isError()) { - return input.error(result); - } - - ParsingPackage pkg = result.getResult(); - if (!ArrayUtils.isEmpty(lite.getSplitNames())) { - pkg.asSplit( - lite.getSplitNames(), - lite.getSplitApkPaths(), - lite.getSplitRevisionCodes(), - splitDependencies - ); - final int num = lite.getSplitNames().length; - - for (int i = 0; i < num; i++) { - final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); - final ParseResult split = - parseSplitApk(input, pkg, i, splitAssets, flags); - if (split.isError()) { - return input.error(split); - } - } - } - - pkg.set32BitAbiPreferred(lite.isUse32bitAbi()); - return input.success(pkg); - } catch (IllegalArgumentException e) { - return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK - : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e); - } finally { - IoUtils.closeQuietly(assetLoader); - } - } - - /** - * Parse the given APK file, treating it as as a single monolithic package. - *

- * Note that this does not perform signature verification; that must be done separately - * in {@link #getSigningDetails(ParseInput, ParsedPackage, boolean)}. - */ - private ParseResult parseMonolithicPackage(ParseInput input, File apkFile, - int flags) { - final ParseResult liteResult = - ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags); - if (liteResult.isError()) { - return input.error(liteResult); - } - - final PackageLite lite = liteResult.getResult(); - final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); - try { - boolean shouldSkipComponents = lite.isIsSdkLibrary() && disallowSdkLibsToBeApps(); - final ParseResult result = parseBaseApk(input, - apkFile, - apkFile.getCanonicalPath(), - assetLoader, flags, shouldSkipComponents); - if (result.isError()) { - return input.error(result); - } - - return input.success(result.getResult() - .set32BitAbiPreferred(lite.isUse32bitAbi())); - } catch (IOException e) { - return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to get path: " + apkFile, e); - } finally { - IoUtils.closeQuietly(assetLoader); - } - } - - /** - * Creates ParsingPackage using only PackageLite. - * Missing fields will contain reasonable defaults. - * Used for packageless (aka archived) package installation. - */ - public ParseResult parsePackageFromPackageLite(ParseInput input, - PackageLite lite, int flags) { - final String volumeUuid = getVolumeUuid(lite.getPath()); - final String pkgName = lite.getPackageName(); - - final TypedArray manifestArray = null; - final ParsingPackage pkg = mCallback.startParsingPackage(pkgName, - lite.getBaseApkPath(), lite.getPath(), manifestArray, lite.isCoreApp()); - - final int targetSdk = lite.getTargetSdk(); - final String versionName = null; - final int compileSdkVersion = 0; - final String compileSdkVersionCodeName = null; - final boolean isolatedSplitLoading = false; - - // Normally set from manifestArray. - pkg.setVersionCode(lite.getVersionCode()); - pkg.setVersionCodeMajor(lite.getVersionCodeMajor()); - pkg.setBaseRevisionCode(lite.getBaseRevisionCode()); - pkg.setVersionName(versionName); - pkg.setCompileSdkVersion(compileSdkVersion); - pkg.setCompileSdkVersionCodeName(compileSdkVersionCodeName); - pkg.setIsolatedSplitLoading(isolatedSplitLoading); - pkg.setTargetSdkVersion(targetSdk); - - // parseBaseApkTags - pkg.setInstallLocation(lite.getInstallLocation()) - .setTargetSandboxVersion(PARSE_DEFAULT_TARGET_SANDBOX) - /* Set the global "on SD card" flag */ - .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0); - - var archivedPackage = lite.getArchivedPackage(); - if (archivedPackage == null) { - return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "archivePackage is missing"); - } - - // parseBaseAppBasicFlags - pkg - // Default true - .setBackupAllowed(true) - .setClearUserDataAllowed(true) - .setClearUserDataOnFailedRestoreAllowed(true) - .setAllowNativeHeapPointerTagging(true) - .setEnabled(true) - .setExtractNativeLibrariesRequested(true) - // targetSdkVersion gated - .setAllowAudioPlaybackCapture(targetSdk >= Build.VERSION_CODES.Q) - .setHardwareAccelerated(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) - .setRequestLegacyExternalStorage( - XmlUtils.convertValueToBoolean(archivedPackage.requestLegacyExternalStorage, - targetSdk < Build.VERSION_CODES.Q)) - .setCleartextTrafficAllowed(targetSdk < Build.VERSION_CODES.P) - // Default false - .setDefaultToDeviceProtectedStorage(XmlUtils.convertValueToBoolean( - archivedPackage.defaultToDeviceProtectedStorage, false)) - .setUserDataFragile( - XmlUtils.convertValueToBoolean(archivedPackage.userDataFragile, false)) - // Ints - .setCategory(ApplicationInfo.CATEGORY_UNDEFINED) - // Floats Default 0f - .setMaxAspectRatio(0f) - .setMinAspectRatio(0f); - - // No APK - no code. - pkg.setDeclaredHavingCode(false); - - final String taskAffinity = null; - ParseResult taskAffinityResult = ComponentParseUtils.buildTaskAffinityName( - pkgName, pkgName, taskAffinity, input); - if (taskAffinityResult.isError()) { - return input.error(taskAffinityResult); - } - pkg.setTaskAffinity(taskAffinityResult.getResult()); - - final CharSequence pname = null; - ParseResult processNameResult = ComponentParseUtils.buildProcessName( - pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input); - if (processNameResult.isError()) { - return input.error(processNameResult); - } - pkg.setProcessName(processNameResult.getResult()); - - pkg.setGwpAsanMode(-1); - pkg.setMemtagMode(-1); - - afterParseBaseApplication(pkg); - - final ParseResult result = validateBaseApkTags(input, pkg); - if (result.isError()) { - return result; - } - - pkg.setVolumeUuid(volumeUuid); - - if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { - pkg.setSigningDetails(lite.getSigningDetails()); - } else { - pkg.setSigningDetails(SigningDetails.UNKNOWN); - } - - return input.success(pkg - .set32BitAbiPreferred(lite.isUse32bitAbi())); - } - - private static String getVolumeUuid(final String apkPath) { - String volumeUuid = null; - if (apkPath.startsWith(MNT_EXPAND)) { - final int end = apkPath.indexOf('/', MNT_EXPAND.length()); - volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); - } - return volumeUuid; - } - - private ParseResult parseBaseApk(ParseInput input, File apkFile, - String codePath, SplitAssetLoader assetLoader, int flags, - boolean shouldSkipComponents) { - final String apkPath = apkFile.getAbsolutePath(); - - final String volumeUuid = getVolumeUuid(apkPath); - - if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); - - final AssetManager assets; - try { - assets = assetLoader.getBaseAssetManager(); - } catch (IllegalArgumentException e) { - return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK - : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e); - } - final int cookie = assets.findCookieForPath(apkPath); - if (cookie == 0) { - return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Failed adding asset path: " + apkPath); - } - - try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, - ANDROID_MANIFEST_FILENAME)) { - final Resources res = new Resources(assets, mDisplayMetrics, null); - - ParseResult result = parseBaseApk(input, apkPath, codePath, res, - parser, flags, shouldSkipComponents); - if (result.isError()) { - return input.error(result.getErrorCode(), - apkPath + " (at " + parser.getPositionDescription() + "): " - + result.getErrorMessage()); - } - - final ParsingPackage pkg = result.getResult(); - if (assets.containsAllocatedTable()) { - final ParseResult deferResult = input.deferError( - "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires" - + " the resources.arsc of installed APKs to be stored uncompressed" - + " and aligned on a 4-byte boundary", - DeferredError.RESOURCES_ARSC_COMPRESSED); - if (deferResult.isError()) { - return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED, - deferResult.getErrorMessage()); - } - } - - ApkAssets apkAssets = assetLoader.getBaseApkAssets(); - boolean definesOverlayable = false; - try { - definesOverlayable = apkAssets.definesOverlayable(); - } catch (IOException ignored) { - // Will fail if there's no packages in the ApkAssets, which can be treated as false - } - - if (definesOverlayable) { - SparseArray packageNames = assets.getAssignedPackageIdentifiers(); - int size = packageNames.size(); - for (int index = 0; index < size; index++) { - String packageName = packageNames.valueAt(index); - Map overlayableToActor = assets.getOverlayableMap(packageName); - if (overlayableToActor != null && !overlayableToActor.isEmpty()) { - for (String overlayable : overlayableToActor.keySet()) { - pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable)); - } - } - } - } - - pkg.setVolumeUuid(volumeUuid); - - if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { - final ParseResult ret = - getSigningDetails(input, pkg, false /*skipVerify*/); - if (ret.isError()) { - return input.error(ret); - } - pkg.setSigningDetails(ret.getResult()); - } else { - pkg.setSigningDetails(SigningDetails.UNKNOWN); - } - - return input.success(pkg); - } catch (Exception e) { - return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to read manifest from " + apkPath, e); - } - } - - private ParseResult parseSplitApk(ParseInput input, - ParsingPackage pkg, int splitIndex, AssetManager assets, int flags) { - final String apkPath = pkg.getSplitCodePaths()[splitIndex]; - - if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); - - // This must always succeed, as the path has been added to the AssetManager before. - final int cookie = assets.findCookieForPath(apkPath); - if (cookie == 0) { - return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Failed adding asset path: " + apkPath); - } - try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, - ANDROID_MANIFEST_FILENAME)) { - Resources res = new Resources(assets, mDisplayMetrics, null); - ParseResult parseResult = parseSplitApk(input, pkg, res, - parser, flags, splitIndex); - if (parseResult.isError()) { - return input.error(parseResult.getErrorCode(), - apkPath + " (at " + parser.getPositionDescription() + "): " - + parseResult.getErrorMessage()); - } - - return parseResult; - } catch (Exception e) { - return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to read manifest from " + apkPath, e); - } - } - - /** - * Parse the manifest of a base APK. When adding new features you need to consider - * whether they should be supported by split APKs and child packages. - * - * @param apkPath The package apk file path - * @param res The resources from which to resolve values - * @param parser The manifest parser - * @param flags Flags how to parse - * @param shouldSkipComponents If the package is a sdk-library - * @return Parsed package or null on error. - */ - private ParseResult parseBaseApk(ParseInput input, String apkPath, - String codePath, Resources res, XmlResourceParser parser, int flags, - boolean shouldSkipComponents) throws XmlPullParserException, IOException { - final String splitName; - final String pkgName; - - ParseResult> packageSplitResult = - ApkLiteParseUtils.parsePackageSplitNames(input, parser); - if (packageSplitResult.isError()) { - return input.error(packageSplitResult); - } - - Pair packageSplit = packageSplitResult.getResult(); - pkgName = packageSplit.first; - splitName = packageSplit.second; - - if (!TextUtils.isEmpty(splitName)) { - return input.error( - PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, - "Expected base APK, but found split " + splitName - ); - } - - final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest); - try { - final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/, - "coreApp", false); - final ParsingPackage pkg = mCallback.startParsingPackage( - pkgName, apkPath, codePath, manifestArray, isCoreApp); - final ParseResult result = - parseBaseApkTags(input, pkg, manifestArray, res, parser, flags, - shouldSkipComponents); - if (result.isError()) { - return result; - } - - return input.success(pkg); - } finally { - manifestArray.recycle(); - } - } - - /** - * Parse the manifest of a split APK. - *

- * Note that split APKs have many more restrictions on what they're capable of doing, so many - * valid features of a base APK have been carefully omitted here. - * - * @param pkg builder to fill - * @return false on failure - */ - private ParseResult parseSplitApk(ParseInput input, ParsingPackage pkg, - Resources res, XmlResourceParser parser, int flags, int splitIndex) - throws XmlPullParserException, IOException { - // We parsed manifest tag earlier; just skip past it - final ParseResult> packageSplitResult = - ApkLiteParseUtils.parsePackageSplitNames(input, parser); - if (packageSplitResult.isError()) { - return input.error(packageSplitResult); - } - - int type; - - boolean foundApp = false; - - int outerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (outerDepth + 1 < parser.getDepth() || type != XmlPullParser.START_TAG) { - continue; - } - - final ParseResult result; - String tagName = parser.getName(); - if (TAG_APPLICATION.equals(tagName)) { - if (foundApp) { - if (RIGID_PARSER) { - result = input.error(" has more than one "); - } else { - Slog.w(TAG, " has more than one "); - result = input.success(null); - } - } else { - foundApp = true; - result = parseSplitApplication(input, pkg, res, parser, flags, splitIndex); - } - } else { - result = ParsingUtils.unknownTag("", pkg, parser, input); - } - - if (result.isError()) { - return input.error(result); - } - } - - if (!foundApp) { - ParseResult deferResult = input.deferError( - " does not contain an ", DeferredError.MISSING_APP_TAG); - if (deferResult.isError()) { - return input.error(deferResult); - } - } - - return input.success(pkg); - } - - /** - * Parse the {@code application} XML tree at the current parse location in a - * split APK manifest. - *

- * Note that split APKs have many more restrictions on what they're capable of doing, so many - * valid features of a base APK have been carefully omitted here. - */ - private ParseResult parseSplitApplication(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex) - throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); - try { - pkg.setSplitHasCode(splitIndex, sa.getBoolean( - R.styleable.AndroidManifestApplication_hasCode, true)); - - final String classLoaderName = sa.getString( - R.styleable.AndroidManifestApplication_classLoader); - if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName( - classLoaderName)) { - pkg.setSplitClassLoaderName(splitIndex, classLoaderName); - } else { - return input.error("Invalid class loader name: " + classLoaderName); - } - } finally { - sa.recycle(); - } - - // If the loaded component did not specify a split, inherit the split name - // based on the split it is defined in. - // This is used to later load the correct split when starting this - // component. - String defaultSplitName = pkg.getSplitNames()[splitIndex]; - - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - ParsedMainComponent mainComponent = null; - - final ParseResult result; - String tagName = parser.getName(); - boolean isActivity = false; - switch (tagName) { - case "activity": - isActivity = true; - // fall-through - case "receiver": - ParseResult activityResult = - ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, - res, parser, flags, sUseRoundIcon, defaultSplitName, input); - if (activityResult.isSuccess()) { - ParsedActivity activity = activityResult.getResult(); - if (isActivity) { - pkg.addActivity(activity); - } else { - pkg.addReceiver(activity); - } - mainComponent = activity; - } - result = activityResult; - break; - case "service": - ParseResult serviceResult = ParsedServiceUtils.parseService( - mSeparateProcesses, pkg, res, parser, flags, sUseRoundIcon, - defaultSplitName, input); - if (serviceResult.isSuccess()) { - ParsedService service = serviceResult.getResult(); - pkg.addService(service); - mainComponent = service; - } - result = serviceResult; - break; - case "provider": - ParseResult providerResult = - ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, - flags, sUseRoundIcon, defaultSplitName, input); - if (providerResult.isSuccess()) { - ParsedProvider provider = providerResult.getResult(); - pkg.addProvider(provider); - mainComponent = provider; - } - result = providerResult; - break; - case "activity-alias": - activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, parser, - sUseRoundIcon, defaultSplitName, input); - if (activityResult.isSuccess()) { - ParsedActivity activity = activityResult.getResult(); - pkg.addActivity(activity); - mainComponent = activity; - } - - result = activityResult; - break; - default: - result = parseSplitBaseAppChildTags(input, tagName, pkg, res, parser); - break; - } - - if (result.isError()) { - return input.error(result); - } - - if (hasTooManyComponents(pkg)) { - return input.error(MAX_NUM_COMPONENTS_ERR_MSG); - } - } - - return input.success(pkg); - } - - private static boolean hasTooManyComponents(ParsingPackage pkg) { - return (pkg.getActivities().size() + pkg.getServices().size() + pkg.getProviders().size() - + pkg.getReceivers().size()) > MAX_NUM_COMPONENTS; - } - - /** - * For parsing non-MainComponents. Main ones have an order and some special handling which is - * done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources, - * XmlResourceParser, int, int)}. - */ - private ParseResult parseSplitBaseAppChildTags(ParseInput input, String tag, ParsingPackage pkg, - Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { - switch (tag) { - case "meta-data": - // note: application meta-data is stored off to the side, so it can - // remain null in the primary copy (we like to avoid extra copies because - // it can be large) - ParseResult metaDataResult = parseMetaData(pkg, null /*component*/, - res, parser, "", input); - if (metaDataResult.isSuccess() && metaDataResult.getResult() != null) { - pkg.setMetaData(metaDataResult.getResult().toBundle(pkg.getMetaData())); - } - return metaDataResult; - case "property": - ParseResult propertyResult = parseMetaData(pkg, null /*component*/, - res, parser, "", input); - if (propertyResult.isSuccess()) { - pkg.addProperty(propertyResult.getResult()); - } - return propertyResult; - case "uses-sdk-library": - return parseUsesSdkLibrary(input, pkg, res, parser); - case "uses-static-library": - return parseUsesStaticLibrary(input, pkg, res, parser); - case "uses-library": - return parseUsesLibrary(input, pkg, res, parser); - case "uses-native-library": - return parseUsesNativeLibrary(input, pkg, res, parser); - case "uses-package": - // Dependencies for app installers; we don't currently try to - // enforce this. - return input.success(null); - default: - return ParsingUtils.unknownTag("", pkg, parser, input); - } - } - private ParseResult parseBaseApkTags(ParseInput input, ParsingPackage pkg, - TypedArray sa, Resources res, XmlResourceParser parser, int flags, - boolean shouldSkipComponents) throws XmlPullParserException, IOException { - ParseResult sharedUserResult = parseSharedUser(input, pkg, sa); - if (sharedUserResult.isError()) { - return sharedUserResult; - } - - final boolean updatableSystem = parser.getAttributeBooleanValue(null /*namespace*/, - "updatableSystem", true); - - pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION, - R.styleable.AndroidManifest_installLocation, sa)) - .setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX, - R.styleable.AndroidManifest_targetSandboxVersion, sa)) - /* Set the global "on SD card" flag */ - .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0) - .setUpdatableSystem(updatableSystem); - - boolean foundApp = false; - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - String tagName = parser.getName(); - final ParseResult result; - - // has special logic, so it's handled outside the general method - if (TAG_APPLICATION.equals(tagName)) { - if (foundApp) { - if (RIGID_PARSER) { - result = input.error(" has more than one "); - } else { - Slog.w(TAG, " has more than one "); - result = input.success(null); - } - } else { - foundApp = true; - result = parseBaseApplication(input, pkg, res, parser, flags, - shouldSkipComponents); - } - } else { - result = parseBaseApkTag(tagName, input, pkg, res, parser, flags); - } - - if (result.isError()) { - return input.error(result); - } - } - - if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) { - ParseResult deferResult = input.deferError( - " does not contain an or ", - DeferredError.MISSING_APP_TAG); - if (deferResult.isError()) { - return input.error(deferResult); - } - } - - return validateBaseApkTags(input, pkg); - } - - private ParseResult validateBaseApkTags(ParseInput input, ParsingPackage pkg) { - if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) { - return input.error( - INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Combination tags are not valid" - ); - } - - if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) { - return input.error( - INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Found duplicate permission with a different attribute value." - ); - } - - convertCompatPermissions(pkg); - - convertSplitPermissions(pkg); - - // At this point we can check if an application is not supporting densities and hence - // cannot be windowed / resized. Note that an SDK version of 0 is common for - // pre-Doughnut applications. - if (pkg.getTargetSdkVersion() < DONUT - || (!pkg.isSmallScreensSupported() - && !pkg.isNormalScreensSupported() - && !pkg.isLargeScreensSupported() - && !pkg.isExtraLargeScreensSupported() - && !pkg.isResizeable() - && !pkg.isAnyDensity())) { - adjustPackageToBeUnresizeableAndUnpipable(pkg); - } - - return input.success(pkg); - } - - private ParseResult parseBaseApkTag(String tag, ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) - throws IOException, XmlPullParserException { - switch (tag) { - case TAG_OVERLAY: - return parseOverlay(input, pkg, res, parser); - case TAG_KEY_SETS: - return parseKeySets(input, pkg, res, parser); - case "feature": // TODO moltmann: Remove - case TAG_ATTRIBUTION: - return parseAttribution(input, pkg, res, parser); - case TAG_PERMISSION_GROUP: - return parsePermissionGroup(input, pkg, res, parser); - case TAG_PERMISSION: - return parsePermission(input, pkg, res, parser); - case TAG_PERMISSION_TREE: - return parsePermissionTree(input, pkg, res, parser); - case TAG_USES_PERMISSION: - case TAG_USES_PERMISSION_SDK_M: - case TAG_USES_PERMISSION_SDK_23: - return parseUsesPermission(input, pkg, res, parser); - case TAG_USES_CONFIGURATION: - return parseUsesConfiguration(input, pkg, res, parser); - case TAG_USES_FEATURE: - return parseUsesFeature(input, pkg, res, parser); - case TAG_FEATURE_GROUP: - return parseFeatureGroup(input, pkg, res, parser); - case TAG_USES_SDK: - return parseUsesSdk(input, pkg, res, parser, flags); - case TAG_SUPPORT_SCREENS: - return parseSupportScreens(input, pkg, res, parser); - case TAG_PROTECTED_BROADCAST: - return parseProtectedBroadcast(input, pkg, res, parser); - case TAG_INSTRUMENTATION: - return parseInstrumentation(input, pkg, res, parser); - case TAG_ORIGINAL_PACKAGE: - return parseOriginalPackage(input, pkg, res, parser); - case TAG_ADOPT_PERMISSIONS: - return parseAdoptPermissions(input, pkg, res, parser); - case TAG_USES_GL_TEXTURE: - case TAG_COMPATIBLE_SCREENS: - case TAG_SUPPORTS_INPUT: - case TAG_EAT_COMMENT: - // Just skip this tag - XmlUtils.skipCurrentTag(parser); - return input.success(pkg); - case TAG_RESTRICT_UPDATE: - return parseRestrictUpdateHash(flags, input, pkg, res, parser); - case TAG_INSTALL_CONSTRAINTS: - return parseInstallConstraints(input, pkg, res, parser); - case TAG_QUERIES: - return parseQueries(input, pkg, res, parser); - default: - return ParsingUtils.unknownTag("", pkg, parser, input); - } - } - - private static ParseResult parseSharedUser(ParseInput input, - ParsingPackage pkg, TypedArray sa) { - String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa); - if (TextUtils.isEmpty(str)) { - return input.success(pkg); - } - - if (!"android".equals(pkg.getPackageName())) { - ParseResult nameResult = FrameworkParsingPackageUtils.validateName(input, str, - true, true); - if (nameResult.isError()) { - return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, - " specifies bad sharedUserId name \"" + str + "\": " - + nameResult.getErrorMessage()); - } - } - - boolean leaving = false; - if (!SharedUidMigration.isDisabled()) { - int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa); - leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT); - } - - return input.success(pkg - .setLeavingSharedUser(leaving) - .setSharedUserId(str.intern()) - .setSharedUserLabelResourceId( - resId(R.styleable.AndroidManifest_sharedUserLabel, sa))); - } - - private static ParseResult parseKeySets(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - // we've encountered the 'key-sets' tag - // all the keys and keysets that we want must be defined here - // so we're going to iterate over the parser and pull out the things we want - int outerDepth = parser.getDepth(); - int currentKeySetDepth = -1; - int type; - String currentKeySet = null; - ArrayMap publicKeys = new ArrayMap<>(); - ArraySet upgradeKeySets = new ArraySet<>(); - ArrayMap> definedKeySets = new ArrayMap<>(); - ArraySet improperKeySets = new ArraySet<>(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG) { - if (parser.getDepth() == currentKeySetDepth) { - currentKeySet = null; - currentKeySetDepth = -1; - } - continue; - } - String tagName = parser.getName(); - switch (tagName) { - case "key-set": { - if (currentKeySet != null) { - return input.error("Improperly nested 'key-set' tag at " - + parser.getPositionDescription()); - } - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestKeySet); - try { - final String keysetName = sa.getNonResourceString( - R.styleable.AndroidManifestKeySet_name); - definedKeySets.put(keysetName, new ArraySet<>()); - currentKeySet = keysetName; - currentKeySetDepth = parser.getDepth(); - } finally { - sa.recycle(); - } - } break; - case "public-key": { - if (currentKeySet == null) { - return input.error("Improperly nested 'key-set' tag at " - + parser.getPositionDescription()); - } - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestPublicKey); - try { - final String publicKeyName = nonResString( - R.styleable.AndroidManifestPublicKey_name, sa); - final String encodedKey = nonResString( - R.styleable.AndroidManifestPublicKey_value, sa); - if (encodedKey == null && publicKeys.get(publicKeyName) == null) { - return input.error("'public-key' " + publicKeyName - + " must define a public-key value on first use at " - + parser.getPositionDescription()); - } else if (encodedKey != null) { - PublicKey currentKey = - FrameworkParsingPackageUtils.parsePublicKey(encodedKey); - if (currentKey == null) { - Slog.w(TAG, "No recognized valid key in 'public-key' tag at " - + parser.getPositionDescription() + " key-set " - + currentKeySet - + " will not be added to the package's defined key-sets."); - improperKeySets.add(currentKeySet); - XmlUtils.skipCurrentTag(parser); - continue; - } - if (publicKeys.get(publicKeyName) == null - || publicKeys.get(publicKeyName).equals(currentKey)) { - - /* public-key first definition, or matches old definition */ - publicKeys.put(publicKeyName, currentKey); - } else { - return input.error("Value of 'public-key' " + publicKeyName - + " conflicts with previously defined value at " - + parser.getPositionDescription()); - } - } - definedKeySets.get(currentKeySet).add(publicKeyName); - XmlUtils.skipCurrentTag(parser); - } finally { - sa.recycle(); - } - } break; - case "upgrade-key-set": { - TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestUpgradeKeySet); - try { - String name = sa.getNonResourceString( - R.styleable.AndroidManifestUpgradeKeySet_name); - upgradeKeySets.add(name); - XmlUtils.skipCurrentTag(parser); - } finally { - sa.recycle(); - } - } break; - default: - ParseResult result = ParsingUtils.unknownTag("", pkg, parser, - input); - if (result.isError()) { - return input.error(result); - } - break; - } - } - String packageName = pkg.getPackageName(); - Set publicKeyNames = publicKeys.keySet(); - if (publicKeyNames.removeAll(definedKeySets.keySet())) { - return input.error("Package" + packageName - + " AndroidManifest.xml 'key-set' and 'public-key' names must be distinct."); - } - - for (ArrayMap.Entry> e : definedKeySets.entrySet()) { - final String keySetName = e.getKey(); - if (e.getValue().size() == 0) { - Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " - + "'key-set' " + keySetName + " has no valid associated 'public-key'." - + " Not including in package's defined key-sets."); - continue; - } else if (improperKeySets.contains(keySetName)) { - Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " - + "'key-set' " + keySetName + " contained improper 'public-key'" - + " tags. Not including in package's defined key-sets."); - continue; - } - - for (String s : e.getValue()) { - pkg.addKeySet(keySetName, publicKeys.get(s)); - } - } - if (pkg.getKeySetMapping().keySet().containsAll(upgradeKeySets)) { - pkg.setUpgradeKeySets(upgradeKeySets); - } else { - return input.error("Package" + packageName - + " AndroidManifest.xml does not define all 'upgrade-key-set's ."); - } - - return input.success(pkg); - } - - private static ParseResult parseAttribution(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws IOException, XmlPullParserException { - ParseResult result = ParsedAttributionUtils.parseAttribution(res, - parser, input); - if (result.isError()) { - return input.error(result); - } - return input.success(pkg.addAttribution(result.getResult())); - } - - private static ParseResult parsePermissionGroup(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - ParseResult result = ParsedPermissionUtils.parsePermissionGroup( - pkg, res, parser, sUseRoundIcon, input); - if (result.isError()) { - return input.error(result); - } - return input.success(pkg.addPermissionGroup(result.getResult())); - } - - private static ParseResult parsePermission(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - ParseResult result = ParsedPermissionUtils.parsePermission( - pkg, res, parser, sUseRoundIcon, input); - if (result.isError()) { - return input.error(result); - } - ParsedPermission permission = result.getResult(); - if (permission != null) { - pkg.addPermission(permission); - } - return input.success(pkg); - } - - private static ParseResult parsePermissionTree(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - ParseResult result = ParsedPermissionUtils.parsePermissionTree( - pkg, res, parser, sUseRoundIcon, input); - if (result.isError()) { - return input.error(result); - } - return input.success(pkg.addPermission(result.getResult())); - } - - private int parseMinOrMaxSdkVersion(TypedArray sa, int attr, int defaultValue) { - int val = defaultValue; - TypedValue peekVal = sa.peekValue(attr); - if (peekVal != null) { - if (peekVal.type >= TypedValue.TYPE_FIRST_INT - && peekVal.type <= TypedValue.TYPE_LAST_INT) { - val = peekVal.data; - } - } - return val; - } - - private ParseResult parseUsesPermission(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws IOException, XmlPullParserException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesPermission); - try { - // Note: don't allow this value to be a reference to a resource - // that may change. - String name = sa.getNonResourceString( - R.styleable.AndroidManifestUsesPermission_name); - if (TextUtils.length(name) > MAX_PERMISSION_NAME_LENGTH) { - return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "The name in the is greater than " - + MAX_PERMISSION_NAME_LENGTH); - } - - int minSdkVersion = parseMinOrMaxSdkVersion(sa, - R.styleable.AndroidManifestUsesPermission_minSdkVersion, - Integer.MIN_VALUE); - - int maxSdkVersion = parseMinOrMaxSdkVersion(sa, - R.styleable.AndroidManifestUsesPermission_maxSdkVersion, - Integer.MAX_VALUE); - - final ArraySet requiredFeatures = new ArraySet<>(); - String feature = sa.getNonConfigurationString( - com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, - 0); - if (feature != null) { - requiredFeatures.add(feature); - } - - final ArraySet requiredNotFeatures = new ArraySet<>(); - feature = sa.getNonConfigurationString( - com.android.internal.R.styleable - .AndroidManifestUsesPermission_requiredNotFeature, - 0); - if (feature != null) { - requiredNotFeatures.add(feature); - } - - final int usesPermissionFlags = sa.getInt( - com.android.internal.R.styleable.AndroidManifestUsesPermission_usesPermissionFlags, - 0); - - final int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - final ParseResult result; - switch (parser.getName()) { - case "required-feature": - result = parseRequiredFeature(input, res, parser); - if (result.isSuccess()) { - requiredFeatures.add((String) result.getResult()); - } - break; - - case "required-not-feature": - result = parseRequiredNotFeature(input, res, parser); - if (result.isSuccess()) { - requiredNotFeatures.add((String) result.getResult()); - } - break; - - default: - result = ParsingUtils.unknownTag("", pkg, parser, input); - break; - } - - if (result.isError()) { - return input.error(result); - } - } - - // Can only succeed from here on out - ParseResult success = input.success(pkg); - - if (name == null) { - return success; - } - - if (Build.VERSION.RESOURCES_SDK_INT < minSdkVersion - || Build.VERSION.RESOURCES_SDK_INT > maxSdkVersion) { - return success; - } - - if (mCallback != null) { - // Only allow requesting this permission if the platform supports all of the - // "required-feature"s. - for (int i = requiredFeatures.size() - 1; i >= 0; i--) { - if (!mCallback.hasFeature(requiredFeatures.valueAt(i))) { - return success; - } - } - - // Only allow requesting this permission if the platform does not supports any of - // the "required-not-feature"s. - for (int i = requiredNotFeatures.size() - 1; i >= 0; i--) { - if (mCallback.hasFeature(requiredNotFeatures.valueAt(i))) { - return success; - } - } - } - - // Quietly ignore duplicate permission requests, but fail loudly if - // the two requests have conflicting flags - boolean found = false; - final List usesPermissions = pkg.getUsesPermissions(); - final int size = usesPermissions.size(); - for (int i = 0; i < size; i++) { - final ParsedUsesPermission usesPermission = usesPermissions.get(i); - if (Objects.equals(usesPermission.getName(), name)) { - if (usesPermission.getUsesPermissionFlags() != usesPermissionFlags) { - return input.error("Conflicting uses-permissions flags: " - + name + " in package: " + pkg.getPackageName() + " at: " - + parser.getPositionDescription()); - } else { - Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " - + name + " in package: " + pkg.getPackageName() + " at: " - + parser.getPositionDescription()); - } - found = true; - break; - } - } - - if (!found) { - pkg.addUsesPermission(new ParsedUsesPermissionImpl(name, usesPermissionFlags)); - } - return success; - } finally { - sa.recycle(); - } - } - - private ParseResult parseRequiredFeature(ParseInput input, Resources res, - AttributeSet attrs) { - final TypedArray sa = res.obtainAttributes(attrs, - com.android.internal.R.styleable.AndroidManifestRequiredFeature); - try { - final String featureName = sa.getString( - R.styleable.AndroidManifestRequiredFeature_name); - return TextUtils.isEmpty(featureName) - ? input.error("Feature name is missing from tag.") - : input.success(featureName); - } finally { - sa.recycle(); - } - } - - private ParseResult parseRequiredNotFeature(ParseInput input, Resources res, - AttributeSet attrs) { - final TypedArray sa = res.obtainAttributes(attrs, - com.android.internal.R.styleable.AndroidManifestRequiredNotFeature); - try { - final String featureName = sa.getString( - R.styleable.AndroidManifestRequiredNotFeature_name); - return TextUtils.isEmpty(featureName) - ? input.error("Feature name is missing from tag.") - : input.success(featureName); - } finally { - sa.recycle(); - } - } - - private static ParseResult parseUsesConfiguration(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - ConfigurationInfo cPref = new ConfigurationInfo(); - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesConfiguration); - try { - cPref.reqTouchScreen = sa.getInt( - R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, - Configuration.TOUCHSCREEN_UNDEFINED); - cPref.reqKeyboardType = sa.getInt( - R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, - Configuration.KEYBOARD_UNDEFINED); - if (sa.getBoolean( - R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, - false)) { - cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; - } - cPref.reqNavigation = sa.getInt( - R.styleable.AndroidManifestUsesConfiguration_reqNavigation, - Configuration.NAVIGATION_UNDEFINED); - if (sa.getBoolean( - R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, - false)) { - cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; - } - pkg.addConfigPreference(cPref); - return input.success(pkg); - } finally { - sa.recycle(); - } - } - - private static ParseResult parseUsesFeature(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - FeatureInfo fi = parseFeatureInfo(res, parser); - pkg.addReqFeature(fi); - - if (fi.name == null) { - ConfigurationInfo cPref = new ConfigurationInfo(); - cPref.reqGlEsVersion = fi.reqGlEsVersion; - pkg.addConfigPreference(cPref); - } - - return input.success(pkg); - } - - private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) { - FeatureInfo fi = new FeatureInfo(); - TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestUsesFeature); - try { - // Note: don't allow this value to be a reference to a resource - // that may change. - fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name); - fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0); - if (fi.name == null) { - fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion, - FeatureInfo.GL_ES_VERSION_UNDEFINED); - } - if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) { - fi.flags |= FeatureInfo.FLAG_REQUIRED; - } - return fi; - } finally { - sa.recycle(); - } - } - - private static ParseResult parseFeatureGroup(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws IOException, XmlPullParserException { - FeatureGroupInfo group = new FeatureGroupInfo(); - ArrayList features = null; - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - final String innerTagName = parser.getName(); - if (innerTagName.equals("uses-feature")) { - FeatureInfo featureInfo = parseFeatureInfo(res, parser); - // FeatureGroups are stricter and mandate that - // any declared are mandatory. - featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; - features = ArrayUtils.add(features, featureInfo); - } else { - Slog.w(TAG, - "Unknown element under : " + innerTagName - + " at " + pkg.getBaseApkPath() + " " - + parser.getPositionDescription()); - } - } - - if (features != null) { - group.features = new FeatureInfo[features.size()]; - group.features = features.toArray(group.features); - } - - pkg.addFeatureGroup(group); - return input.success(pkg); - } - - private static ParseResult parseUsesSdk(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) - throws IOException, XmlPullParserException { - if (SDK_VERSION > 0) { - final boolean isApkInApex = (flags & PARSE_APK_IN_APEX) != 0; - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); - try { - int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION; - String minCode = null; - boolean minAssigned = false; - int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION; - String targetCode = null; - int maxVers = Integer.MAX_VALUE; - - TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion); - if (val != null) { - if (val.type == TypedValue.TYPE_STRING && val.string != null) { - minCode = val.string.toString(); - minAssigned = !TextUtils.isEmpty(minCode); - } else { - // If it's not a string, it's an integer. - minVers = val.data; - minAssigned = true; - } - } - - val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion); - if (val != null) { - if (val.type == TypedValue.TYPE_STRING && val.string != null) { - targetCode = val.string.toString(); - if (!minAssigned) { - minCode = targetCode; - } - } else { - // If it's not a string, it's an integer. - targetVers = val.data; - } - } else { - targetVers = minVers; - targetCode = minCode; - } - - if (isApkInApex) { - val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion); - if (val != null) { - // maxSdkVersion only supports integer - maxVers = val.data; - } - } - - ParseResult targetSdkVersionResult = FrameworkParsingPackageUtils - .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input, - isApkInApex); - if (targetSdkVersionResult.isError()) { - return input.error(targetSdkVersionResult); - } - - int targetSdkVersion = targetSdkVersionResult.getResult(); - - ParseResult deferResult = - input.enableDeferredError(pkg.getPackageName(), targetSdkVersion); - if (deferResult.isError()) { - return input.error(deferResult); - } - - ParseResult minSdkVersionResult = FrameworkParsingPackageUtils - .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, input); - if (minSdkVersionResult.isError()) { - return input.error(minSdkVersionResult); - } - - int minSdkVersion = minSdkVersionResult.getResult(); - - pkg.setMinSdkVersion(minSdkVersion) - .setTargetSdkVersion(targetSdkVersion); - if (isApkInApex) { - ParseResult maxSdkVersionResult = FrameworkParsingPackageUtils - .computeMaxSdkVersion(maxVers, SDK_VERSION, input); - if (maxSdkVersionResult.isError()) { - return input.error(maxSdkVersionResult); - } - int maxSdkVersion = maxSdkVersionResult.getResult(); - pkg.setMaxSdkVersion(maxSdkVersion); - } - - int type; - final int innerDepth = parser.getDepth(); - SparseIntArray minExtensionVersions = null; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - final ParseResult result; - if (parser.getName().equals("extension-sdk")) { - if (minExtensionVersions == null) { - minExtensionVersions = new SparseIntArray(); - } - result = parseExtensionSdk(input, res, parser, minExtensionVersions); - XmlUtils.skipCurrentTag(parser); - } else { - result = ParsingUtils.unknownTag("", pkg, parser, input); - } - - if (result.isError()) { - return input.error(result); - } - } - pkg.setMinExtensionVersions(exactSizedCopyOfSparseArray(minExtensionVersions)); - } finally { - sa.recycle(); - } - } - return input.success(pkg); - } - - @Nullable - private static SparseIntArray exactSizedCopyOfSparseArray(@Nullable SparseIntArray input) { - if (input == null) { - return null; - } - SparseIntArray output = new SparseIntArray(input.size()); - for (int i = 0; i < input.size(); i++) { - output.put(input.keyAt(i), input.valueAt(i)); - } - return output; - } - - private static ParseResult parseExtensionSdk( - ParseInput input, Resources res, XmlResourceParser parser, - SparseIntArray minExtensionVersions) { - int sdkVersion; - int minVersion; - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestExtensionSdk); - try { - sdkVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1); - minVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_minExtensionVersion, -1); - } finally { - sa.recycle(); - } - - if (sdkVersion < 0) { - return input.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - " must specify an sdkVersion >= 0"); - } - if (minVersion < 0) { - return input.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - " must specify minExtensionVersion >= 0"); - } - - try { - int version = SdkExtensions.getExtensionVersion(sdkVersion); - if (version < minVersion) { - return input.error( - PackageManager.INSTALL_FAILED_OLDER_SDK, - "Package requires " + sdkVersion + " extension version " + minVersion - + " which exceeds device version " + version); - } - } catch (RuntimeException e) { - return input.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Specified sdkVersion " + sdkVersion + " is not valid"); - } - minExtensionVersions.put(sdkVersion, minVersion); - return input.success(minExtensionVersions); - } - - private static ParseResult parseRestrictUpdateHash(int flags, ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - if ((flags & PARSE_IS_SYSTEM_DIR) != 0) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestRestrictUpdate); - try { - final String hash = sa.getNonConfigurationString( - R.styleable.AndroidManifestRestrictUpdate_hash, - 0); - - if (hash != null) { - final int hashLength = hash.length(); - final byte[] hashBytes = new byte[hashLength / 2]; - for (int i = 0; i < hashLength; i += 2) { - hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16) - << 4) - + Character.digit(hash.charAt(i + 1), 16)); - } - pkg.setRestrictUpdateHash(hashBytes); - } else { - pkg.setRestrictUpdateHash(null); - } - } finally { - sa.recycle(); - } - } - return input.success(pkg); - } - - private static ParseResult parseInstallConstraints( - ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws IOException, XmlPullParserException { - return InstallConstraintsTagParser.parseInstallConstraints(input, pkg, res, parser); - } - - private static ParseResult parseQueries(ParseInput input, ParsingPackage pkg, - Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - if (parser.getName().equals("intent")) { - ParseResult result = ParsedIntentInfoUtils.parseIntentInfo( - null /*className*/, pkg, res, parser, true /*allowGlobs*/, - true /*allowAutoVerify*/, input); - if (result.isError()) { - return input.error(result); - } - - IntentFilter intentInfo = result.getResult().getIntentFilter(); - - Uri data = null; - String dataType = null; - String host = null; - final int numActions = intentInfo.countActions(); - final int numSchemes = intentInfo.countDataSchemes(); - final int numTypes = intentInfo.countDataTypes(); - final int numHosts = intentInfo.getHosts().length; - if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { - return input.error("intent tags must contain either an action or data."); - } - if (numActions > 1) { - return input.error("intent tag may have at most one action."); - } - if (numTypes > 1) { - return input.error("intent tag may have at most one data type."); - } - if (numSchemes > 1) { - return input.error("intent tag may have at most one data scheme."); - } - if (numHosts > 1) { - return input.error("intent tag may have at most one data host."); - } - Intent intent = new Intent(); - for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { - intent.addCategory(intentInfo.getCategory(i)); - } - if (numHosts == 1) { - host = intentInfo.getHosts()[0]; - } - if (numSchemes == 1) { - data = new Uri.Builder() - .scheme(intentInfo.getDataScheme(0)) - .authority(host) - .path(IntentFilter.WILDCARD_PATH) - .build(); - } - if (numTypes == 1) { - dataType = intentInfo.getDataType(0); - // The dataType may have had the '/' removed for the dynamic mimeType feature. - // If we detect that case, we add the * back. - if (!dataType.contains("/")) { - dataType = dataType + "/*"; - } - if (data == null) { - data = new Uri.Builder() - .scheme("content") - .authority(IntentFilter.WILDCARD) - .path(IntentFilter.WILDCARD_PATH) - .build(); - } - } - intent.setDataAndType(data, dataType); - if (numActions == 1) { - intent.setAction(intentInfo.getAction(0)); - } - pkg.addQueriesIntent(intent); - } else if (parser.getName().equals("package")) { - final TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestQueriesPackage); - final String packageName = sa.getNonConfigurationString( - R.styleable.AndroidManifestQueriesPackage_name, 0); - if (TextUtils.isEmpty(packageName)) { - return input.error("Package name is missing from package tag."); - } - pkg.addQueriesPackage(packageName.intern()); - } else if (parser.getName().equals("provider")) { - final TypedArray sa = res.obtainAttributes(parser, - R.styleable.AndroidManifestQueriesProvider); - try { - final String authorities = sa.getNonConfigurationString( - R.styleable.AndroidManifestQueriesProvider_authorities, 0); - if (TextUtils.isEmpty(authorities)) { - return input.error( - PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, - "Authority missing from provider tag." - ); - } - StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";"); - while (authoritiesTokenizer.hasMoreElements()) { - pkg.addQueriesProvider(authoritiesTokenizer.nextToken()); - } - } finally { - sa.recycle(); - } - } - } - return input.success(pkg); - } - - /** - * Parse the {@code application} XML tree at the current parse location in a - * base APK manifest. - *

- * When adding new features, carefully consider if they should also be supported by split APKs. - *

- * This method should avoid using a getter for fields set by this method. Prefer assigning a - * local variable and using it. Otherwise there's an ordering problem which can be broken if any - * code moves around. - */ - private ParseResult parseBaseApplication(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, - boolean shouldSkipComponents) throws XmlPullParserException, IOException { - final String pkgName = pkg.getPackageName(); - int targetSdk = pkg.getTargetSdkVersion(); - - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); - try { - // TODO(b/135203078): Remove this and force unit tests to mock an empty manifest - // This case can only happen in unit tests where we sometimes need to create fakes - // of various package parser data structures. - if (sa == null) { - return input.error(" does not contain any attributes"); - } - - String name = sa.getNonConfigurationString(R.styleable.AndroidManifestApplication_name, - 0); - if (name != null) { - String packageName = pkg.getPackageName(); - String outInfoName = ParsingUtils.buildClassName(packageName, name); - if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { - return input.error(" invalid android:name"); - } else if (outInfoName == null) { - return input.error("Empty class name in package " + packageName); - } - - pkg.setApplicationClassName(outInfoName); - } - - TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label); - if (labelValue != null) { - pkg.setLabelResourceId(labelValue.resourceId); - if (labelValue.resourceId == 0) { - pkg.setNonLocalizedLabel(labelValue.coerceToString()); - } - } - - parseBaseAppBasicFlags(pkg, sa); - - String manageSpaceActivity = nonConfigString(Configuration.NATIVE_CONFIG_VERSION, - R.styleable.AndroidManifestApplication_manageSpaceActivity, sa); - if (manageSpaceActivity != null) { - String manageSpaceActivityName = ParsingUtils.buildClassName(pkgName, - manageSpaceActivity); - - if (manageSpaceActivityName == null) { - return input.error("Empty class name in package " + pkgName); - } - - pkg.setManageSpaceActivityName(manageSpaceActivityName); - } - - if (pkg.isBackupAllowed()) { - // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, - // and restoreAnyVersion are only relevant if backup is possible for the - // given application. - String backupAgent = nonConfigString(Configuration.NATIVE_CONFIG_VERSION, - R.styleable.AndroidManifestApplication_backupAgent, sa); - if (backupAgent != null) { - String backupAgentName = ParsingUtils.buildClassName(pkgName, backupAgent); - if (backupAgentName == null) { - return input.error("Empty class name in package " + pkgName); - } - - if (DEBUG_BACKUP) { - Slog.v(TAG, "android:backupAgent = " + backupAgentName - + " from " + pkgName + "+" + backupAgent); - } - - pkg.setBackupAgentName(backupAgentName) - .setKillAfterRestoreAllowed(bool(true, - R.styleable.AndroidManifestApplication_killAfterRestore, sa)) - .setRestoreAnyVersion(bool(false, - R.styleable.AndroidManifestApplication_restoreAnyVersion, sa)) - .setFullBackupOnly(bool(false, - R.styleable.AndroidManifestApplication_fullBackupOnly, sa)) - .setBackupInForeground(bool(false, - R.styleable.AndroidManifestApplication_backupInForeground, sa)); - } - - TypedValue v = sa.peekValue( - R.styleable.AndroidManifestApplication_fullBackupContent); - int fullBackupContent = 0; - - if (v != null) { - fullBackupContent = v.resourceId; - - if (v.resourceId == 0) { - if (DEBUG_BACKUP) { - Slog.v(TAG, "fullBackupContent specified as boolean=" + - (v.data == 0 ? "false" : "true")); - } - // "false" => -1, "true" => 0 - fullBackupContent = v.data == 0 ? -1 : 0; - } - - pkg.setFullBackupContentResourceId(fullBackupContent); - } - if (DEBUG_BACKUP) { - Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName); - } - } - - if (sa.getBoolean(R.styleable.AndroidManifestApplication_persistent, false)) { - // Check if persistence is based on a feature being present - final String requiredFeature = sa.getNonResourceString(R.styleable - .AndroidManifestApplication_persistentWhenFeatureAvailable); - pkg.setPersistent(requiredFeature == null || mCallback.hasFeature(requiredFeature)); - } - - if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { - pkg.setResizeableActivity(sa.getBoolean( - R.styleable.AndroidManifestApplication_resizeableActivity, true)); - } else { - pkg.setResizeableActivityViaSdkVersion( - targetSdk >= Build.VERSION_CODES.N); - } - - String taskAffinity; - if (targetSdk >= Build.VERSION_CODES.FROYO) { - taskAffinity = sa.getNonConfigurationString( - R.styleable.AndroidManifestApplication_taskAffinity, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - taskAffinity = sa.getNonResourceString( - R.styleable.AndroidManifestApplication_taskAffinity); - } - - ParseResult taskAffinityResult = ComponentParseUtils.buildTaskAffinityName( - pkgName, pkgName, taskAffinity, input); - if (taskAffinityResult.isError()) { - return input.error(taskAffinityResult); - } - - pkg.setTaskAffinity(taskAffinityResult.getResult()); - String factory = sa.getNonResourceString( - R.styleable.AndroidManifestApplication_appComponentFactory); - if (factory != null) { - String appComponentFactory = ParsingUtils.buildClassName(pkgName, factory); - if (appComponentFactory == null) { - return input.error("Empty class name in package " + pkgName); - } - - pkg.setAppComponentFactory(appComponentFactory); - } - - CharSequence pname; - if (targetSdk >= Build.VERSION_CODES.FROYO) { - pname = sa.getNonConfigurationString( - R.styleable.AndroidManifestApplication_process, - Configuration.NATIVE_CONFIG_VERSION); - } else { - // Some older apps have been seen to use a resource reference - // here that on older builds was ignored (with a warning). We - // need to continue to do this for them so they don't break. - pname = sa.getNonResourceString( - R.styleable.AndroidManifestApplication_process); - } - ParseResult processNameResult = ComponentParseUtils.buildProcessName( - pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input); - if (processNameResult.isError()) { - return input.error(processNameResult); - } - - String processName = processNameResult.getResult(); - pkg.setProcessName(processName); - - if (pkg.isSaveStateDisallowed()) { - // A heavy-weight application can not be in a custom process. - // We can do direct compare because we intern all strings. - if (processName != null && !processName.equals(pkgName)) { - return input.error( - "cantSaveState applications can not use custom processes"); - } - } - - String classLoaderName = pkg.getClassLoaderName(); - if (classLoaderName != null - && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { - return input.error("Invalid class loader name: " + classLoaderName); - } - - pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1)); - pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1)); - if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized)) { - final boolean v = sa.getBoolean( - R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized, false); - pkg.setNativeHeapZeroInitialized( - v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED); - } - if (sa.hasValue( - R.styleable.AndroidManifestApplication_requestRawExternalStorageAccess)) { - pkg.setRequestRawExternalStorageAccess(sa.getBoolean(R.styleable - .AndroidManifestApplication_requestRawExternalStorageAccess, - false)); - } - if (sa.hasValue( - R.styleable.AndroidManifestApplication_requestForegroundServiceExemption)) { - pkg.setRequestForegroundServiceExemption(sa.getBoolean(R.styleable - .AndroidManifestApplication_requestForegroundServiceExemption, - false)); - } - final ParseResult> knownActivityEmbeddingCertsResult = - parseKnownActivityEmbeddingCerts(sa, res, - R.styleable.AndroidManifestApplication_knownActivityEmbeddingCerts, - input); - if (knownActivityEmbeddingCertsResult.isError()) { - return input.error(knownActivityEmbeddingCertsResult); - } else { - final Set knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult - .getResult(); - if (knownActivityEmbeddingCerts != null) { - pkg.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts); - } - } - } finally { - sa.recycle(); - } - - boolean hasActivityOrder = false; - boolean hasReceiverOrder = false; - boolean hasServiceOrder = false; - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - final ParseResult result; - String tagName = parser.getName(); - boolean isActivity = false; - switch (tagName) { - case "activity": - isActivity = true; - // fall-through - case "receiver": - if (shouldSkipComponents) { - continue; - } - ParseResult activityResult = - ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, - res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/, - input); - - if (activityResult.isSuccess()) { - ParsedActivity activity = activityResult.getResult(); - if (isActivity) { - hasActivityOrder |= (activity.getOrder() != 0); - pkg.addActivity(activity); - } else { - hasReceiverOrder |= (activity.getOrder() != 0); - pkg.addReceiver(activity); - } - } - - result = activityResult; - break; - case "service": - if (shouldSkipComponents) { - continue; - } - ParseResult serviceResult = - ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser, - flags, sUseRoundIcon, null /*defaultSplitName*/, - input); - if (serviceResult.isSuccess()) { - ParsedService service = serviceResult.getResult(); - hasServiceOrder |= (service.getOrder() != 0); - pkg.addService(service); - } - - result = serviceResult; - break; - case "provider": - if (shouldSkipComponents) { - continue; - } - ParseResult providerResult = - ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, - flags, sUseRoundIcon, null /*defaultSplitName*/, - input); - if (providerResult.isSuccess()) { - pkg.addProvider(providerResult.getResult()); - } - - result = providerResult; - break; - case "activity-alias": - if (shouldSkipComponents) { - continue; - } - activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, - parser, sUseRoundIcon, null /*defaultSplitName*/, - input); - if (activityResult.isSuccess()) { - ParsedActivity activity = activityResult.getResult(); - hasActivityOrder |= (activity.getOrder() != 0); - pkg.addActivity(activity); - } - - result = activityResult; - break; - case "apex-system-service": - ParseResult systemServiceResult = - ParsedApexSystemServiceUtils.parseApexSystemService(res, - parser, input); - if (systemServiceResult.isSuccess()) { - ParsedApexSystemService systemService = - systemServiceResult.getResult(); - pkg.addApexSystemService(systemService); - } - - result = systemServiceResult; - break; - default: - result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags); - break; - } - - if (result.isError()) { - return input.error(result); - } - if (hasTooManyComponents(pkg)) { - return input.error(MAX_NUM_COMPONENTS_ERR_MSG); - } - } - - if (TextUtils.isEmpty(pkg.getStaticSharedLibraryName()) && TextUtils.isEmpty( - pkg.getSdkLibraryName())) { - // Add a hidden app detail activity to normal apps which forwards user to App Details - // page. - ParseResult a = generateAppDetailsHiddenActivity(input, pkg); - if (a.isError()) { - // Error should be impossible here, as the only failure case as of SDK R is a - // string validation error on a constant ":app_details" string passed in by the - // parsing code itself. For this reason, this is just a hard failure instead of - // deferred. - return input.error(a); - } - - pkg.addActivity(a.getResult()); - } - - if (hasActivityOrder) { - pkg.sortActivities(); - } - if (hasReceiverOrder) { - pkg.sortReceivers(); - } - if (hasServiceOrder) { - pkg.sortServices(); - } - - afterParseBaseApplication(pkg); - - return input.success(pkg); - } - - // Must be run after the entire {@link ApplicationInfo} has been fully processed and after - // every activity info has had a chance to set it from its attributes. - private void afterParseBaseApplication(ParsingPackage pkg) { - setMaxAspectRatio(pkg); - setMinAspectRatio(pkg); - setSupportsSizeChanges(pkg); - - pkg.setHasDomainUrls(hasDomainURLs(pkg)); - } - - /** - * Collection of single-line, no (or little) logic assignments. Separated for readability. - *

- * Flags are separated by type and by default value. They are sorted alphabetically within each - * section. - */ - private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) { - int targetSdk = pkg.getTargetSdkVersion(); - //@formatter:off - // CHECKSTYLE:off - pkg - // Default true - .setBackupAllowed(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa)) - .setClearUserDataAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa)) - .setClearUserDataOnFailedRestoreAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa)) - .setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa)) - .setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa)) - .setExtractNativeLibrariesRequested(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa)) - .setDeclaredHavingCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa)) - // Default false - .setTaskReparentingAllowed(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa)) - .setSaveStateDisallowed(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa)) - .setCrossProfile(bool(false, R.styleable.AndroidManifestApplication_crossProfile, sa)) - .setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa)) - .setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa)) - .setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa)) - .setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa)) - .setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa)) - .setUserDataFragile(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa)) - .setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa)) - .setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa)) - .setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa)) - .setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa)) - .setRtlSupported(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa)) - .setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa)) - .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa)) - .setNonSdkApiRequested(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa)) - .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa)) - .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa)) - .setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa)) - .setResetEnabledSettingsOnAppDataCleared(bool(false, - R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared, - sa)) - .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa)) - // targetSdkVersion gated - .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa)) - .setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa)) - .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa)) - .setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa)) - // Ints Default 0 - .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa)) - // Ints - .setCategory(anInt(ApplicationInfo.CATEGORY_UNDEFINED, R.styleable.AndroidManifestApplication_appCategory, sa)) - // Floats Default 0f - .setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa)) - .setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa)) - // Resource ID - .setBannerResourceId(resId(R.styleable.AndroidManifestApplication_banner, sa)) - .setDescriptionResourceId(resId(R.styleable.AndroidManifestApplication_description, sa)) - .setIconResourceId(resId(R.styleable.AndroidManifestApplication_icon, sa)) - .setLogoResourceId(resId(R.styleable.AndroidManifestApplication_logo, sa)) - .setNetworkSecurityConfigResourceId(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa)) - .setRoundIconResourceId(resId(R.styleable.AndroidManifestApplication_roundIcon, sa)) - .setThemeResourceId(resId(R.styleable.AndroidManifestApplication_theme, sa)) - .setDataExtractionRulesResourceId( - resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa)) - .setLocaleConfigResourceId(resId(R.styleable.AndroidManifestApplication_localeConfig, sa)) - // Strings - .setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa)) - .setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa)) - .setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa)) - .setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa)) - // Non-Config String - .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa)); - // CHECKSTYLE:on - //@formatter:on - } - - /** - * For parsing non-MainComponents. Main ones have an order and some special handling which is - * done directly in {@link #parseBaseApplication(ParseInput, ParsingPackage, Resources, - * XmlResourceParser, int, boolean)}. - */ - private ParseResult parseBaseAppChildTag(ParseInput input, String tag, ParsingPackage pkg, - Resources res, XmlResourceParser parser, int flags) - throws IOException, XmlPullParserException { - switch (tag) { - case "meta-data": - // TODO(b/135203078): I have no idea what this comment means - // note: application meta-data is stored off to the side, so it can - // remain null in the primary copy (we like to avoid extra copies because - // it can be large) - final ParseResult metaDataResult = parseMetaData(pkg, null /*component*/, - res, parser, "", input); - if (metaDataResult.isSuccess() && metaDataResult.getResult() != null) { - pkg.setMetaData(metaDataResult.getResult().toBundle(pkg.getMetaData())); - } - return metaDataResult; - case "property": - final ParseResult propertyResult = parseMetaData(pkg, null /*component*/, - res, parser, "", input); - if (propertyResult.isSuccess()) { - pkg.addProperty(propertyResult.getResult()); - } - return propertyResult; - case "sdk-library": - return parseSdkLibrary(pkg, res, parser, input); - case "static-library": - return parseStaticLibrary(pkg, res, parser, input); - case "library": - return parseLibrary(pkg, res, parser, input); - case "uses-sdk-library": - return parseUsesSdkLibrary(input, pkg, res, parser); - case "uses-static-library": - return parseUsesStaticLibrary(input, pkg, res, parser); - case "uses-library": - return parseUsesLibrary(input, pkg, res, parser); - case "uses-native-library": - return parseUsesNativeLibrary(input, pkg, res, parser); - case "processes": - return parseProcesses(input, pkg, res, parser, mSeparateProcesses, flags); - case "uses-package": - // Dependencies for app installers; we don't currently try to - // enforce this. - return input.success(null); - case "profileable": - return parseProfileable(input, pkg, res, parser); - default: - return ParsingUtils.unknownTag("", pkg, parser, input); - } - } - - @NonNull - private static ParseResult parseSdkLibrary( - ParsingPackage pkg, Resources res, - XmlResourceParser parser, ParseInput input) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSdkLibrary); - try { - // Note: don't allow this value to be a reference to a resource that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestSdkLibrary_name); - final int versionMajor = sa.getInt( - R.styleable.AndroidManifestSdkLibrary_versionMajor, - -1); - - // Fail if malformed. - if (lname == null || versionMajor < 0) { - return input.error("Bad sdk-library declaration name: " + lname - + " version: " + versionMajor); - } else if (pkg.getSharedUserId() != null) { - return input.error( - PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, - "sharedUserId not allowed in SDK library" - ); - } else if (pkg.getSdkLibraryName() != null) { - return input.error("Multiple SDKs for package " - + pkg.getPackageName()); - } - - return input.success(pkg.setSdkLibraryName(lname.intern()) - .setSdkLibVersionMajor(versionMajor) - .setSdkLibrary(true)); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parseStaticLibrary( - ParsingPackage pkg, Resources res, - XmlResourceParser parser, ParseInput input) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestStaticLibrary); - try { - // Note: don't allow this value to be a reference to a resource - // that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestStaticLibrary_name); - final int version = sa.getInt( - R.styleable.AndroidManifestStaticLibrary_version, -1); - final int versionMajor = sa.getInt( - R.styleable.AndroidManifestStaticLibrary_versionMajor, - 0); - - // Since the app canot run without a static lib - fail if malformed - if (lname == null || version < 0) { - return input.error("Bad static-library declaration name: " + lname - + " version: " + version); - } else if (pkg.getSharedUserId() != null) { - return input.error( - PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, - "sharedUserId not allowed in static shared library" - ); - } else if (pkg.getStaticSharedLibraryName() != null) { - return input.error("Multiple static-shared libs for package " - + pkg.getPackageName()); - } - - return input.success(pkg.setStaticSharedLibraryName(lname.intern()) - .setStaticSharedLibraryVersion( - PackageInfo.composeLongVersionCode(versionMajor, version)) - .setStaticSharedLibrary(true)); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parseLibrary( - ParsingPackage pkg, Resources res, - XmlResourceParser parser, ParseInput input) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestLibrary); - try { - // Note: don't allow this value to be a reference to a resource - // that may change. - String lname = sa.getNonResourceString(R.styleable.AndroidManifestLibrary_name); - - if (lname != null) { - lname = lname.intern(); - if (!ArrayUtils.contains(pkg.getLibraryNames(), lname)) { - pkg.addLibraryName(lname); - } - } - return input.success(pkg); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parseUsesSdkLibrary(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdkLibrary); - try { - // Note: don't allow this value to be a reference to a resource that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestUsesSdkLibrary_name); - final int versionMajor = sa.getInt( - R.styleable.AndroidManifestUsesSdkLibrary_versionMajor, -1); - String certSha256Digest = sa.getNonResourceString(R.styleable - .AndroidManifestUsesSdkLibrary_certDigest); - boolean optional = - sa.getBoolean(R.styleable.AndroidManifestUsesSdkLibrary_optional, false); - - // Since an APK providing a static shared lib can only provide the lib - fail if - // malformed - if (lname == null || versionMajor < 0 || certSha256Digest == null) { - return input.error("Bad uses-sdk-library declaration name: " + lname - + " version: " + versionMajor + " certDigest" + certSha256Digest); - } - - // Can depend only on one version of the same library - List usesSdkLibraries = pkg.getUsesSdkLibraries(); - if (usesSdkLibraries.contains(lname)) { - return input.error( - "Depending on multiple versions of SDK library " + lname); - } - - lname = lname.intern(); - // We allow ":" delimiters in the SHA declaration as this is the format - // emitted by the certtool making it easy for developers to copy/paste. - certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); - - if ("".equals(certSha256Digest)) { - // Test-only uses-sdk-library empty certificate digest override. - certSha256Digest = SystemProperties.get( - "debug.pm.uses_sdk_library_default_cert_digest", ""); - // Validate the overridden digest. - try { - HexEncoding.decode(certSha256Digest, false); - } catch (IllegalArgumentException e) { - certSha256Digest = ""; - } - } - - ParseResult certResult = parseAdditionalCertificates(input, res, parser); - if (certResult.isError()) { - return input.error(certResult); - } - String[] additionalCertSha256Digests = certResult.getResult(); - - final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; - certSha256Digests[0] = certSha256Digest; - System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, - 1, additionalCertSha256Digests.length); - - return input.success( - pkg.addUsesSdkLibrary(lname, versionMajor, certSha256Digests, optional)); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parseUsesStaticLibrary(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesStaticLibrary); - try { - // Note: don't allow this value to be a reference to a resource that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestUsesLibrary_name); - final int version = sa.getInt( - R.styleable.AndroidManifestUsesStaticLibrary_version, -1); - String certSha256Digest = sa.getNonResourceString(R.styleable - .AndroidManifestUsesStaticLibrary_certDigest); - - // Since an APK providing a static shared lib can only provide the lib - fail if - // malformed - if (lname == null || version < 0 || certSha256Digest == null) { - return input.error("Bad uses-static-library declaration name: " + lname - + " version: " + version + " certDigest" + certSha256Digest); - } - - // Can depend only on one version of the same library - List usesStaticLibraries = pkg.getUsesStaticLibraries(); - if (usesStaticLibraries.contains(lname)) { - return input.error( - "Depending on multiple versions of static library " + lname); - } - - lname = lname.intern(); - // We allow ":" delimiters in the SHA declaration as this is the format - // emitted by the certtool making it easy for developers to copy/paste. - certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); - - // Fot apps targeting O-MR1 we require explicit enumeration of all certs. - String[] additionalCertSha256Digests = EmptyArray.STRING; - if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) { - ParseResult certResult = parseAdditionalCertificates(input, res, parser); - if (certResult.isError()) { - return input.error(certResult); - } - additionalCertSha256Digests = certResult.getResult(); - } - - final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; - certSha256Digests[0] = certSha256Digest; - System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, - 1, additionalCertSha256Digests.length); - - return input.success(pkg.addUsesStaticLibrary(lname, version, certSha256Digests)); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parseUsesLibrary(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary); - try { - // Note: don't allow this value to be a reference to a resource - // that may change. - String lname = sa.getNonResourceString(R.styleable.AndroidManifestUsesLibrary_name); - boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesLibrary_required, true); - - if (lname != null) { - lname = lname.intern(); - if (req) { - // Upgrade to treat as stronger constraint - pkg.addUsesLibrary(lname) - .removeUsesOptionalLibrary(lname); - } else { - // Ignore if someone already defined as required - if (!ArrayUtils.contains(pkg.getUsesLibraries(), lname)) { - pkg.addUsesOptionalLibrary(lname); - } - } - } - - return input.success(pkg); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parseUsesNativeLibrary(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesNativeLibrary); - try { - // Note: don't allow this value to be a reference to a resource - // that may change. - String lname = sa.getNonResourceString( - R.styleable.AndroidManifestUsesNativeLibrary_name); - boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesNativeLibrary_required, - true); - - if (lname != null) { - if (req) { - // Upgrade to treat as stronger constraint - pkg.addUsesNativeLibrary(lname) - .removeUsesOptionalNativeLibrary(lname); - } else { - // Ignore if someone already defined as required - if (!ArrayUtils.contains(pkg.getUsesNativeLibraries(), lname)) { - pkg.addUsesOptionalNativeLibrary(lname); - } - } - } - - return input.success(pkg); - } finally { - sa.recycle(); - } - } - - @NonNull - private static ParseResult parseProcesses(ParseInput input, ParsingPackage pkg, - Resources res, XmlResourceParser parser, String[] separateProcesses, int flags) - throws IOException, XmlPullParserException { - ParseResult> result = - ParsedProcessUtils.parseProcesses(separateProcesses, pkg, res, parser, flags, - input); - if (result.isError()) { - return input.error(result); - } - - return input.success(pkg.setProcesses(result.getResult())); - } - - @NonNull - private static ParseResult parseProfileable(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProfileable); - try { - ParsingPackage newPkg = pkg.setProfileableByShell(pkg.isProfileableByShell() - || bool(false, R.styleable.AndroidManifestProfileable_shell, sa)); - return input.success(newPkg.setProfileable(newPkg.isProfileable() - && bool(true, R.styleable.AndroidManifestProfileable_enabled, sa))); - } finally { - sa.recycle(); - } - } - - private static ParseResult parseAdditionalCertificates(ParseInput input, - Resources resources, XmlResourceParser parser) - throws XmlPullParserException, IOException { - String[] certSha256Digests = EmptyArray.STRING; - final int depth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > depth)) { - if (type != XmlPullParser.START_TAG) { - continue; - } - - final String nodeName = parser.getName(); - if (nodeName.equals("additional-certificate")) { - TypedArray sa = resources.obtainAttributes(parser, - R.styleable.AndroidManifestAdditionalCertificate); - try { - String certSha256Digest = sa.getNonResourceString( - R.styleable.AndroidManifestAdditionalCertificate_certDigest); - - if (TextUtils.isEmpty(certSha256Digest)) { - return input.error("Bad additional-certificate declaration with empty" - + " certDigest:" + certSha256Digest); - } - - - // We allow ":" delimiters in the SHA declaration as this is the format - // emitted by the certtool making it easy for developers to copy/paste. - certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); - certSha256Digests = ArrayUtils.appendElement(String.class, - certSha256Digests, certSha256Digest); - } finally { - sa.recycle(); - } - } - } - - return input.success(certSha256Digests); - } - - /** - * Generate activity object that forwards user to App Details page automatically. - * This activity should be invisible to user and user should not know or see it. - */ - @NonNull - private static ParseResult generateAppDetailsHiddenActivity(ParseInput input, - ParsingPackage pkg) { - String packageName = pkg.getPackageName(); - ParseResult result = ComponentParseUtils.buildTaskAffinityName( - packageName, packageName, ":app_details", input); - if (result.isError()) { - return input.error(result); - } - - String taskAffinity = result.getResult(); - - // Build custom App Details activity info instead of parsing it from xml - return input.success(ParsedActivityImpl.makeAppDetailsActivity(packageName, - pkg.getProcessName(), pkg.getUiOptions(), taskAffinity, - pkg.isHardwareAccelerated())); - } - - /** - * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI - * - * This is distinct from any of the functionality of app links domain verification, and cannot - * be converted to remain backwards compatible. It's possible the presence of this flag does - * not indicate a valid package for domain verification. - */ - private static boolean hasDomainURLs(ParsingPackage pkg) { - final List activities = pkg.getActivities(); - final int activitiesSize = activities.size(); - for (int index = 0; index < activitiesSize; index++) { - ParsedActivity activity = activities.get(index); - List filters = activity.getIntents(); - final int filtersSize = filters.size(); - for (int filtersIndex = 0; filtersIndex < filtersSize; filtersIndex++) { - IntentFilter aii = filters.get(filtersIndex).getIntentFilter(); - if (!aii.hasAction(Intent.ACTION_VIEW)) continue; - if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; - if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || - aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { - return true; - } - } - } - return false; - } - - /** - * Sets the max aspect ratio of every child activity that doesn't already have an aspect - * ratio set. - */ - private static void setMaxAspectRatio(ParsingPackage pkg) { - // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. - // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. - float maxAspectRatio = pkg.getTargetSdkVersion() < O ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; - - float packageMaxAspectRatio = pkg.getMaxAspectRatio(); - if (packageMaxAspectRatio != 0) { - // Use the application max aspect ration as default if set. - maxAspectRatio = packageMaxAspectRatio; - } else { - Bundle appMetaData = pkg.getMetaData(); - if (appMetaData != null && appMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) { - maxAspectRatio = appMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio); - } - } - - List activities = pkg.getActivities(); - int activitiesSize = activities.size(); - for (int index = 0; index < activitiesSize; index++) { - ParsedActivity activity = activities.get(index); - // If the max aspect ratio for the activity has already been set, skip. - if (activity.getMaxAspectRatio() != ASPECT_RATIO_NOT_SET) { - continue; - } - - // By default we prefer to use a values defined on the activity directly than values - // defined on the application. We do not check the styled attributes on the activity - // as it would have already been set when we processed the activity. We wait to - // process the meta data here since this method is called at the end of processing - // the application and all meta data is guaranteed. - final float activityAspectRatio = activity.getMetaData() - .getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio); - - ComponentMutateUtils.setMaxAspectRatio(activity, activity.getResizeMode(), - activityAspectRatio); - } - } - - /** - * Sets the min aspect ratio of every child activity that doesn't already have an aspect - * ratio set. - */ - private void setMinAspectRatio(ParsingPackage pkg) { - // Use the application max aspect ration as default if set. - final float minAspectRatio = pkg.getMinAspectRatio(); - - List activities = pkg.getActivities(); - int activitiesSize = activities.size(); - for (int index = 0; index < activitiesSize; index++) { - ParsedActivity activity = activities.get(index); - if (activity.getMinAspectRatio() == ASPECT_RATIO_NOT_SET) { - ComponentMutateUtils.setMinAspectRatio(activity, activity.getResizeMode(), - minAspectRatio); - } - } - } - - private void setSupportsSizeChanges(ParsingPackage pkg) { - final Bundle appMetaData = pkg.getMetaData(); - final boolean supportsSizeChanges = appMetaData != null - && appMetaData.getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false); - - List activities = pkg.getActivities(); - int activitiesSize = activities.size(); - for (int index = 0; index < activitiesSize; index++) { - ParsedActivity activity = activities.get(index); - if (supportsSizeChanges || activity.getMetaData() - .getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false)) { - ComponentMutateUtils.setSupportsSizeChanges(activity, true); - } - } - } - - private static ParseResult parseOverlay(ParseInput input, ParsingPackage pkg, - Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay); - try { - String target = sa.getString(R.styleable.AndroidManifestResourceOverlay_targetPackage); - int priority = anInt(0, R.styleable.AndroidManifestResourceOverlay_priority, sa); - - if (target == null) { - return input.error(" does not specify a target package"); - } else if (priority < 0 || priority > 9999) { - return input.error(" priority must be between 0 and 9999"); - } - - // check to see if overlay should be excluded based on system property condition - String propName = sa.getString( - R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName); - String propValue = sa.getString( - R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue); - if (!FrameworkParsingPackageUtils.checkRequiredSystemProperties(propName, propValue)) { - String message = "Skipping target and overlay pair " + target + " and " - + pkg.getBaseApkPath() - + ": overlay ignored due to required system property: " - + propName + " with value: " + propValue; - Slog.i(TAG, message); - return input.skip(message); - } - - return input.success(pkg.setResourceOverlay(true) - .setOverlayTarget(target) - .setOverlayPriority(priority) - .setOverlayTargetOverlayableName( - sa.getString(R.styleable.AndroidManifestResourceOverlay_targetName)) - .setOverlayCategory( - sa.getString(R.styleable.AndroidManifestResourceOverlay_category)) - .setOverlayIsStatic( - bool(false, R.styleable.AndroidManifestResourceOverlay_isStatic, sa))); - } finally { - sa.recycle(); - } - } - - private static ParseResult parseProtectedBroadcast(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProtectedBroadcast); - try { - // Note: don't allow this value to be a reference to a resource - // that may change. - String name = nonResString(R.styleable.AndroidManifestProtectedBroadcast_name, sa); - if (name != null) { - pkg.addProtectedBroadcast(name); - } - return input.success(pkg); - } finally { - sa.recycle(); - } - } - - private static ParseResult parseSupportScreens(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSupportsScreens); - try { - int requiresSmallestWidthDp = anInt(0, - R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, sa); - int compatibleWidthLimitDp = anInt(0, - R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, sa); - int largestWidthLimitDp = anInt(0, - R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, sa); - - // This is a trick to get a boolean and still able to detect - // if a value was actually set. - return input.success(pkg - .setSmallScreensSupported( - anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa)) - .setNormalScreensSupported( - anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa)) - .setLargeScreensSupported( - anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa)) - .setExtraLargeScreensSupported( - anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa)) - .setResizeable( - anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa)) - .setAnyDensity( - anInt(1, R.styleable.AndroidManifestSupportsScreens_anyDensity, sa)) - .setRequiresSmallestWidthDp(requiresSmallestWidthDp) - .setCompatibleWidthLimitDp(compatibleWidthLimitDp) - .setLargestWidthLimitDp(largestWidthLimitDp)); - } finally { - sa.recycle(); - } - } - - private static ParseResult parseInstrumentation(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { - ParseResult result = ParsedInstrumentationUtils.parseInstrumentation( - pkg, res, parser, sUseRoundIcon, input); - if (result.isError()) { - return input.error(result); - } - return input.success(pkg.addInstrumentation(result.getResult())); - } - - private static ParseResult parseOriginalPackage(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage); - try { - String orig = sa.getNonConfigurationString( - R.styleable.AndroidManifestOriginalPackage_name, - 0); - if (!pkg.getPackageName().equals(orig)) { - pkg.addOriginalPackage(orig); - } - return input.success(pkg); - } finally { - sa.recycle(); - } - } - - private static ParseResult parseAdoptPermissions(ParseInput input, - ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage); - try { - String name = nonConfigString(0, R.styleable.AndroidManifestOriginalPackage_name, sa); - if (name != null) { - pkg.addAdoptPermission(name); - } - return input.success(pkg); - } finally { - sa.recycle(); - } - } - - private static void convertCompatPermissions(ParsingPackage pkg) { - for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) { - final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i]; - if (pkg.getTargetSdkVersion() >= info.getSdkVersion()) { - break; - } - if (!pkg.getRequestedPermissions().contains(info.getName())) { - pkg.addImplicitPermission(info.getName()); - } - } - } - - private void convertSplitPermissions(ParsingPackage pkg) { - final int listSize = mSplitPermissionInfos.size(); - for (int is = 0; is < listSize; is++) { - final PermissionManager.SplitPermissionInfo spi = mSplitPermissionInfos.get(is); - Set requestedPermissions = pkg.getRequestedPermissions(); - if (pkg.getTargetSdkVersion() >= spi.getTargetSdk() - || !requestedPermissions.contains(spi.getSplitPermission())) { - continue; - } - final List newPerms = spi.getNewPermissions(); - for (int in = 0; in < newPerms.size(); in++) { - final String perm = newPerms.get(in); - if (!requestedPermissions.contains(perm)) { - pkg.addImplicitPermission(perm); - } - } - } - } - - /** - * This is a pre-density application which will get scaled - instead of being pixel perfect. - * This type of application is not resizable. - * - * @param pkg The package which needs to be marked as unresizable. - */ - private static void adjustPackageToBeUnresizeableAndUnpipable(ParsingPackage pkg) { - List activities = pkg.getActivities(); - int activitiesSize = activities.size(); - for (int index = 0; index < activitiesSize; index++) { - ParsedActivity activity = activities.get(index); - ComponentMutateUtils.setResizeMode(activity, RESIZE_MODE_UNRESIZEABLE); - ComponentMutateUtils.setExactFlags(activity, - activity.getFlags() & ~FLAG_SUPPORTS_PICTURE_IN_PICTURE); - } - } - - /** - * Parse a meta data defined on the enclosing tag. - *

Meta data can be defined by either <meta-data> or <property> elements. - */ - public static ParseResult parseMetaData(ParsingPackage pkg, ParsedComponent component, - Resources res, XmlResourceParser parser, String tagName, ParseInput input) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestMetaData); - try { - final Property property; - final String name = TextUtils.safeIntern( - nonConfigString(0, R.styleable.AndroidManifestMetaData_name, sa)); - if (name == null) { - return input.error(tagName + " requires an android:name attribute"); - } - - final String packageName = pkg.getPackageName(); - final String className = component != null ? component.getName() : null; - TypedValue v = sa.peekValue(R.styleable.AndroidManifestMetaData_resource); - if (v != null && v.resourceId != 0) { - property = new Property(name, v.resourceId, true, packageName, className); - } else { - v = sa.peekValue(R.styleable.AndroidManifestMetaData_value); - if (v != null) { - if (v.type == TypedValue.TYPE_STRING) { - final CharSequence cs = v.coerceToString(); - final String stringValue = cs != null ? cs.toString() : null; - property = new Property(name, stringValue, packageName, className); - } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { - property = new Property(name, v.data != 0, packageName, className); - } else if (v.type >= TypedValue.TYPE_FIRST_INT - && v.type <= TypedValue.TYPE_LAST_INT) { - property = new Property(name, v.data, false, packageName, className); - } else if (v.type == TypedValue.TYPE_FLOAT) { - property = new Property(name, v.getFloat(), packageName, className); - } else { - if (!RIGID_PARSER) { - Slog.w(TAG, - tagName + " only supports string, integer, float, color, " - + "boolean, and resource reference types: " - + parser.getName() + " at " - + pkg.getBaseApkPath() + " " - + parser.getPositionDescription()); - property = null; - } else { - return input.error(tagName + " only supports string, integer, float, " - + "color, boolean, and resource reference types"); - } - } - } else { - return input.error(tagName + " requires an android:value " - + "or android:resource attribute"); - } - } - return input.success(property); - } finally { - sa.recycle(); - } - } - - /** - * Collect certificates from all the APKs described in the given package. Also asserts that - * all APK contents are signed correctly and consistently. - * - * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse - * call if requested. Leaving this as an optional method for the caller means we have to - * construct a placeholder ParseInput. - */ - @CheckResult - public static ParseResult getSigningDetails(ParseInput input, - ParsedPackage pkg, boolean skipVerify) { - return getSigningDetails(input, pkg.getBaseApkPath(), pkg.isStaticSharedLibrary(), - pkg.getTargetSdkVersion(), pkg.getSplitCodePaths(), skipVerify); - } - - @CheckResult - private static ParseResult getSigningDetails(ParseInput input, - ParsingPackage pkg, boolean skipVerify) { - return getSigningDetails(input, pkg.getBaseApkPath(), pkg.isStaticSharedLibrary(), - pkg.getTargetSdkVersion(), pkg.getSplitCodePaths(), skipVerify); - } - - /** - * Collect certificates from all the APKs described in the given package. Also asserts that - * all APK contents are signed correctly and consistently. - * - * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse - * call if requested. Leaving this as an optional method for the caller means we have to - * construct a dummy ParseInput. - */ - @CheckResult - public static ParseResult getSigningDetails(ParseInput input, - String baseApkPath, boolean isStaticSharedLibrary, int targetSdkVersion, - String[] splitCodePaths, boolean skipVerify) { - SigningDetails signingDetails = SigningDetails.UNKNOWN; - - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); - try { - ParseResult result = getSigningDetails( - input, - baseApkPath, - skipVerify, - isStaticSharedLibrary, - signingDetails, - targetSdkVersion - ); - if (result.isError()) { - return input.error(result); - } - - signingDetails = result.getResult(); - final File frameworkRes = new File(Environment.getRootDirectory(), - "framework/framework-res.apk"); - boolean isFrameworkResSplit = frameworkRes.getAbsolutePath() - .equals(baseApkPath); - if (!ArrayUtils.isEmpty(splitCodePaths) && !isFrameworkResSplit) { - for (int i = 0; i < splitCodePaths.length; i++) { - result = getSigningDetails( - input, - splitCodePaths[i], - skipVerify, - isStaticSharedLibrary, - signingDetails, - targetSdkVersion - ); - if (result.isError()) { - return input.error(result); - } - } - } - return result; - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - @CheckResult - public static ParseResult getSigningDetails(ParseInput input, - String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary, - @NonNull SigningDetails existingSigningDetails, int targetSdk) { - int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( - targetSdk); - if (isStaticSharedLibrary) { - // must use v2 signing scheme - minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; - } - final ParseResult verified; - if (skipVerify) { - // systemDir APKs are already trusted, save time by not verifying - verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(input, baseCodePath, - minSignatureScheme); - } else { - verified = ApkSignatureVerifier.verify(input, baseCodePath, minSignatureScheme); - } - - if (verified.isError()) { - return input.error(verified); - } - - // Verify that entries are signed consistently with the first pkg - // we encountered. Note that for splits, certificates may have - // already been populated during an earlier parse of a base APK. - if (existingSigningDetails == SigningDetails.UNKNOWN) { - return verified; - } else { - if (!Signature.areExactMatch(existingSigningDetails, verified.getResult())) { - return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, - baseCodePath + " has mismatched certificates"); - } - - return input.success(existingSigningDetails); - } - } - - /** - * @hide - */ - public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { - sCompatibilityModeEnabled = compatibilityModeEnabled; - } - - /** - * @hide - */ - public static void readConfigUseRoundIcon(Resources r) { - if (r != null) { - sUseRoundIcon = r.getBoolean(com.android.internal.R.bool.config_useRoundIcon); - return; - } - - final ApplicationInfo androidAppInfo; - try { - androidAppInfo = ActivityThread.getPackageManager().getApplicationInfo( - "android", 0 /* flags */, - UserHandle.myUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - final Resources systemResources = Resources.getSystem(); - - // Create in-flight as this overlayable resource is only used when config changes - final Resources overlayableRes = ResourcesManager.getInstance().getResources( - null /* activityToken */, - null /* resDir */, - null /* splitResDirs */, - androidAppInfo.resourceDirs, - androidAppInfo.overlayPaths, - androidAppInfo.sharedLibraryFiles, - null /* overrideDisplayId */, - null /* overrideConfig */, - systemResources.getCompatibilityInfo(), - systemResources.getClassLoader(), - null /* loaders */); - - sUseRoundIcon = overlayableRes.getBoolean(com.android.internal.R.bool.config_useRoundIcon); - } - - /* - The following set of methods makes code easier to read by re-ordering the TypedArray methods. - - The first parameter is the default, which is the most important to understand for someone - reading through the parsing code. - - That's followed by the attribute name, which is usually irrelevant during reading because - it'll look like setSomeValue(true, R.styleable.ReallyLongParentName_SomeValueAttr... and - the "setSomeValue" part is enough to communicate what the line does. - - Last comes the TypedArray, which is by far the least important since each try-with-resources - should only have 1. - */ - - // Note there is no variant of bool without a defaultValue parameter, since explicit true/false - // is important to specify when adding an attribute. - private static boolean bool(boolean defaultValue, @StyleableRes int attribute, TypedArray sa) { - return sa.getBoolean(attribute, defaultValue); - } - - private static float aFloat(float defaultValue, @StyleableRes int attribute, TypedArray sa) { - return sa.getFloat(attribute, defaultValue); - } - - private static float aFloat(@StyleableRes int attribute, TypedArray sa) { - return sa.getFloat(attribute, 0f); - } - - private static int anInt(int defaultValue, @StyleableRes int attribute, TypedArray sa) { - return sa.getInt(attribute, defaultValue); - } - - private static int anInteger(int defaultValue, @StyleableRes int attribute, TypedArray sa) { - return sa.getInteger(attribute, defaultValue); - } - - private static int anInt(@StyleableRes int attribute, TypedArray sa) { - return sa.getInt(attribute, 0); - } - - @AnyRes - private static int resId(@StyleableRes int attribute, TypedArray sa) { - return sa.getResourceId(attribute, 0); - } - - private static String string(@StyleableRes int attribute, TypedArray sa) { - return sa.getString(attribute); - } - - private static String nonConfigString(int allowedChangingConfigs, @StyleableRes int attribute, - TypedArray sa) { - return sa.getNonConfigurationString(attribute, allowedChangingConfigs); - } - - private static String nonResString(@StyleableRes int index, TypedArray sa) { - return sa.getNonResourceString(index); - } - - /** - * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. - */ - public static void writeKeySetMapping(@NonNull Parcel dest, - @NonNull Map> keySetMapping) { - if (keySetMapping == null) { - dest.writeInt(-1); - return; - } - - final int N = keySetMapping.size(); - dest.writeInt(N); - - for (String key : keySetMapping.keySet()) { - dest.writeString(key); - ArraySet keys = keySetMapping.get(key); - if (keys == null) { - dest.writeInt(-1); - continue; - } - - final int M = keys.size(); - dest.writeInt(M); - for (int j = 0; j < M; j++) { - dest.writeSerializable(keys.valueAt(j)); - } - } - } - - /** - * Reads a keyset mapping from the given parcel at the given data position. May return - * {@code null} if the serialized mapping was {@code null}. - */ - @NonNull - public static ArrayMap> readKeySetMapping(@NonNull Parcel in) { - final int N = in.readInt(); - if (N == -1) { - return null; - } - - ArrayMap> keySetMapping = new ArrayMap<>(); - for (int i = 0; i < N; ++i) { - String key = in.readString(); - final int M = in.readInt(); - if (M == -1) { - keySetMapping.put(key, null); - continue; - } - - ArraySet keys = new ArraySet<>(M); - for (int j = 0; j < M; ++j) { - PublicKey pk = (PublicKey) in.readSerializable(java.security.PublicKey.class.getClassLoader(), java.security.PublicKey.class); - keys.add(pk); - } - - keySetMapping.put(key, keys); - } - - return keySetMapping; - } - - /** - * Callback interface for retrieving information that may be needed while parsing - * a package. - */ - public interface Callback { - boolean hasFeature(String feature); - - ParsingPackage startParsingPackage(@NonNull String packageName, - @NonNull String baseApkPath, @NonNull String path, - @NonNull TypedArray manifestArray, boolean isCoreApp); - } -} diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java deleted file mode 100644 index 1d159554e8a7..000000000000 --- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.pkg.parsing; - -import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.pm.parsing.result.ParseInput; -import android.content.pm.parsing.result.ParseResult; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Pair; -import android.util.Slog; - -import com.android.internal.pm.pkg.component.ParsedIntentInfo; -import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.internal.util.Parcelling; -import com.android.internal.util.XmlUtils; -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** @hide **/ -public class ParsingUtils { - - public static final String TAG = "PackageParsing"; - - public static final String ANDROID_RES_NAMESPACE = "http://schemas.android.com/apk/res/android"; - - public static final int DEFAULT_MIN_SDK_VERSION = 1; - public static final int DEFAULT_MAX_SDK_VERSION = Integer.MAX_VALUE; - public static final int DEFAULT_TARGET_SDK_VERSION = 0; - - public static final int NOT_SET = -1; - - @Nullable - public static String buildClassName(String pkg, CharSequence clsSeq) { - if (clsSeq == null || clsSeq.length() <= 0) { - return null; - } - String cls = clsSeq.toString(); - char c = cls.charAt(0); - if (c == '.') { - return pkg + cls; - } - if (cls.indexOf('.') < 0) { - StringBuilder b = new StringBuilder(pkg); - b.append('.'); - b.append(cls); - return b.toString(); - } - return cls; - } - - @NonNull - public static ParseResult unknownTag(String parentTag, ParsingPackage pkg, - XmlResourceParser parser, ParseInput input) throws IOException, XmlPullParserException { - if (RIGID_PARSER) { - return input.error("Bad element under " + parentTag + ": " + parser.getName()); - } - Slog.w(TAG, "Unknown element under " + parentTag + ": " - + parser.getName() + " at " + pkg.getBaseApkPath() + " " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - return input.success(null); // Type doesn't matter - } - - /** - * Use with {@link Parcel#writeTypedList(List)} or - * {@link #writeInterfaceAsImplList(Parcel, List)} - * - * @see Parcel#createTypedArrayList(Parcelable.Creator) - */ - @NonNull - public static List createTypedInterfaceList( - @NonNull Parcel parcel, @NonNull Parcelable.Creator creator) { - int size = parcel.readInt(); - if (size < 0) { - return new ArrayList<>(); - } - ArrayList list = new ArrayList(size); - while (size > 0) { - list.add(parcel.readTypedObject(creator)); - size--; - } - return list; - } - - /** - * Use with {@link #createTypedInterfaceList(Parcel, Parcelable.Creator)}. - * - * Writes a list that can be cast as Parcelable types at runtime. - * TODO: Remove with ImmutableList multi-casting support - * - * @see Parcel#writeTypedList(List) - */ - @NonNull - public static void writeParcelableList(@NonNull Parcel parcel, List list) { - if (list == null) { - parcel.writeInt(-1); - return; - } - int size = list.size(); - int index = 0; - parcel.writeInt(size); - while (index < size) { - parcel.writeTypedObject((Parcelable) list.get(index), 0); - index++; - } - } - - public static class StringPairListParceler implements - Parcelling>> { - - @Override - public void parcel(List> item, Parcel dest, - int parcelFlags) { - if (item == null) { - dest.writeInt(-1); - return; - } - - final int size = item.size(); - dest.writeInt(size); - - for (int index = 0; index < size; index++) { - Pair pair = item.get(index); - dest.writeString(pair.first); - dest.writeParcelable((Parcelable) pair.second, parcelFlags); - } - } - - @Override - public List> unparcel(Parcel source) { - int size = source.readInt(); - if (size == -1) { - return null; - } - - if (size == 0) { - return new ArrayList<>(0); - } - - final List> list = new ArrayList<>(size); - for (int i = 0; i < size; ++i) { - list.add(Pair.create(source.readString(), source.readParcelable( - ParsedIntentInfoImpl.class.getClassLoader(), ParsedIntentInfo.class))); - } - - return list; - } - } - - /** - * Parse the {@link android.R.attr#knownActivityEmbeddingCerts} attribute, if available. - */ - @NonNull - public static ParseResult> parseKnownActivityEmbeddingCerts(@NonNull TypedArray sa, - @NonNull Resources res, int resourceId, @NonNull ParseInput input) { - if (!sa.hasValue(resourceId)) { - return input.success(null); - } - - final int knownActivityEmbeddingCertsResource = sa.getResourceId(resourceId, 0); - if (knownActivityEmbeddingCertsResource != 0) { - // The knownCerts attribute supports both a string array resource as well as a - // string resource for the case where the permission should only be granted to a - // single known signer. - Set knownEmbeddingCertificates = null; - final String resourceType = res.getResourceTypeName( - knownActivityEmbeddingCertsResource); - if (resourceType.equals("array")) { - final String[] knownCerts = res.getStringArray(knownActivityEmbeddingCertsResource); - if (knownCerts != null) { - knownEmbeddingCertificates = Set.of(knownCerts); - } - } else { - final String knownCert = res.getString(knownActivityEmbeddingCertsResource); - if (knownCert != null) { - knownEmbeddingCertificates = Set.of(knownCert); - } - } - if (knownEmbeddingCertificates == null || knownEmbeddingCertificates.isEmpty()) { - return input.error("Defined a knownActivityEmbeddingCerts attribute but the " - + "provided resource is null"); - } - return input.success(knownEmbeddingCertificates); - } - - // If the knownCerts resource ID is null - the app specified a string value for the - // attribute representing a single trusted signer. - final String knownCert = sa.getString(resourceId); - if (knownCert == null || knownCert.isEmpty()) { - return input.error("Defined a knownActivityEmbeddingCerts attribute but the provided " - + "string is empty"); - } - return input.success(Set.of(knownCert)); - } -} diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java index 532a7f8f893f..c9da99da7902 100644 --- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java @@ -45,11 +45,13 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.pm.pkg.component.ComponentMutateUtils; import com.android.internal.pm.pkg.component.ParsedActivity; import com.android.internal.pm.pkg.component.ParsedComponent; import com.android.internal.pm.pkg.component.ParsedIntentInfo; import com.android.internal.pm.pkg.component.ParsedMainComponent; import com.android.internal.pm.pkg.component.ParsedProvider; +import com.android.internal.pm.pkg.component.ParsedProviderImpl; import com.android.internal.pm.pkg.component.ParsedService; import com.android.internal.util.ArrayUtils; import com.android.server.IntentResolver; @@ -62,8 +64,6 @@ import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageStateUtils; import com.android.server.pm.pkg.PackageUserStateInternal; -import com.android.server.pm.pkg.component.ComponentMutateUtils; -import com.android.server.pm.pkg.component.ParsedProviderImpl; import com.android.server.pm.snapshot.PackageDataSnapshot; import com.android.server.utils.Snappable; import com.android.server.utils.SnapshotCache; diff --git a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java b/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java deleted file mode 100644 index 0bb969f488fe..000000000000 --- a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.split; - -import android.content.pm.parsing.ApkLiteParseUtils; -import android.content.pm.parsing.PackageLite; -import android.content.res.ApkAssets; -import android.content.res.AssetManager; -import android.os.Build; - -import com.android.internal.util.ArrayUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags; - -import libcore.io.IoUtils; - -import java.io.IOException; - -/** - * Loads the base and split APKs into a single AssetManager. - * @hide - */ -public class DefaultSplitAssetLoader implements SplitAssetLoader { - private final String mBaseApkPath; - private final String[] mSplitApkPaths; - private final @ParseFlags int mFlags; - private AssetManager mCachedAssetManager; - - private ApkAssets mBaseApkAssets; - - public DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags) { - mBaseApkPath = pkg.getBaseApkPath(); - mSplitApkPaths = pkg.getSplitApkPaths(); - mFlags = flags; - } - - private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) - throws IllegalArgumentException { - if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0 - && !ApkLiteParseUtils.isApkPath(path)) { - throw new IllegalArgumentException("Invalid package file: " + path); - } - - try { - return ApkAssets.loadFromPath(path); - } catch (IOException e) { - throw new IllegalArgumentException("Failed to load APK at path " + path, e); - } - } - - @Override - public AssetManager getBaseAssetManager() throws IllegalArgumentException { - if (mCachedAssetManager != null) { - return mCachedAssetManager; - } - - ApkAssets[] apkAssets = new ApkAssets[(mSplitApkPaths != null - ? mSplitApkPaths.length : 0) + 1]; - - // Load the base. - int splitIdx = 0; - apkAssets[splitIdx++] = mBaseApkAssets = loadApkAssets(mBaseApkPath, mFlags); - - // Load any splits. - if (!ArrayUtils.isEmpty(mSplitApkPaths)) { - for (String apkPath : mSplitApkPaths) { - apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags); - } - } - - AssetManager assets = new AssetManager(); - assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, Build.VERSION.RESOURCES_SDK_INT); - assets.setApkAssets(apkAssets, false /*invalidateCaches*/); - - mCachedAssetManager = assets; - return mCachedAssetManager; - } - - @Override - public AssetManager getSplitAssetManager(int splitIdx) throws IllegalArgumentException { - return getBaseAssetManager(); - } - - @Override - public ApkAssets getBaseApkAssets() { - return mBaseApkAssets; - } - - @Override - public void close() throws Exception { - IoUtils.closeQuietly(mCachedAssetManager); - } -} diff --git a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java b/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java deleted file mode 100644 index 56d92fbc95a2..000000000000 --- a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.split; - -import android.annotation.NonNull; -import android.content.pm.parsing.ApkLiteParseUtils; -import android.content.pm.parsing.PackageLite; -import android.content.pm.split.SplitDependencyLoader; -import android.content.res.ApkAssets; -import android.content.res.AssetManager; -import android.os.Build; -import android.util.SparseArray; - -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags; - -import libcore.io.IoUtils; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; - -/** - * Loads AssetManagers for splits and their dependencies. This SplitAssetLoader implementation - * is to be used when an application opts-in to isolated split loading. - * @hide - */ -public class SplitAssetDependencyLoader extends SplitDependencyLoader - implements SplitAssetLoader { - private final String[] mSplitPaths; - private final @ParseFlags int mFlags; - private final ApkAssets[][] mCachedSplitApks; - private final AssetManager[] mCachedAssetManagers; - - public SplitAssetDependencyLoader(PackageLite pkg, - SparseArray dependencies, @ParseFlags int flags) { - super(dependencies); - - // The base is inserted into index 0, so we need to shift all the splits by 1. - mSplitPaths = new String[pkg.getSplitApkPaths().length + 1]; - mSplitPaths[0] = pkg.getBaseApkPath(); - System.arraycopy(pkg.getSplitApkPaths(), 0, mSplitPaths, 1, pkg.getSplitApkPaths().length); - - mFlags = flags; - mCachedSplitApks = new ApkAssets[mSplitPaths.length][]; - mCachedAssetManagers = new AssetManager[mSplitPaths.length]; - } - - @Override - protected boolean isSplitCached(int splitIdx) { - return mCachedAssetManagers[splitIdx] != null; - } - - private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) - throws IllegalArgumentException { - if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0 - && !ApkLiteParseUtils.isApkPath(path)) { - throw new IllegalArgumentException("Invalid package file: " + path); - } - - try { - return ApkAssets.loadFromPath(path); - } catch (IOException e) { - throw new IllegalArgumentException("Failed to load APK at path " + path, e); - } - } - - private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) { - final AssetManager assets = new AssetManager(); - assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, Build.VERSION.RESOURCES_SDK_INT); - assets.setApkAssets(apkAssets, false /*invalidateCaches*/); - return assets; - } - - @Override - protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, - int parentSplitIdx) throws IllegalArgumentException { - final ArrayList assets = new ArrayList<>(); - - // Include parent ApkAssets. - if (parentSplitIdx >= 0) { - Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]); - } - - // Include this ApkAssets. - assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags)); - - // Load and include all config splits for this feature. - for (int configSplitIdx : configSplitIndices) { - assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags)); - } - - // Cache the results. - mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]); - mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets(mCachedSplitApks[splitIdx]); - } - - @Override - public AssetManager getBaseAssetManager() throws IllegalArgumentException { - loadDependenciesForSplit(0); - return mCachedAssetManagers[0]; - } - - @Override - public AssetManager getSplitAssetManager(int idx) throws IllegalArgumentException { - // Since we insert the base at position 0, and ParsingPackageUtils keeps splits separate - // from the base, we need to adjust the index. - loadDependenciesForSplit(idx + 1); - return mCachedAssetManagers[idx + 1]; - } - - @Override - public ApkAssets getBaseApkAssets() { - return mCachedSplitApks[0][0]; - } - - @Override - public void close() throws Exception { - for (AssetManager assets : mCachedAssetManagers) { - IoUtils.closeQuietly(assets); - } - } -} diff --git a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java b/services/core/java/com/android/server/pm/split/SplitAssetLoader.java deleted file mode 100644 index 845015916e60..000000000000 --- a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2022 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.server.pm.split; - -import android.content.res.ApkAssets; -import android.content.res.AssetManager; - -/** - * Simple interface for loading base Assets and Splits. Used by ParsingPackageUtils when parsing - * split APKs. - * - * @hide - */ -public interface SplitAssetLoader extends AutoCloseable { - AssetManager getBaseAssetManager() throws IllegalArgumentException; - AssetManager getSplitAssetManager(int splitIdx) throws IllegalArgumentException; - - ApkAssets getBaseApkAssets(); -} diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt index 02032c786563..f69f6283f968 100644 --- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt @@ -24,6 +24,7 @@ import android.content.pm.SigningDetails import android.os.Build import android.util.Slog import com.android.internal.os.RoSystemProperties +import com.android.internal.pm.permission.CompatibilityPermissionInfo import com.android.modules.utils.BinaryXmlPullParser import com.android.modules.utils.BinaryXmlSerializer import com.android.server.permission.access.AccessState @@ -42,7 +43,6 @@ import com.android.server.permission.access.util.hasBits import com.android.server.permission.access.util.isInternal import com.android.server.pm.KnownPackages import com.android.server.pm.parsing.PackageInfoUtils -import com.android.server.pm.permission.CompatibilityPermissionInfo import com.android.server.pm.pkg.AndroidPackage import com.android.server.pm.pkg.PackageState diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java index d62da1a02525..5b222c01d56b 100644 --- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java @@ -57,11 +57,11 @@ import android.platform.test.annotations.Presubmit; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.util.FunctionalUtils.ThrowingSupplier; import com.android.server.LocalServices; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.testing.shadows.ShadowApplicationPackageManager; import com.android.server.testing.shadows.ShadowUserManager; diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt index 3011fa17d4fc..5c4716dc751e 100644 --- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt +++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt @@ -25,6 +25,7 @@ import android.os.Binder import android.os.UserHandle import android.util.ArrayMap import com.android.internal.pm.parsing.pkg.AndroidPackageInternal +import com.android.internal.pm.parsing.pkg.PackageImpl import com.android.internal.pm.parsing.pkg.ParsedPackage import com.android.internal.pm.pkg.component.ParsedActivity import com.android.server.pm.AppsFilterImpl @@ -38,7 +39,6 @@ import com.android.server.pm.Settings import com.android.server.pm.SharedLibrariesImpl import com.android.server.pm.UserManagerInternal import com.android.server.pm.UserManagerService -import com.android.server.pm.parsing.pkg.PackageImpl import com.android.server.pm.pkg.AndroidPackage import com.android.server.pm.resolution.ComponentResolver import com.android.server.pm.snapshot.PackageDataSnapshot @@ -49,6 +49,8 @@ import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever import com.android.server.wm.ActivityTaskManagerInternal import com.google.common.truth.Truth.assertThat +import java.io.File +import java.util.UUID import org.junit.After import org.junit.Before import org.junit.BeforeClass @@ -61,8 +63,6 @@ import org.mockito.Mockito.doReturn import org.mockito.Mockito.intThat import org.mockito.Mockito.same import org.testng.Assert.assertThrows -import java.io.File -import java.util.UUID @RunWith(Parameterized::class) class PackageManagerComponentLabelIconOverrideTest { diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java index 3461bb6b2c55..7277fd79fdd5 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java @@ -49,20 +49,20 @@ import android.util.SparseArray; import androidx.annotation.NonNull; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.internal.pm.pkg.component.ParsedActivity; +import com.android.internal.pm.pkg.component.ParsedActivityImpl; +import com.android.internal.pm.pkg.component.ParsedComponentImpl; +import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl; +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl; import com.android.internal.pm.pkg.component.ParsedPermission; +import com.android.internal.pm.pkg.component.ParsedPermissionImpl; +import com.android.internal.pm.pkg.component.ParsedProviderImpl; +import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl; import com.android.internal.pm.pkg.parsing.ParsingPackage; import com.android.server.om.OverlayReferenceMapper; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.component.ParsedActivityImpl; -import com.android.server.pm.pkg.component.ParsedComponentImpl; -import com.android.server.pm.pkg.component.ParsedInstrumentationImpl; -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl; -import com.android.server.pm.pkg.component.ParsedPermissionImpl; -import com.android.server.pm.pkg.component.ParsedProviderImpl; -import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl; import com.android.server.utils.WatchableTester; import org.junit.Before; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java index f0d389be7cb6..b1c3e94c2138 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java @@ -32,11 +32,11 @@ import android.content.pm.ApplicationInfo; import android.os.Build; import android.platform.test.annotations.Presubmit; +import com.android.internal.pm.parsing.pkg.PackageImpl; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.pm.parsing.PackageInfoUtils; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.PackageStateUnserialized; import com.android.server.pm.pkg.PackageUserStateImpl; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import org.junit.After; import org.junit.Before; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java index f07e820bf8b3..b396cf498a67 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -63,10 +63,10 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.permission.persistence.RuntimePermissionsPersistence; import com.android.server.LocalServices; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.ArchiveState; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java index 9c48af8ecd01..285c059e973a 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java @@ -73,7 +73,7 @@ import androidx.test.filters.Suppress; import com.android.compatibility.common.util.CddTest; import com.android.internal.content.InstallLocationUtils; import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; +import com.android.server.pm.parsing.ParsingUtils; import com.android.server.pm.test.service.server.R; import dalvik.system.VMRuntime; @@ -346,7 +346,7 @@ public class PackageManagerTests extends AndroidTestCase { private ParsedPackage parsePackage(Uri packageURI) { final String archiveFilePath = packageURI.getPath(); - ParseResult result = ParsingPackageUtils.parseDefaultOneTime( + ParseResult result = ParsingUtils.parseDefaultOneTime( new File(archiveFilePath), 0 /*flags*/, Collections.emptyList(), false /*collectCertificates*/); if (result.isError()) { diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java index a62cd4fc5fc2..03e45a27390f 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java @@ -15,7 +15,7 @@ */ package com.android.server.pm; -import static com.android.server.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS; +import static com.android.internal.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -58,17 +58,28 @@ import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.permission.CompatibilityPermissionInfo; import com.android.internal.pm.pkg.component.ParsedActivity; +import com.android.internal.pm.pkg.component.ParsedActivityImpl; import com.android.internal.pm.pkg.component.ParsedApexSystemService; import com.android.internal.pm.pkg.component.ParsedComponent; import com.android.internal.pm.pkg.component.ParsedInstrumentation; +import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl; import com.android.internal.pm.pkg.component.ParsedIntentInfo; +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl; import com.android.internal.pm.pkg.component.ParsedPermission; import com.android.internal.pm.pkg.component.ParsedPermissionGroup; +import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl; +import com.android.internal.pm.pkg.component.ParsedPermissionImpl; +import com.android.internal.pm.pkg.component.ParsedPermissionUtils; import com.android.internal.pm.pkg.component.ParsedProvider; +import com.android.internal.pm.pkg.component.ParsedProviderImpl; import com.android.internal.pm.pkg.component.ParsedService; +import com.android.internal.pm.pkg.component.ParsedServiceImpl; import com.android.internal.pm.pkg.component.ParsedUsesPermission; +import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl; import com.android.internal.pm.pkg.parsing.ParsingPackage; import com.android.internal.util.ArrayUtils; import com.android.server.pm.parsing.PackageCacher; @@ -76,19 +87,8 @@ import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.TestPackageParser2; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; -import com.android.server.pm.parsing.pkg.PackageImpl; -import com.android.server.pm.permission.CompatibilityPermissionInfo; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageUserStateInternal; -import com.android.server.pm.pkg.component.ParsedActivityImpl; -import com.android.server.pm.pkg.component.ParsedInstrumentationImpl; -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl; -import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl; -import com.android.server.pm.pkg.component.ParsedPermissionImpl; -import com.android.server.pm.pkg.component.ParsedPermissionUtils; -import com.android.server.pm.pkg.component.ParsedProviderImpl; -import com.android.server.pm.pkg.component.ParsedServiceImpl; -import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl; import org.junit.Before; import org.junit.Rule; @@ -725,6 +725,16 @@ public class PackageParserTest { public boolean hasFeature(String feature) { return false; } + + @Override + public Set getHiddenApiWhitelistedApps() { + return new ArraySet<>(); + } + + @Override + public Set getInstallConstraintsAllowlist() { + return new ArraySet<>(); + } }); if (cacheDir != null) { setCacheDir(cacheDir); diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java index 6202908cdfbf..c1271bb0ee36 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java @@ -50,13 +50,13 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.util.Pair; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl; import com.android.internal.pm.pkg.parsing.ParsingPackage; import com.android.server.compat.PlatformCompat; import com.android.server.pm.parsing.PackageInfoUtils; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import org.hamcrest.BaseMatcher; @@ -376,7 +376,7 @@ public class ScanTests { // Create the ParsedPackage for the apex final ParsedPackage basicPackage = ((ParsedPackage) new PackageImpl(DUMMY_PACKAGE_NAME, codePath, codePath, - mock(TypedArray.class), false) + mock(TypedArray.class), false, null) .setVolumeUuid(UUID_ONE.toString()) .hideAsParsed()) .setVersionCodeMajor(1) @@ -595,7 +595,7 @@ public class ScanTests { // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps return (ParsingPackage) ((ParsedPackage) new PackageImpl(packageName, "/data/tmp/randompath/base.apk", createCodePath(packageName), - mock(TypedArray.class), false) + mock(TypedArray.class), false, null) .setVolumeUuid(UUID_ONE.toString()) .addUsesStaticLibrary("some.static.library", 234L, new String[]{"testCert1"}) .addUsesStaticLibrary("some.other.static.library", 456L, new String[]{"testCert2"}) diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java index b102ab4f7e3b..b63950c10a18 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java @@ -39,14 +39,14 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.component.ParsedActivityUtils; import com.android.internal.pm.pkg.component.ParsedComponent; import com.android.internal.pm.pkg.component.ParsedIntentInfo; import com.android.internal.pm.pkg.component.ParsedPermission; +import com.android.internal.pm.pkg.component.ParsedPermissionUtils; import com.android.internal.util.ArrayUtils; import com.android.server.pm.PackageManagerException; import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.component.ParsedActivityUtils; -import com.android.server.pm.pkg.component.ParsedPermissionUtils; import com.android.server.pm.test.service.server.R; import com.google.common.truth.Expect; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt index 67b91d2646d9..c435b94fcacd 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt @@ -22,7 +22,6 @@ import android.content.pm.parsing.result.ParseResult import android.platform.test.annotations.Presubmit import androidx.test.InstrumentationRegistry import com.android.internal.pm.parsing.pkg.ParsedPackage -import com.android.server.pm.pkg.parsing.ParsingPackageUtils import com.android.server.pm.test.service.server.R import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage @@ -121,7 +120,7 @@ class PackageParsingDeferErrorTest { input.copyTo(output) } } - return ParsingPackageUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(), + return ParsingUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(), false /*collectCertificates*/) } } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java new file mode 100644 index 000000000000..a9eac95dfd87 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing; + +import android.annotation.NonNull; +import android.content.pm.parsing.result.ParseInput; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; +import android.content.res.TypedArray; +import android.permission.PermissionManager; + +import com.android.internal.pm.parsing.pkg.PackageImpl; +import com.android.internal.pm.parsing.pkg.ParsedPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackage; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; +import com.android.server.SystemConfig; + +import java.io.File; +import java.util.List; +import java.util.Set; + +/** @hide **/ +public class ParsingUtils { + + /** + * @see ParsingPackageUtils#parseDefault(ParseInput, File, int, List, boolean, + * ParsingPackageUtils.Callback) + */ + @NonNull + public static ParseResult parseDefaultOneTime(File file, + @ParsingPackageUtils.ParseFlags int parseFlags, + @NonNull List splitPermissions, + boolean collectCertificates) { + ParseInput input = ParseTypeImpl.forDefaultParsing().reset(); + return ParsingPackageUtils.parseDefault(input, file, parseFlags, splitPermissions, collectCertificates, + new ParsingPackageUtils.Callback() { + @Override + public boolean hasFeature(String feature) { + // Assume the device doesn't support anything. This will affect permission + // parsing and will force declarations to include all + // requiredNotFeature permissions and exclude all requiredFeature + // permissions. This mirrors the old behavior. + return false; + } + + @Override + public ParsingPackage startParsingPackage( + @NonNull String packageName, + @NonNull String baseApkPath, + @NonNull String path, + @NonNull TypedArray manifestArray, boolean isCoreApp) { + return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray, + isCoreApp, this); + } + + @Override + public Set getHiddenApiWhitelistedApps() { + return SystemConfig.getInstance().getHiddenApiWhitelistedApps(); + } + + @Override + public Set getInstallConstraintsAllowlist() { + return SystemConfig.getInstance().getInstallConstraintsAllowlist(); + } + }); + } +} diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt index 1f57b6c9f95f..98af63c65e90 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt @@ -17,15 +17,15 @@ package com.android.server.pm.parsing import android.content.pm.PackageManager -import com.android.server.pm.pkg.parsing.ParsingPackageUtils import android.platform.test.annotations.Postsubmit +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils import com.android.server.pm.PackageManagerException import com.android.server.pm.PackageManagerService import com.android.server.pm.PackageManagerServiceUtils +import java.io.File import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder -import java.io.File /** * This test parses all the system APKs on the device image to ensure that they succeed. diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java index 6cd71237efa2..9517e49c4a73 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java @@ -24,8 +24,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java index 27fd781584f2..01fad8f57d16 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java @@ -21,8 +21,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java index b13d6de55cf6..b1f26c253043 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java @@ -23,8 +23,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java index fa69f844c33a..349763ae18b3 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java @@ -24,9 +24,9 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java index 856013a96017..71bdacbce9f7 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java @@ -22,9 +22,9 @@ import android.util.ArrayMap; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.server.SystemConfig; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Before; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java index ae5ea21aec4e..6aa0c2db4d39 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java @@ -21,8 +21,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java index e126ffcab5ff..44098d0be2b2 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java @@ -23,8 +23,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java index d0b0cf894340..9d5ce8a66395 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java @@ -28,10 +28,10 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.internal.pm.pkg.parsing.ParsingPackage; import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Assume; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java index c141c0337540..bffeb7255b31 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java @@ -23,9 +23,9 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java index a58604b81e06..b114cd375050 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java @@ -23,9 +23,9 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.Test; diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt index 09b66c11d200..ef9c62fd3795 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt @@ -30,21 +30,21 @@ import android.util.ArraySet import android.util.SparseArray import android.util.SparseIntArray import com.android.internal.R -import com.android.server.pm.parsing.pkg.AndroidPackageUtils -import com.android.server.pm.parsing.pkg.PackageImpl +import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils +import com.android.internal.pm.parsing.pkg.PackageImpl +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl +import com.android.internal.pm.pkg.component.ParsedAttributionImpl +import com.android.internal.pm.pkg.component.ParsedComponentImpl +import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl +import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl +import com.android.internal.pm.pkg.component.ParsedPermissionImpl +import com.android.internal.pm.pkg.component.ParsedProcessImpl +import com.android.internal.pm.pkg.component.ParsedProviderImpl +import com.android.internal.pm.pkg.component.ParsedServiceImpl +import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl import com.android.server.pm.pkg.AndroidPackage -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl -import com.android.server.pm.pkg.component.ParsedAttributionImpl -import com.android.server.pm.pkg.component.ParsedComponentImpl -import com.android.server.pm.pkg.component.ParsedInstrumentationImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl -import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl -import com.android.server.pm.pkg.component.ParsedPermissionImpl -import com.android.server.pm.pkg.component.ParsedProcessImpl -import com.android.server.pm.pkg.component.ParsedProviderImpl -import com.android.server.pm.pkg.component.ParsedServiceImpl -import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever import java.security.KeyPairGenerator @@ -534,34 +534,34 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag } ), getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")), - getSetByValue({ AndroidPackageUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true), - getSetByValue({ AndroidPackageUtils.isOem(it) }, "isOem", PackageImpl::setOem, true), + getSetByValue({ AndroidPackageLegacyUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true), + getSetByValue({ AndroidPackageLegacyUtils.isOem(it) }, "isOem", PackageImpl::setOem, true), getSetByValue( - { AndroidPackageUtils.isPrivileged(it) }, + { AndroidPackageLegacyUtils.isPrivileged(it) }, "isPrivileged", PackageImpl::setPrivileged, true ), getSetByValue( - { AndroidPackageUtils.isProduct(it) }, + { AndroidPackageLegacyUtils.isProduct(it) }, "isProduct", PackageImpl::setProduct, true ), getSetByValue( - { AndroidPackageUtils.isVendor(it) }, + { AndroidPackageLegacyUtils.isVendor(it) }, "isVendor", PackageImpl::setVendor, true ), getSetByValue( - { AndroidPackageUtils.isSystem(it) }, + { AndroidPackageLegacyUtils.isSystem(it) }, "isSystem", PackageImpl::setSystem, true ), getSetByValue( - { AndroidPackageUtils.isSystemExt(it) }, + { AndroidPackageLegacyUtils.isSystemExt(it) }, "isSystemExt", PackageImpl::setSystemExt, true @@ -593,7 +593,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag ) ) { "" } }, - true + true, null ) .asSplit( arrayOf("testSplitNameZero", "testSplitNameOne"), diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt index 26468544e8d6..2c8b1cd884f1 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt @@ -18,7 +18,7 @@ package com.android.server.pm.test.parsing.parcelling import android.content.pm.ActivityInfo import com.android.internal.pm.pkg.component.ParsedActivity -import com.android.server.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedActivityImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt index 52d5b3bccb72..ad5374672d22 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt @@ -17,7 +17,7 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedAttribution -import com.android.server.pm.pkg.component.ParsedAttributionImpl +import com.android.internal.pm.pkg.component.ParsedAttributionImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt index af0c0de2db15..3ac48536b39c 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt @@ -18,8 +18,8 @@ package com.android.server.pm.test.parsing.parcelling import android.content.pm.PackageManager import com.android.internal.pm.pkg.component.ParsedComponent -import com.android.server.pm.pkg.component.ParsedComponentImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl +import com.android.internal.pm.pkg.component.ParsedComponentImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import android.os.Bundle import android.os.Parcelable import kotlin.contracts.ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt index dc0f194f10cc..2bd4f617dcb5 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt @@ -17,7 +17,7 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedInstrumentation -import com.android.server.pm.pkg.component.ParsedInstrumentationImpl +import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt index 5224f23d38d1..af385e202a9e 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt @@ -17,7 +17,7 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedIntentInfo -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import android.os.Parcelable import android.os.PatternMatcher import kotlin.contracts.ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt index dfff6025e2eb..061e39ddf6df 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt @@ -17,7 +17,7 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedMainComponent -import com.android.server.pm.pkg.component.ParsedMainComponentImpl +import com.android.internal.pm.pkg.component.ParsedMainComponentImpl import android.os.Parcelable import java.util.Arrays import kotlin.contracts.ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt index ccbf558734d3..3a6418824dfa 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt @@ -17,7 +17,7 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedPermissionGroup -import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl +import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt index 2814783b6849..551f16d2a3bb 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt @@ -18,8 +18,8 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedPermission import com.android.internal.pm.pkg.component.ParsedPermissionGroup -import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl -import com.android.server.pm.pkg.component.ParsedPermissionImpl +import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl +import com.android.internal.pm.pkg.component.ParsedPermissionImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt index 2e9604696acb..93bdeaeb90e3 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt @@ -16,9 +16,9 @@ package com.android.server.pm.test.parsing.parcelling -import com.android.internal.pm.pkg.component.ParsedProcess -import com.android.server.pm.pkg.component.ParsedProcessImpl import android.util.ArrayMap +import com.android.internal.pm.pkg.component.ParsedProcess +import com.android.internal.pm.pkg.component.ParsedProcessImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt index 290dbd6277b6..1e844705fe3c 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt @@ -17,9 +17,9 @@ package com.android.server.pm.test.parsing.parcelling import android.content.pm.PathPermission -import com.android.internal.pm.pkg.component.ParsedProvider -import com.android.server.pm.pkg.component.ParsedProviderImpl import android.os.PatternMatcher +import com.android.internal.pm.pkg.component.ParsedProvider +import com.android.internal.pm.pkg.component.ParsedProviderImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt index 3ae7e9220cc6..79d5a4f7030a 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt @@ -17,7 +17,7 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedService -import com.android.server.pm.pkg.component.ParsedServiceImpl +import com.android.internal.pm.pkg.component.ParsedServiceImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt index 67dfc6d4f7ef..d0ad09be982b 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt @@ -17,7 +17,7 @@ package com.android.server.pm.test.parsing.parcelling import com.android.internal.pm.pkg.component.ParsedUsesPermission -import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl +import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl import kotlin.contracts.ExperimentalContracts @ExperimentalContracts diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt index 1da3a2234ffc..b21c34905bad 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt @@ -17,37 +17,34 @@ package com.android.server.pm.test.pkg import android.content.Intent -import android.content.pm.overlay.OverlayPaths import android.content.pm.PackageManager import android.content.pm.PathPermission import android.content.pm.SharedLibraryInfo import android.content.pm.VersionedPackage +import android.content.pm.overlay.OverlayPaths import android.os.PatternMatcher import android.util.ArraySet +import com.android.internal.pm.parsing.pkg.PackageImpl import com.android.internal.pm.pkg.component.ParsedActivity +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedComponentImpl import com.android.internal.pm.pkg.component.ParsedInstrumentation +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import com.android.internal.pm.pkg.component.ParsedPermission import com.android.internal.pm.pkg.component.ParsedPermissionGroup +import com.android.internal.pm.pkg.component.ParsedPermissionImpl import com.android.internal.pm.pkg.component.ParsedProcess +import com.android.internal.pm.pkg.component.ParsedProcessImpl import com.android.internal.pm.pkg.component.ParsedProvider +import com.android.internal.pm.pkg.component.ParsedProviderImpl import com.android.internal.pm.pkg.component.ParsedService import com.android.server.pm.PackageSetting import com.android.server.pm.PackageSettingBuilder -import com.android.server.pm.parsing.pkg.PackageImpl import com.android.server.pm.pkg.AndroidPackage import com.android.server.pm.pkg.PackageState import com.android.server.pm.pkg.PackageUserState -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedComponentImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl -import com.android.server.pm.pkg.component.ParsedPermissionImpl -import com.android.server.pm.pkg.component.ParsedProcessImpl -import com.android.server.pm.pkg.component.ParsedProviderImpl import com.android.server.pm.test.parsing.parcelling.AndroidPackageTest import com.google.common.truth.Expect -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder import kotlin.contracts.ExperimentalContracts import kotlin.reflect.KClass import kotlin.reflect.KFunction @@ -55,6 +52,9 @@ import kotlin.reflect.KType import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.full.memberFunctions import kotlin.reflect.full.starProjectedType +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder class PackageStateTest { diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt index 9341e9d96335..5e73d198f528 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt @@ -22,11 +22,11 @@ import android.os.Build import android.os.PatternMatcher import android.util.ArraySet import com.android.internal.pm.parsing.pkg.AndroidPackageInternal +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.SystemConfig import com.android.server.compat.PlatformCompat import com.android.server.pm.pkg.AndroidPackage -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationCollector import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt index a737b9097b53..d307608e0be2 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt @@ -29,17 +29,22 @@ import android.util.IndentingPrintWriter import android.util.SparseArray import androidx.test.platform.app.InstrumentationRegistry import com.android.internal.pm.parsing.pkg.AndroidPackageInternal +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.Computer import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.pkg.PackageUserStateInternal -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationEnforcer import com.android.server.pm.verify.domain.DomainVerificationManagerInternal import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever +import java.util.UUID +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger +import kotlin.test.assertFailsWith +import kotlin.test.fail import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -51,11 +56,6 @@ import org.mockito.Mockito.doReturn import org.mockito.Mockito.eq import org.mockito.Mockito.mock import org.mockito.Mockito.verifyNoMoreInteractions -import java.util.UUID -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicInteger -import kotlin.test.assertFailsWith -import kotlin.test.fail @RunWith(Parameterized::class) class DomainVerificationEnforcerTest { diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt index f38df22af630..5edf30a33def 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt @@ -30,24 +30,24 @@ import android.os.Process import android.util.ArraySet import android.util.SparseArray import com.android.internal.pm.parsing.pkg.AndroidPackageInternal +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.pkg.PackageUserStateInternal -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationManagerStub import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever import com.google.common.truth.Truth.assertThat +import java.util.UUID +import java.util.concurrent.atomic.AtomicBoolean +import kotlin.test.assertFailsWith import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.doReturn -import java.util.UUID -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.test.assertFailsWith class DomainVerificationManagerApiTest { diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt index 874e0d2bbc9a..85f012534113 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt @@ -37,27 +37,27 @@ import android.util.ArraySet import android.util.SparseArray import android.util.Xml import com.android.internal.pm.parsing.pkg.AndroidPackageInternal +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.Computer import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.pkg.PackageUserStateInternal -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.testutils.mock import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.spy import com.android.server.testutils.whenever import com.google.common.truth.Truth.assertThat +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.security.PublicKey +import java.util.UUID import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.doReturn -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import java.security.PublicKey -import java.util.UUID class DomainVerificationPackageTest { diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt index 3207e6c2a411..a5c4f6cc0289 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt @@ -25,15 +25,16 @@ import android.os.Process import android.util.ArraySet import android.util.SparseArray import com.android.internal.pm.parsing.pkg.AndroidPackageInternal +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.pkg.PackageUserStateInternal -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationManagerInternal import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever +import java.util.UUID import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -44,7 +45,6 @@ import org.mockito.Mockito.anyString import org.mockito.Mockito.doReturn import org.mockito.Mockito.eq import org.mockito.Mockito.verify -import java.util.UUID @RunWith(Parameterized::class) class DomainVerificationSettingsMutationTest { diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt index a90b7d5ec7da..ae570a3a0ee2 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt @@ -27,14 +27,15 @@ import android.os.Process import android.util.ArraySet import android.util.SparseArray import com.android.internal.pm.parsing.pkg.AndroidPackageInternal +import com.android.internal.pm.pkg.component.ParsedActivityImpl +import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.pkg.PackageUserStateInternal -import com.android.server.pm.pkg.component.ParsedActivityImpl -import com.android.server.pm.pkg.component.ParsedIntentInfoImpl import com.android.server.pm.verify.domain.DomainVerificationService import com.android.server.testutils.mockThrowOnUnmocked import com.android.server.testutils.whenever import com.google.common.truth.Truth.assertThat +import java.util.UUID import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyInt @@ -42,8 +43,6 @@ import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.doReturn -import java.util.UUID - class DomainVerificationUserStateOverrideTest { companion object { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java index de8b3080907c..c2b52b4ee9c8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java @@ -45,14 +45,15 @@ import android.os.Environment; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.pm.parsing.PackageParser2; -import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.pkg.AndroidPackage; -import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import org.junit.Before; import org.junit.Rule; @@ -67,6 +68,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.Objects; +import java.util.Set; @SmallTest @Presubmit @@ -106,6 +108,18 @@ public class ApexManagerTest { public boolean hasFeature(String feature) { return true; } + + @androidx.annotation.NonNull + @Override + public Set getHiddenApiWhitelistedApps() { + return new ArraySet<>(); + } + + @androidx.annotation.NonNull + @Override + public Set getInstallConstraintsAllowlist() { + return new ArraySet<>(); + } }); mMockSystem.system().stageNominalSystemState(); @@ -385,7 +399,7 @@ public class ApexManagerTest { findFactory(results, "test.apex.rebootless").apexInfo); assertThat(factoryPkg.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath); assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1); - assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue(); + assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue(); } @Test @@ -416,7 +430,7 @@ public class ApexManagerTest { findFactory(results, "test.apex.rebootless").apexInfo); assertThat(factoryPkg.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath); assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1); - assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue(); + assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue(); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index 28bd98781ced..7b29e2a4159d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -56,8 +56,10 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.spy import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder import com.android.internal.R +import com.android.internal.pm.parsing.pkg.PackageImpl import com.android.internal.pm.parsing.pkg.ParsedPackage import com.android.internal.pm.pkg.parsing.ParsingPackage +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils import com.android.server.LocalManagerRegistry import com.android.server.LocalServices import com.android.server.LockGuard @@ -68,10 +70,8 @@ import com.android.server.extendedtestutils.wheneverStatic import com.android.server.pm.dex.DexManager import com.android.server.pm.dex.DynamicCodeLogger import com.android.server.pm.parsing.PackageParser2 -import com.android.server.pm.parsing.pkg.PackageImpl import com.android.server.pm.permission.PermissionManagerServiceInternal import com.android.server.pm.pkg.AndroidPackage -import com.android.server.pm.pkg.parsing.ParsingPackageUtils import com.android.server.pm.resolution.ComponentResolver import com.android.server.pm.snapshot.PackageDataSnapshot import com.android.server.pm.verify.domain.DomainVerificationManagerInternal @@ -81,14 +81,6 @@ import com.android.server.testutils.mock import com.android.server.testutils.nullable import com.android.server.testutils.whenever import com.android.server.utils.WatchedArrayMap -import libcore.util.HexEncoding -import org.junit.Assert -import org.junit.rules.TestRule -import org.junit.runner.Description -import org.junit.runners.model.Statement -import org.mockito.AdditionalMatchers.or -import org.mockito.Mockito -import org.mockito.quality.Strictness import java.io.File import java.io.IOException import java.nio.file.Files @@ -97,6 +89,14 @@ import java.security.cert.CertificateException import java.util.Arrays import java.util.Random import java.util.concurrent.FutureTask +import libcore.util.HexEncoding +import org.junit.Assert +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement +import org.mockito.AdditionalMatchers.or +import org.mockito.Mockito +import org.mockito.quality.Strictness /** * A utility for mocking behavior of the system and dependencies when testing PackageManagerService diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt index e685c3fa9fa4..944b1aae7bda 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt @@ -21,17 +21,17 @@ import android.content.pm.PackageManager import android.content.pm.SharedLibraryInfo import android.content.pm.VersionedPackage import android.os.Build -import android.os.storage.StorageManager import android.os.UserHandle +import android.os.storage.StorageManager import android.util.ArrayMap import android.util.PackageUtils +import com.android.internal.pm.parsing.pkg.PackageImpl import com.android.internal.pm.parsing.pkg.ParsedPackage import com.android.server.SystemConfig.SharedLibraryEntry import com.android.server.compat.PlatformCompat import com.android.server.extendedtestutils.wheneverStatic import com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME import com.android.server.pm.pkg.AndroidPackage -import com.android.server.pm.parsing.pkg.PackageImpl import com.android.server.testutils.any import com.android.server.testutils.eq import com.android.server.testutils.mock diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java index dd687fd4286c..86a1358f371c 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java @@ -27,9 +27,9 @@ import static org.mockito.Mockito.when; import android.os.Build; import android.platform.test.annotations.Presubmit; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.server.compat.PlatformCompat; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.PackageState; import org.junit.Test; diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java index 8464969cd0f3..ee93bc1e3562 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java @@ -53,10 +53,10 @@ import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import androidx.test.uiautomator.UiDevice; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.server.LocalServices; import com.android.server.SystemConfig; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import org.junit.After; diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index 0f87202f8939..587f5fa9c623 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -29,9 +29,9 @@ import android.util.SparseArray; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.internal.pm.pkg.parsing.ParsingPackage; -import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.AndroidPackage; import dalvik.system.DelegateLastClassLoader; diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt index ee23a00f27d7..9b4ca2a86f2c 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt @@ -21,17 +21,17 @@ import android.os.Environment import android.os.SystemProperties.PROP_VALUE_MAX import android.platform.test.annotations.Postsubmit import com.android.internal.R +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils import com.android.server.pm.PackageManagerService -import com.android.server.pm.pkg.parsing.ParsingPackageUtils import com.google.common.truth.Truth.assertThat +import java.io.ByteArrayInputStream +import java.io.File import org.junit.Assert.assertEquals import org.junit.Assert.assertThrows import org.junit.Assert.fail import org.junit.Test import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParserFactory -import java.io.ByteArrayInputStream -import java.io.File @Postsubmit class AndroidPackageParsingValidationTest { diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt index 2332817911f7..c44f583a93ef 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt @@ -17,6 +17,7 @@ package com.android.server.pm.parsing import android.content.pm.ApplicationInfo +import android.util.ArraySet import java.io.File class TestPackageParser2(var cacheDir: File? = null) : PackageParser2( @@ -33,4 +34,7 @@ class TestPackageParser2(var cacheDir: File? = null) : PackageParser2( // behavior. return false } + + override fun getHiddenApiWhitelistedApps() = ArraySet() + override fun getInstallConstraintsAllowlist() = ArraySet() }) diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java index 5ba4851270fd..759b204516c6 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java @@ -32,8 +32,9 @@ import android.content.rollback.PackageRollbackInfo; import android.util.SparseArray; import android.util.SparseIntArray; +import com.android.internal.pm.parsing.pkg.PackageImpl; import com.android.server.pm.PackageList; -import com.android.server.pm.parsing.pkg.PackageImpl; + import com.google.common.collect.Range; import org.junit.Before; @@ -415,7 +416,7 @@ public class RollbackUnitTest { private void addPkgWithMinExtVersions(String pkg, int[][] minExtVersions) { mPackages.add(pkg); - PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false); + PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false, null); pkgImpl.setMinExtensionVersions(sparseArrayFrom(minExtVersions)); when(mMockPmi.getPackage(pkg)).thenReturn(pkgImpl); -- cgit v1.2.3-59-g8ed1b