summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp36
-rw-r--r--TEST_MAPPING28
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java7
-rw-r--r--apex/sdkext/Android.bp26
-rw-r--r--apex/sdkext/TEST_MAPPING2
-rw-r--r--apex/sdkext/derive_sdk/derive_sdk.cpp2
-rw-r--r--apex/sdkext/framework/java/android/os/ext/SdkExtensions.java21
-rw-r--r--apex/sdkext/framework/tests/Android.bp11
-rw-r--r--apex/sdkext/framework/tests/AndroidManifest.xml27
-rw-r--r--apex/sdkext/gen_sdkinfo.py19
-rw-r--r--apex/statsd/Android.bp11
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java62
-rw-r--r--apex/statsd/testing/Android.bp25
-rw-r--r--apex/statsd/testing/test_manifest.json4
-rw-r--r--api/current.txt24
-rw-r--r--api/system-current.txt146
-rw-r--r--api/system-lint-baseline.txt1
-rw-r--r--api/test-current.txt3
-rw-r--r--api/test-lint-baseline.txt6
-rw-r--r--cmds/statsd/Android.bp1
-rw-r--r--cmds/statsd/src/atoms.proto38
-rw-r--r--cmds/statsd/src/external/StatsCallbackPuller.cpp21
-rw-r--r--cmds/statsd/src/external/StatsCallbackPuller.h8
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp12
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp11
-rw-r--r--cmds/statsd/src/logd/LogEvent.h5
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp28
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h7
-rw-r--r--cmds/statsd/src/state/StateManager.cpp9
-rw-r--r--cmds/statsd/src/state/StateManager.h13
-rw-r--r--cmds/statsd/src/state/StateTracker.cpp7
-rw-r--r--cmds/statsd/src/state/StateTracker.h6
-rw-r--r--cmds/statsd/tests/external/StatsCallbackPuller_test.cpp210
-rw-r--r--cmds/statsd/tests/external/StatsPuller_test.cpp5
-rw-r--r--cmds/uiautomator/library/Android.bp1
-rw-r--r--config/preloaded-classes12
-rw-r--r--core/java/android/accessibilityservice/AccessibilityShortcutInfo.java10
-rw-r--r--core/java/android/annotation/Hide.java41
-rw-r--r--core/java/android/app/Activity.java110
-rw-r--r--core/java/android/app/ActivityThread.java1
-rw-r--r--core/java/android/app/AppOpsManager.java2
-rw-r--r--core/java/android/app/IBackupAgent.aidl13
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/Instrumentation.java17
-rw-r--r--core/java/android/app/backup/BackupAgent.java47
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.java1
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.java7
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/Intent.java172
-rw-r--r--core/java/android/content/integrity/AtomicFormula.java2
-rw-r--r--core/java/android/content/integrity/CompoundFormula.java1
-rw-r--r--core/java/android/content/integrity/Formula.java1
-rw-r--r--core/java/android/content/integrity/Rule.java1
-rw-r--r--core/java/android/content/pm/ActivityInfo.java3
-rw-r--r--core/java/android/content/pm/PackageInfo.java3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java14
-rw-r--r--core/java/android/content/pm/PackageParser.java438
-rw-r--r--core/java/android/content/pm/PackageUserState.java60
-rw-r--r--core/java/android/content/pm/ParceledListSlice.aidl2
-rw-r--r--core/java/android/content/pm/SharedLibraryInfo.java21
-rw-r--r--core/java/android/content/pm/dex/DexMetadataHelper.java7
-rw-r--r--core/java/android/content/pm/parsing/AndroidPackage.aidl21
-rw-r--r--core/java/android/content/pm/parsing/AndroidPackage.java475
-rw-r--r--core/java/android/content/pm/parsing/AndroidPackageWrite.java59
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java428
-rw-r--r--core/java/android/content/pm/parsing/ApkParseUtils.java3187
-rw-r--r--core/java/android/content/pm/parsing/ComponentParseUtils.java3250
-rw-r--r--core/java/android/content/pm/parsing/PackageImpl.java3234
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoUtils.java572
-rw-r--r--core/java/android/content/pm/parsing/ParsedPackage.java155
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java327
-rw-r--r--core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java (renamed from core/java/android/content/pm/AndroidHidlUpdater.java)26
-rw-r--r--core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java (renamed from core/java/android/content/pm/AndroidTestBaseUpdater.java)21
-rw-r--r--core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java (renamed from core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java)20
-rw-r--r--core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java (renamed from core/java/android/content/pm/PackageBackwardCompatibility.java)42
-rw-r--r--core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java (renamed from core/java/android/content/pm/PackageSharedLibraryUpdater.java)48
-rw-r--r--core/java/android/content/pm/parsing/library/SharedLibraryNames.java (renamed from core/java/android/content/pm/SharedLibraryNames.java)4
-rw-r--r--core/java/android/content/res/Configuration.java6
-rw-r--r--core/java/android/content/res/Resources.java1
-rw-r--r--core/java/android/content/res/ResourcesImpl.java4
-rw-r--r--core/java/android/ddm/DdmHandleAppName.java64
-rw-r--r--core/java/android/ddm/DdmHandleHello.java14
-rw-r--r--core/java/android/net/InterfaceConfiguration.java4
-rw-r--r--core/java/android/net/NetworkRequest.java9
-rw-r--r--core/java/android/os/Process.java11
-rw-r--r--core/java/android/os/Trace.java54
-rw-r--r--core/java/android/os/ZygoteProcess.java29
-rw-r--r--core/java/android/os/storage/StorageManagerInternal.java9
-rw-r--r--core/java/android/provider/ContactsContract.java36
-rw-r--r--core/java/android/provider/DeviceConfig.java7
-rw-r--r--core/java/android/provider/Settings.java16
-rw-r--r--core/java/android/service/incremental/IncrementalDataLoaderService.java563
-rw-r--r--core/java/android/service/sms/FinancialSmsService.java104
-rw-r--r--core/java/android/service/sms/IFinancialSmsService.aidl30
-rw-r--r--core/java/android/service/textclassifier/TextClassifierService.java25
-rw-r--r--core/java/android/telephony/CellBroadcastIntents.java13
-rw-r--r--core/java/android/text/AlteredCharSequence.java4
-rw-r--r--core/java/android/util/LocalLog.java23
-rw-r--r--core/java/android/util/StatsEvent.aidl19
-rw-r--r--core/java/android/util/StatsEvent.java66
-rw-r--r--core/java/android/util/StatsLog.java3
-rw-r--r--core/java/android/util/apk/VerityBuilder.java53
-rw-r--r--core/java/android/view/Display.java9
-rw-r--r--core/java/android/view/Window.java10
-rw-r--r--core/java/android/view/WindowManager.java63
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java51
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl2
-rw-r--r--core/java/android/view/textclassifier/ConfigParser.java264
-rw-r--r--core/java/android/view/textclassifier/SelectionEvent.java4
-rw-r--r--core/java/android/view/textclassifier/TextClassificationConstants.java187
-rw-r--r--core/java/android/view/textclassifier/TextClassificationManager.java57
-rw-r--r--core/java/android/widget/RemoteViews.java23
-rw-r--r--core/java/com/android/internal/accessibility/AccessibilityShortcutController.java133
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java151
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java355
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java128
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java330
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java9
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java16
-rw-r--r--core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java113
-rw-r--r--core/java/com/android/internal/app/WrapHeightViewPager.java71
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java15
-rw-r--r--core/java/com/android/internal/infra/AndroidFuture.java5
-rw-r--r--core/java/com/android/internal/infra/TEST_MAPPING16
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java5
-rw-r--r--core/java/com/android/internal/os/WrapperInit.java12
-rw-r--r--core/java/com/android/internal/os/Zygote.java1
-rw-r--r--core/java/com/android/internal/os/ZygoteArguments.java16
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java1
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java14
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java12
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java8
-rw-r--r--core/java/com/android/internal/util/Preconditions.java18
-rw-r--r--core/jni/Android.bp4
-rw-r--r--core/jni/AndroidRuntime.cpp13
-rw-r--r--core/jni/android_media_AudioDeviceAddress.cpp53
-rw-r--r--core/jni/android_media_AudioDeviceAddress.h (renamed from core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java)27
-rw-r--r--core/jni/android_media_AudioSystem.cpp63
-rw-r--r--core/jni/android_os_Trace.cpp12
-rw-r--r--core/jni/android_service_DataLoaderService.cpp269
-rw-r--r--core/jni/fd_utils.cpp2
-rw-r--r--core/proto/android/server/windowmanagerservice.proto1
-rw-r--r--core/proto/android/service/notification.proto11
-rw-r--r--core/proto/android/view/windowlayoutparams.proto7
-rw-r--r--core/res/AndroidManifest.xml12
-rw-r--r--core/res/res/layout/chooser_grid.xml14
-rw-r--r--core/res/res/layout/chooser_list_per_profile.xml27
-rw-r--r--core/res/res/layout/resolver_list.xml16
-rw-r--r--core/res/res/layout/resolver_list_per_profile.xml31
-rw-r--r--core/res/res/layout/resolver_list_with_default.xml16
-rw-r--r--core/res/res/values-sw600dp/bools.xml1
-rw-r--r--core/res/res/values-television/config.xml4
-rw-r--r--core/res/res/values/bools.xml1
-rw-r--r--core/res/res/values/config.xml14
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--core/tests/coretests/Android.bp1
-rw-r--r--core/tests/coretests/apks/install_multi_package/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_multi_package/AndroidManifest.xml104
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java24
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java24
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java30
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java30
-rw-r--r--core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java136
-rw-r--r--core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java110
-rw-r--r--core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java64
-rw-r--r--core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java110
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageBuilder.java104
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageParserTest.java137
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java32
-rw-r--r--core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java133
-rw-r--r--core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java132
-rw-r--r--core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java31
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java191
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java152
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java79
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java152
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java (renamed from core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java)85
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java50
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java169
-rw-r--r--core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java168
-rw-r--r--core/tests/coretests/src/android/util/LocalLogTest.java20
-rw-r--r--core/tests/coretests/src/android/util/StatsEventTest.java7
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java138
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java321
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java2
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java89
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java16
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java5
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java21
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java13
-rw-r--r--core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java126
-rw-r--r--data/etc/Android.bp2
-rw-r--r--data/etc/CleanSpec.mk2
-rw-r--r--data/etc/com.android.settings.xml1
-rw-r--r--data/etc/services.core.protolog.json30
-rw-r--r--data/sounds/AudioPackageGo.mk4
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java3
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp13
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp165
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h4
-rw-r--r--libs/services/Android.bp5
-rw-r--r--libs/services/include/android/util/StatsEvent.h43
-rw-r--r--libs/services/src/util/StatsEvent.cpp58
-rw-r--r--location/java/android/location/LocationManager.java8
-rw-r--r--media/apex/java/android/media/MediaParser.java51
-rw-r--r--media/java/android/media/AudioDeviceAddress.java34
-rw-r--r--media/java/android/media/AudioDeviceInfo.java4
-rw-r--r--media/java/android/media/AudioManager.java81
-rw-r--r--media/java/android/media/AudioSystem.java42
-rw-r--r--media/java/android/media/IAudioService.aidl7
-rw-r--r--media/java/android/media/MediaFormat.java28
-rw-r--r--media/java/android/media/audiopolicy/AudioProductStrategy.java14
-rw-r--r--media/java/android/media/tv/tuner/DvrSettings.java124
-rw-r--r--media/java/android/media/tv/tuner/FilterSettings.java383
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java19
-rw-r--r--media/java/android/media/tv/tuner/TunerConstants.java18
-rw-r--r--media/jni/Android.bp2
-rw-r--r--media/jni/android_media_tv_Tuner.cpp248
-rw-r--r--media/jni/android_media_tv_Tuner.h25
-rw-r--r--media/jni/audioeffect/Android.bp1
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java14
-rw-r--r--packages/SettingsLib/res/values/strings.xml6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java329
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java41
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java174
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java47
-rw-r--r--packages/SystemUI/AndroidManifest.xml8
-rw-r--r--packages/SystemUI/TEST_MAPPING6
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java3
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.pngbin139 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable/tv_circle_dark.xml (renamed from packages/SystemUI/res/drawable/tv_bg_item_app_info.xml)10
-rw-r--r--packages/SystemUI/res/drawable/tv_circle_white_translucent.xml (renamed from packages/SystemUI/res/drawable/circle_red.xml)7
-rw-r--r--packages/SystemUI/res/drawable/tv_ic_mic_white.xml46
-rw-r--r--packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml26
-rw-r--r--packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml26
-rw-r--r--packages/SystemUI/res/drawable/tv_ring_white.xml (renamed from packages/SystemUI/res/drawable/tv_gradient_protection.xml)13
-rw-r--r--packages/SystemUI/res/layout/bubble_overflow_activity.xml20
-rw-r--r--packages/SystemUI/res/layout/tv_audio_recording_indicator.xml121
-rw-r--r--packages/SystemUI/res/layout/tv_item_app_info.xml41
-rw-r--r--packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml63
-rw-r--r--packages/SystemUI/res/values/attrs.xml7
-rw-r--r--packages/SystemUI/res/values/colors_tv.xml10
-rw-r--r--packages/SystemUI/res/values/strings_tv.xml4
-rw-r--r--packages/SystemUI/res/values/styles.xml1
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/SysuiLog.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java376
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/Events.java436
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java73
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java215
-rw-r--r--packages/Tethering/Android.bp1
-rw-r--r--packages/Tethering/apex/manifest.json2
-rw-r--r--services/Android.bp27
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java430
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java163
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java6
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java48
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java96
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java150
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java6
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java131
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java45
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java82
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java78
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java27
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java17
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java24
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java2
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java31
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java51
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java56
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java1
-rw-r--r--services/core/java/com/android/server/connectivity/DataConnectionStats.java38
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java7
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java48
-rw-r--r--services/core/java/com/android/server/display/HysteresisLevels.java9
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java7
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerService.java (renamed from apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java)35
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java80
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java117
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java23
-rw-r--r--services/core/java/com/android/server/location/GnssVisibilityControl.java2
-rw-r--r--services/core/java/com/android/server/location/LocationSettingsStore.java29
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java67
-rw-r--r--services/core/java/com/android/server/notification/NotificationUsageStats.java54
-rw-r--r--services/core/java/com/android/server/notification/PulledStats.java129
-rw-r--r--services/core/java/com/android/server/package-info.java (renamed from core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java)13
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java86
-rw-r--r--services/core/java/com/android/server/pm/ComponentResolver.java930
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java144
-rw-r--r--services/core/java/com/android/server/pm/InstructionSets.java36
-rw-r--r--services/core/java/com/android/server/pm/IntentFilterVerificationState.java8
-rw-r--r--services/core/java/com/android/server/pm/KeySetManagerService.java74
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java8
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java50
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelper.java35
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelperImpl.java57
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java138
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageKeySetData.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java3721
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java72
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java43
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java13
-rw-r--r--services/core/java/com/android/server/pm/PackageUsage.java29
-rw-r--r--services/core/java/com/android/server/pm/ParallelPackageParser.java17
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java27
-rw-r--r--services/core/java/com/android/server/pm/Settings.java398
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java24
-rw-r--r--services/core/java/com/android/server/pm/UserSystemPackageInstaller.java19
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java59
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java2
-rw-r--r--services/core/java/com/android/server/pm/dex/DexoptUtils.java38
-rw-r--r--services/core/java/com/android/server/pm/dex/ViewCompiler.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java173
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java638
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java26
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionSettings.java6
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java24
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java17
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java67
-rw-r--r--services/core/java/com/android/server/role/FinancialSmsManager.java218
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java11
-rw-r--r--services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java190
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java36
-rw-r--r--services/core/java/com/android/server/storage/StorageUserConnection.java113
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java219
-rw-r--r--services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java491
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java14
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityDisplay.java22
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java333
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java511
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java165
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java27
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java2
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java21
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java112
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java11
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java571
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java4
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java2
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java2
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java9
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java17
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java4
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java145
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java84
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java119
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java24
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/net/java/android/net/NetworkMonitorManager.java2
-rw-r--r--services/net/java/android/net/ip/IpClientManager.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java52
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java192
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/display/TestUtils.java60
-rw-r--r--services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java58
-rw-r--r--services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java72
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java218
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java94
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java176
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java575
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java49
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java141
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java129
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt132
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt78
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt361
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java529
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java66
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java113
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java41
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java17
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsDatabase.java17
-rw-r--r--telephony/java/android/telephony/Annotation.java2
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java155
-rw-r--r--telephony/java/android/telephony/CbGeoUtils.java7
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java167
-rw-r--r--telephony/java/android/telephony/DataFailCause.java9
-rw-r--r--telephony/java/android/telephony/LocationAccessPolicy.java4
-rw-r--r--telephony/java/android/telephony/NetworkScanRequest.java12
-rw-r--r--telephony/java/android/telephony/PhoneNumberRange.java16
-rw-r--r--telephony/java/android/telephony/SignalThresholdInfo.java256
-rw-r--r--telephony/java/android/telephony/SubscriptionInfo.java20
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java2
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java205
-rw-r--r--telephony/java/android/telephony/data/DataProfile.java4
-rw-r--r--telephony/java/android/telephony/ims/ImsCallSession.java14
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java3
-rw-r--r--telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/IccCardConstants.java34
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java4
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java3
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java19
-rw-r--r--telephony/java/com/android/internal/telephony/util/HandlerExecutor.java47
-rw-r--r--test-mock/Android.bp1
-rw-r--r--tests/ApkVerityTest/Android.bp2
-rw-r--r--tests/ApkVerityTest/AndroidTest.xml2
-rw-r--r--tests/ApkVerityTest/TEST_MAPPING15
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java5
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java50
-rw-r--r--tools/aapt2/java/ProguardRules.cpp20
-rw-r--r--tools/aapt2/java/ProguardRules_test.cpp19
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp1
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl3
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java29
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java29
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java3
-rw-r--r--wifi/java/android/net/wifi/aware/ConfigRequest.java74
-rw-r--r--wifi/java/com/android/server/wifi/BaseWifiService.java18
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java12
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java18
510 files changed, 30300 insertions, 12440 deletions
diff --git a/Android.bp b/Android.bp
index 8daee86c6ac2..04b4e6edf2ec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -205,10 +205,23 @@ filegroup {
"wifi/java/**/*.java",
"wifi/java/**/*.aidl",
],
+ exclude_srcs: [
+ ":framework-wifi-non-updatable-sources"
+ ],
path: "wifi/java",
}
filegroup {
+ name: "framework-wifi-non-updatable-sources",
+ srcs: [
+ // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
+ // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
+ // to a separate package.
+ "wifi/java/android/net/wifi/WifiNetworkScoreCache.java"
+ ],
+}
+
+filegroup {
name: "framework-non-updatable-sources",
srcs: [
// Java/AIDL sources under frameworks/base
@@ -233,6 +246,7 @@ filegroup {
":framework-telephony-common-sources",
":framework-telephony-sources",
":framework-wifi-sources",
+ ":framework-wifi-non-updatable-sources",
":PacProcessor-aidl-sources",
":ProxyHandler-aidl-sources",
@@ -374,12 +388,14 @@ java_defaults {
exclude_srcs: [
// See comment on framework-atb-backward-compatibility module below
- "core/java/android/content/pm/AndroidTestBaseUpdater.java",
+ "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
],
sdk_version: "core_platform",
libs: [
+ "app-compat-annotations",
"ext",
+ "unsupportedappusage",
"updatable_media_stubs",
],
@@ -427,7 +443,6 @@ java_library {
name: "framework-minus-apex",
defaults: ["framework-defaults"],
srcs: [":framework-non-updatable-sources"],
- libs: ["app-compat-annotations"],
installable: true,
javac_shard_size: 150,
required: [
@@ -445,6 +460,7 @@ java_library {
],
// For backwards compatibility.
stem: "framework",
+ apex_available: ["//apex_available:platform"],
}
// This "framework" module is NOT installed to the device. It's
@@ -465,6 +481,7 @@ java_library {
// TODO(jiyong): add stubs for APEXes here
],
sdk_version: "core_platform",
+ apex_available: ["//apex_available:platform"],
}
java_library {
@@ -472,15 +489,18 @@ java_library {
defaults: ["framework-defaults"],
srcs: [":framework-all-sources"],
installable: false,
- libs: ["app-compat-annotations"],
- static_libs: ["exoplayer2-core"]
+ static_libs: ["exoplayer2-core"],
+ apex_available: ["//apex_available:platform"],
}
java_library {
name: "framework-annotation-proc",
defaults: ["framework-aidl-export-defaults"],
srcs: [":framework-all-sources"],
- libs: ["app-compat-annotations"],
+ libs: [
+ "app-compat-annotations",
+ "unsupportedappusage",
+ ],
installable: false,
plugins: [
"unsupportedappusage-annotation-processor",
@@ -526,7 +546,7 @@ java_library {
installable: true,
libs: ["app-compat-annotations"],
srcs: [
- "core/java/android/content/pm/AndroidTestBaseUpdater.java",
+ "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
],
}
@@ -571,6 +591,7 @@ filegroup {
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/IntRange.java",
+ "core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/UnsupportedAppUsage.java",
"core/java/com/android/internal/annotations/GuardedBy.java",
"core/java/com/android/internal/annotations/VisibleForTesting.java",
@@ -1683,7 +1704,8 @@ filegroup {
name: "framework-wifi-service-shared-srcs",
srcs: [
":framework-annotations",
- "core/java/android/os/HandlerExecutor.java",
+ "core/java/android/net/InterfaceConfiguration.java",
+ "core/java/android/os/HandlerExecutor.java",
"core/java/android/util/BackupUtils.java",
"core/java/android/util/LocalLog.java",
"core/java/android/util/Rational.java",
diff --git a/TEST_MAPPING b/TEST_MAPPING
index b1c4cad72dc9..2b12da291acb 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -23,6 +23,34 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
}
],
"postsubmit-managedprofile-stress": [
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 525fbaedc140..435384dd2319 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -372,9 +372,10 @@ class JobConcurrencyManager {
continue;
}
- // TODO lastEvaluatedPriority should be evaluateJobPriorityLocked. (double check it)
- if (minPriorityForPreemption > nextPending.lastEvaluatedPriority) {
- minPriorityForPreemption = nextPending.lastEvaluatedPriority;
+ if (minPriorityForPreemption > jobPriority) {
+ // Step down the preemption threshold - wind up replacing
+ // the lowest-priority running job
+ minPriorityForPreemption = jobPriority;
selectedContextId = j;
// In this case, we're just going to preempt a low priority job, we're not
// actually starting a job, so don't set startingJob.
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
index 40f3c45518bb..aaf25b1d40bb 100644
--- a/apex/sdkext/Android.bp
+++ b/apex/sdkext/Android.bp
@@ -19,7 +19,6 @@ apex {
java_libs: [ "framework-sdkext" ],
prebuilts: [
"com.android.sdkext.ldconfig",
- "cur_sdkinfo",
"derive_sdk.rc",
],
key: "com.android.sdkext.key",
@@ -43,28 +42,3 @@ prebuilt_etc {
filename: "ld.config.txt",
installable: false,
}
-
-python_binary_host {
- name: "gen_sdkinfo",
- srcs: [
- "derive_sdk/sdk.proto",
- "gen_sdkinfo.py",
- ],
- proto: {
- canonical_path_from_root: false,
- },
-}
-
-gensrcs {
- name: "cur_sdkinfo_src",
- srcs: [""],
- tools: [ "gen_sdkinfo" ],
- cmd: "$(location) -v 0 -o $(out)",
-}
-
-prebuilt_etc {
- name: "cur_sdkinfo",
- src: ":cur_sdkinfo_src",
- filename: "sdkinfo.binarypb",
- installable: false,
-}
diff --git a/apex/sdkext/TEST_MAPPING b/apex/sdkext/TEST_MAPPING
index 8dc732d36c79..91947f39980a 100644
--- a/apex/sdkext/TEST_MAPPING
+++ b/apex/sdkext/TEST_MAPPING
@@ -1,7 +1,7 @@
{
"presubmit": [
{
- "name": "framework-sdkext-tests"
+ "name": "CtsSdkExtTestCases"
}
]
}
diff --git a/apex/sdkext/derive_sdk/derive_sdk.cpp b/apex/sdkext/derive_sdk/derive_sdk.cpp
index 0aacebefaaca..7536def60767 100644
--- a/apex/sdkext/derive_sdk/derive_sdk.cpp
+++ b/apex/sdkext/derive_sdk/derive_sdk.cpp
@@ -68,7 +68,7 @@ int main(int, char**) {
auto itr = std::min_element(versions.begin(), versions.end());
std::string prop_value = itr == versions.end() ? "0" : std::to_string(*itr);
- if (!android::base::SetProperty("persist.com.android.sdkext.sdk_info", prop_value)) {
+ if (!android::base::SetProperty("ro.build.version.extensions.r", prop_value)) {
LOG(ERROR) << "failed to set sdk_info prop";
return EXIT_FAILURE;
}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
index c039a820fc04..d3b9397d45f2 100644
--- a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
+++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
@@ -17,25 +17,40 @@
package android.os.ext;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.os.Build.VERSION_CODES;
import android.os.SystemProperties;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-/** @hide */
+/**
+ * Methods for interacting with the extension SDK.
+ *
+ * This class provides information about the extension SDK version present
+ * on this device. Use the {@link #getExtensionVersion(int) getExtension} to
+ * query for the extension version for the given SDK version.
+
+ * @hide
+ */
+@SystemApi
public class SdkExtensions {
private static final int R_EXTENSION_INT;
static {
- R_EXTENSION_INT = SystemProperties.getInt("persist.com.android.sdkext.sdk_info", 0);
+ R_EXTENSION_INT = SystemProperties.getInt("ro.build.version.extensions.r", 0);
}
- /** Values suitable as parameters for {@link #getExtensionVersion(int)}. */
+ /**
+ * Values suitable as parameters for {@link #getExtensionVersion(int)}.
+ * @hide
+ */
@IntDef(value = { VERSION_CODES.R })
@Retention(RetentionPolicy.SOURCE)
public @interface SdkVersion {}
+ private SdkExtensions() { }
+
/**
* Return the version of the extension to the given SDK.
*
diff --git a/apex/sdkext/framework/tests/Android.bp b/apex/sdkext/framework/tests/Android.bp
deleted file mode 100644
index ab6327582efd..000000000000
--- a/apex/sdkext/framework/tests/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-android_test {
- name: "framework-sdkext-tests",
- srcs: ["src/**/*.java"],
- libs: [
- "android.test.base",
- "android.test.runner",
- ],
- static_libs: [ "framework-sdkext" ],
- test_suites: [ "general-tests" ],
- platform_apis: true,
-}
diff --git a/apex/sdkext/framework/tests/AndroidManifest.xml b/apex/sdkext/framework/tests/AndroidManifest.xml
deleted file mode 100644
index 831f1328c006..000000000000
--- a/apex/sdkext/framework/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.sdkext.tests">
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.sdkext.tests" />
-
-</manifest>
diff --git a/apex/sdkext/gen_sdkinfo.py b/apex/sdkext/gen_sdkinfo.py
deleted file mode 100644
index 5af478ba7fe6..000000000000
--- a/apex/sdkext/gen_sdkinfo.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import sdk_pb2
-import sys
-
-if __name__ == '__main__':
- argv = sys.argv[1:]
- if not len(argv) == 4 or sorted([argv[0], argv[2]]) != ['-o', '-v']:
- print('usage: gen_sdkinfo -v <version> -o <output-file>')
- sys.exit(1)
-
- for i in range(len(argv)):
- if sys.argv[i] == '-o':
- filename = sys.argv[i+1]
- if sys.argv[i] == '-v':
- version = int(sys.argv[i+1])
-
- proto = sdk_pb2.SdkVersion()
- proto.version = version
- with open(filename, 'wb') as f:
- f.write(proto.SerializeToString())
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index d76a40e9e26d..8327f31e4645 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -14,20 +14,19 @@
apex {
name: "com.android.os.statsd",
-
+ defaults: ["com.android.os.statsd-defaults"],
manifest: "apex_manifest.json",
- // optional. if unspecified, a default one is auto-generated
- //androidManifest: "AndroidManifest.xml",
+}
+
+apex_defaults {
// libc.so and libcutils.so are included in the apex
// native_shared_libs: ["libc", "libcutils"],
// binaries: ["vold"],
// java_libs: ["core-all"],
// prebuilts: ["my_prebuilt"],
-
- compile_multilib: "both",
-
+ name: "com.android.os.statsd-defaults",
key: "com.android.os.statsd.key",
certificate: ":com.android.os.statsd.certificate",
}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index c9139b15f223..6fb3bc47859d 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -41,6 +41,7 @@ import android.app.AppOpsManager.HistoricalOps;
import android.app.AppOpsManager.HistoricalOpsRequest;
import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManager.HistoricalUidOps;
+import android.app.INotificationManager;
import android.app.ProcessMemoryState;
import android.app.StatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -139,6 +140,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.notification.NotificationManagerService;
import com.android.server.role.RoleManagerInternal;
import com.android.server.stats.IonMemoryUtil.IonAllocations;
import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
@@ -1750,14 +1752,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (statsFiles.size() != 1) {
return;
}
- InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(
- statsFiles.get(0));
- int[] len = new int[1];
- byte[] stats = readFully(stream, len);
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
- wallClockNanos);
- e.writeStorage(Arrays.copyOf(stats, len[0]));
- pulledData.add(e);
+ unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles);
new File(mBaseDir.getAbsolutePath() + "/" + section + "_"
+ lastHighWaterMark).delete();
new File(
@@ -1773,6 +1768,52 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
+ private INotificationManager mNotificationManager =
+ INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+
+ private void pullNotificationStats(int reportId, int tagId, long elapsedNanos,
+ long wallClockNanos,
+ List<StatsLogEventWrapper> pulledData) {
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // determine last pull tine. Copy file trick from pullProcessStats?
+ long lastNotificationStatsNs = wallClockNanos -
+ TimeUnit.NANOSECONDS.convert(1, TimeUnit.DAYS);
+
+ List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
+ long notificationStatsNs = mNotificationManager.pullStats(
+ lastNotificationStatsNs, reportId, true, statsFiles);
+ if (statsFiles.size() != 1) {
+ return;
+ }
+ unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles);
+ } catch (IOException e) {
+ Log.e(TAG, "Getting notistats failed: ", e);
+
+ } catch (RemoteException e) {
+ Log.e(TAG, "Getting notistats failed: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Getting notistats failed: ", e);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+
+ }
+
+ static void unpackStreamedData(int tagId, long elapsedNanos, long wallClockNanos,
+ List<StatsLogEventWrapper> pulledData, List<ParcelFileDescriptor> statsFiles)
+ throws IOException {
+ InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(
+ statsFiles.get(0));
+ int[] len = new int[1];
+ byte[] stats = readFully(stream, len);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+ wallClockNanos);
+ e.writeStorage(Arrays.copyOf(stats, len[0]));
+ pulledData.add(e);
+ }
+
static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
int pos = 0;
final int initialAvail = stream.available();
@@ -2621,6 +2662,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullAppOps(elapsedNanos, wallClockNanos, ret);
break;
}
+ case StatsLog.NOTIFICATION_REMOTE_VIEWS: {
+ pullNotificationStats(NotificationManagerService.REPORT_REMOTE_VIEWS,
+ tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
diff --git a/apex/statsd/testing/Android.bp b/apex/statsd/testing/Android.bp
new file mode 100644
index 000000000000..22e73015ba39
--- /dev/null
+++ b/apex/statsd/testing/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex {
+ name: "test_com.android.os.statsd",
+ visibility: [
+ "//system/apex/tests",
+ ],
+ defaults: ["com.android.os.statsd-defaults"],
+ manifest: "test_manifest.json",
+ file_contexts: ":com.android.os.statsd-file_contexts",
+ // Test APEX, should never be installed
+ installable: false,
+}
diff --git a/apex/statsd/testing/test_manifest.json b/apex/statsd/testing/test_manifest.json
new file mode 100644
index 000000000000..57343d3e6ae5
--- /dev/null
+++ b/apex/statsd/testing/test_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.os.statsd",
+ "version": 2147483647
+}
diff --git a/api/current.txt b/api/current.txt
index d05ef8cea53a..00f06ec3545d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25367,6 +25367,8 @@ package android.media {
field public static final String KEY_COMPLEXITY = "complexity";
field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
field public static final String KEY_DURATION = "durationUs";
+ field public static final String KEY_ENCODER_DELAY = "encoder-delay";
+ field public static final String KEY_ENCODER_PADDING = "encoder-padding";
field public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
field public static final String KEY_FRAME_RATE = "frame-rate";
field public static final String KEY_GRID_COLUMNS = "grid-cols";
@@ -25395,6 +25397,8 @@ package android.media {
field public static final String KEY_OPERATING_RATE = "operating-rate";
field public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
field public static final String KEY_PCM_ENCODING = "pcm-encoding";
+ field public static final String KEY_PIXEL_ASPECT_RATIO_HEIGHT = "sar-height";
+ field public static final String KEY_PIXEL_ASPECT_RATIO_WIDTH = "sar-width";
field public static final String KEY_PREPEND_HEADER_TO_SYNC_FRAMES = "prepend-sps-pps-to-idr-frames";
field public static final String KEY_PRIORITY = "priority";
field public static final String KEY_PROFILE = "profile";
@@ -25644,7 +25648,7 @@ package android.media {
method public void onTracksFound(int);
}
- public static interface MediaParser.SeekMap {
+ public static final class MediaParser.SeekMap {
method public long getDurationUs();
method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long);
method public boolean isSeekable();
@@ -29209,6 +29213,7 @@ package android.net {
public class NetworkRequest implements android.os.Parcelable {
method public int describeContents();
+ method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -38342,6 +38347,8 @@ package android.provider {
public static final class ContactsContract.RawContacts implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.SyncColumns {
method public static android.net.Uri getContactLookupUri(android.content.ContentResolver, android.net.Uri);
+ method @Nullable public static String getLocalAccountName(@NonNull android.content.Context);
+ method @Nullable public static String getLocalAccountType(@NonNull android.content.Context);
method public static android.content.EntityIterator newEntityIterator(android.database.Cursor);
field public static final int AGGREGATION_MODE_DEFAULT = 0; // 0x0
field public static final int AGGREGATION_MODE_DISABLED = 3; // 0x3
@@ -42828,6 +42835,7 @@ package android.system {
method public static String[] listxattr(String) throws android.system.ErrnoException;
method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
method public static android.system.StructStat lstat(String) throws android.system.ErrnoException;
+ method @NonNull public static java.io.FileDescriptor memfd_create(@NonNull String, int) throws android.system.ErrnoException;
method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
method public static void mkdir(String, int) throws android.system.ErrnoException;
method public static void mkfifo(String, int) throws android.system.ErrnoException;
@@ -43136,6 +43144,7 @@ package android.system {
field public static final int MCAST_UNBLOCK_SOURCE;
field public static final int MCL_CURRENT;
field public static final int MCL_FUTURE;
+ field public static final int MFD_CLOEXEC;
field public static final int MSG_CTRUNC;
field public static final int MSG_DONTROUTE;
field public static final int MSG_EOR;
@@ -44707,7 +44716,6 @@ package android.telephony {
field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int";
field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
- field public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT = "parameters_use_for_5g_nr_signal_bar_int";
field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool";
field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
@@ -46533,12 +46541,12 @@ package android.telephony.mbms {
package android.text {
- public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars {
- method public char charAt(int);
- method public void getChars(int, int, char[], int);
- method public int length();
- method public static android.text.AlteredCharSequence make(CharSequence, char[], int, int);
- method public CharSequence subSequence(int, int);
+ @Deprecated public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars {
+ method @Deprecated public char charAt(int);
+ method @Deprecated public void getChars(int, int, char[], int);
+ method @Deprecated public int length();
+ method @Deprecated public static android.text.AlteredCharSequence make(CharSequence, char[], int, int);
+ method @Deprecated public CharSequence subSequence(int, int);
}
@Deprecated public class AndroidCharacter {
diff --git a/api/system-current.txt b/api/system-current.txt
index 217943c519af..472f1ecbf0b4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1686,9 +1686,25 @@ package android.content {
field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
+ field @Deprecated public static final String EXTRA_SIM_LOCKED_REASON = "reason";
+ field @Deprecated public static final String EXTRA_SIM_STATE = "ss";
field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
field public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
+ field @Deprecated public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
+ field @Deprecated public static final String SIM_LOCKED_NETWORK = "NETWORK";
+ field @Deprecated public static final String SIM_LOCKED_ON_PIN = "PIN";
+ field @Deprecated public static final String SIM_LOCKED_ON_PUK = "PUK";
+ field @Deprecated public static final String SIM_STATE_ABSENT = "ABSENT";
+ field @Deprecated public static final String SIM_STATE_CARD_IO_ERROR = "CARD_IO_ERROR";
+ field @Deprecated public static final String SIM_STATE_CARD_RESTRICTED = "CARD_RESTRICTED";
+ field @Deprecated public static final String SIM_STATE_IMSI = "IMSI";
+ field @Deprecated public static final String SIM_STATE_LOADED = "LOADED";
+ field @Deprecated public static final String SIM_STATE_LOCKED = "LOCKED";
+ field @Deprecated public static final String SIM_STATE_NOT_READY = "NOT_READY";
+ field @Deprecated public static final String SIM_STATE_PRESENT = "PRESENT";
+ field @Deprecated public static final String SIM_STATE_READY = "READY";
+ field @Deprecated public static final String SIM_STATE_UNKNOWN = "UNKNOWN";
}
public class IntentFilter implements android.os.Parcelable {
@@ -1730,7 +1746,7 @@ package android.content.integrity {
}
public abstract class AtomicFormula implements android.content.integrity.Formula {
- ctor public AtomicFormula(@android.content.integrity.AtomicFormula.Key int);
+ ctor public AtomicFormula(int);
method public int getKey();
field public static final int APP_CERTIFICATE = 1; // 0x1
field public static final int EQ = 0; // 0x0
@@ -1746,7 +1762,7 @@ package android.content.integrity {
}
public static final class AtomicFormula.BooleanAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
- ctor public AtomicFormula.BooleanAtomicFormula(@android.content.integrity.AtomicFormula.Key int, boolean);
+ ctor public AtomicFormula.BooleanAtomicFormula(int, boolean);
method public int describeContents();
method public int getTag();
method public boolean getValue();
@@ -1756,7 +1772,7 @@ package android.content.integrity {
}
public static final class AtomicFormula.IntAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
- ctor public AtomicFormula.IntAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @android.content.integrity.AtomicFormula.Operator int, int);
+ ctor public AtomicFormula.IntAtomicFormula(int, int, int);
method public int describeContents();
method public int getOperator();
method public int getTag();
@@ -1766,14 +1782,8 @@ package android.content.integrity {
field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.IntAtomicFormula> CREATOR;
}
- @IntDef({android.content.integrity.AtomicFormula.PACKAGE_NAME, android.content.integrity.AtomicFormula.APP_CERTIFICATE, android.content.integrity.AtomicFormula.INSTALLER_NAME, android.content.integrity.AtomicFormula.INSTALLER_CERTIFICATE, android.content.integrity.AtomicFormula.VERSION_CODE, android.content.integrity.AtomicFormula.PRE_INSTALLED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Key {
- }
-
- @IntDef({android.content.integrity.AtomicFormula.EQ, android.content.integrity.AtomicFormula.LT, android.content.integrity.AtomicFormula.LE, android.content.integrity.AtomicFormula.GT, android.content.integrity.AtomicFormula.GE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Operator {
- }
-
public static final class AtomicFormula.StringAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
- ctor public AtomicFormula.StringAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @NonNull String, boolean);
+ ctor public AtomicFormula.StringAtomicFormula(int, @NonNull String, boolean);
method public int describeContents();
method public boolean getIsHashedValue();
method public int getTag();
@@ -1784,9 +1794,9 @@ package android.content.integrity {
}
public final class CompoundFormula implements android.content.integrity.Formula android.os.Parcelable {
- ctor public CompoundFormula(@android.content.integrity.CompoundFormula.Connector int, @NonNull java.util.List<android.content.integrity.Formula>);
+ ctor public CompoundFormula(int, @NonNull java.util.List<android.content.integrity.Formula>);
method public int describeContents();
- method @android.content.integrity.CompoundFormula.Connector public int getConnector();
+ method public int getConnector();
method @NonNull public java.util.List<android.content.integrity.Formula> getFormulas();
method public int getTag();
method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
@@ -1797,11 +1807,8 @@ package android.content.integrity {
field public static final int OR = 1; // 0x1
}
- @IntDef({android.content.integrity.CompoundFormula.AND, android.content.integrity.CompoundFormula.OR, android.content.integrity.CompoundFormula.NOT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CompoundFormula.Connector {
- }
-
public interface Formula {
- method @android.content.integrity.Formula.Tag public int getTag();
+ method public int getTag();
method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
method @NonNull public static android.content.integrity.Formula readFromParcel(@NonNull android.os.Parcel);
method public static void writeToParcel(@NonNull android.content.integrity.Formula, @NonNull android.os.Parcel, int);
@@ -1811,13 +1818,10 @@ package android.content.integrity {
field public static final int STRING_ATOMIC_FORMULA_TAG = 1; // 0x1
}
- @IntDef({android.content.integrity.Formula.COMPOUND_FORMULA_TAG, android.content.integrity.Formula.STRING_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.INT_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.BOOLEAN_ATOMIC_FORMULA_TAG}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Formula.Tag {
- }
-
public final class Rule implements android.os.Parcelable {
- ctor public Rule(@NonNull android.content.integrity.Formula, @android.content.integrity.Rule.Effect int);
+ ctor public Rule(@NonNull android.content.integrity.Formula, int);
method public int describeContents();
- method @android.content.integrity.Rule.Effect public int getEffect();
+ method public int getEffect();
method @NonNull public android.content.integrity.Formula getFormula();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR;
@@ -1825,9 +1829,6 @@ package android.content.integrity {
field public static final int FORCE_ALLOW = 1; // 0x1
}
- @IntDef({android.content.integrity.Rule.DENY, android.content.integrity.Rule.FORCE_ALLOW}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Rule.Effect {
- }
-
public class RuleSet {
method @NonNull public java.util.List<android.content.integrity.Rule> getRules();
method @NonNull public String getVersion();
@@ -3928,16 +3929,19 @@ package android.media {
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAddress getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method public boolean isAudioServerRunning();
method public boolean isHdmiSystemAudioSupported();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAddress);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
@@ -4108,9 +4112,11 @@ package android.media.audiopolicy {
}
public final class AudioProductStrategy implements android.os.Parcelable {
+ method @NonNull public static android.media.audiopolicy.AudioProductStrategy createInvalidAudioProductStrategy(int);
method public int describeContents();
method @NonNull public android.media.AudioAttributes getAudioAttributes();
method public int getId();
+ method public boolean supportsAudioAttributes(@NonNull android.media.AudioAttributes);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategy> CREATOR;
}
@@ -4826,6 +4832,9 @@ package android.net.ipsec.ike {
}
public abstract class ChildSessionParams {
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors();
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors();
+ method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals();
}
public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
@@ -4893,6 +4902,13 @@ package android.net.ipsec.ike {
}
public final class IkeSessionParams {
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig();
+ method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification();
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig();
+ method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification();
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals();
+ method @NonNull public java.net.InetAddress getServerAddress();
+ method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket();
}
public static final class IkeSessionParams.Builder {
@@ -4909,6 +4925,27 @@ package android.net.ipsec.ike {
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
}
+ public abstract static class IkeSessionParams.IkeAuthConfig {
+ }
+
+ public static class IkeSessionParams.IkeAuthDigitalSignLocalConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public java.security.cert.X509Certificate getClientEndCertificate();
+ method @NonNull public java.util.List<java.security.cert.X509Certificate> getIntermediateCertificates();
+ method @NonNull public java.security.PrivateKey getPrivateKey();
+ }
+
+ public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public java.security.cert.X509Certificate getRemoteCaCert();
+ }
+
+ public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public android.net.eap.EapSessionConfig getEapConfig();
+ }
+
+ public static class IkeSessionParams.IkeAuthPskConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public byte[] getPsk();
+ }
+
public final class IkeTrafficSelector {
ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
field public final int endPort;
@@ -4955,6 +4992,7 @@ package android.net.ipsec.ike {
}
public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
+ method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest> getConfigurationRequests();
}
public static final class TunnelModeChildSessionParams.Builder {
@@ -4972,6 +5010,39 @@ package android.net.ipsec.ike {
method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
}
+ public static interface TunnelModeChildSessionParams.ConfigRequest {
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet4Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet4Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet4Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet6Address getAddress();
+ method public int getPrefixLength();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet6Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ }
+
}
package android.net.ipsec.ike.exceptions {
@@ -6731,6 +6802,14 @@ package android.os.connectivity {
}
+package android.os.ext {
+
+ public class SdkExtensions {
+ method public static int getExtensionVersion(int);
+ }
+
+}
+
package android.os.image {
public class DynamicSystemClient {
@@ -8016,16 +8095,6 @@ package android.service.settings.suggestions {
}
-package android.service.sms {
-
- public abstract class FinancialSmsService extends android.app.Service {
- method public android.os.IBinder onBind(android.content.Intent);
- method @Nullable public abstract android.database.CursorWindow onGetSmsMessages(@NonNull android.os.Bundle);
- field public static final String ACTION_FINANCIAL_SERVICE_INTENT = "android.service.sms.action.FINANCIAL_SERVICE_INTENT";
- }
-
-}
-
package android.service.storage {
public abstract class ExternalStorageService extends android.app.Service {
@@ -8489,14 +8558,6 @@ package android.telephony {
field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
}
- public static final class CarrierConfigManager.Wifi {
- field public static final String KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING = "wifi.carrier_connection_manager_package_string";
- field public static final String KEY_CARRIER_PROFILES_VERSION_INT = "wifi.carrier_profiles_version_int";
- field public static final String KEY_NETWORK_PROFILES_STRING_ARRAY = "wifi.network_profiles_string_array";
- field public static final String KEY_PASSPOINT_PROFILES_STRING_ARRAY = "wifi.passpoint_profiles_string_array";
- field public static final String KEY_PREFIX = "wifi.";
- }
-
public final class CarrierRestrictionRules implements android.os.Parcelable {
method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
method public int describeContents();
@@ -8868,6 +8929,7 @@ package android.telephony {
field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889
field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897
field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27
+ field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002
field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b
field public static final int UNKNOWN = 65536; // 0x10000
field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index fcf5178716e1..9a6357572d36 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -196,7 +196,6 @@ ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.
ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
-
SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean):
diff --git a/api/test-current.txt b/api/test-current.txt
index 3e144697ee28..efb85387a743 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1151,6 +1151,7 @@ package android.location {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
+ field public static final String FUSED_PROVIDER = "fused";
}
public final class LocationRequest implements android.os.Parcelable {
@@ -4437,7 +4438,7 @@ package android.view.accessibility {
public final class AccessibilityManager {
method public void addAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, @Nullable android.os.Handler);
- method @Nullable @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public String getAccessibilityShortcutService();
+ method @NonNull @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int);
method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void performAccessibilityShortcut();
method public void removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
}
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index a8c4db38c841..ef8165fc6edb 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -2426,6 +2426,12 @@ ProtectedMember: android.view.View#resetResolvedDrawables():
ProtectedMember: android.view.ViewGroup#resetResolvedDrawables():
+PublicTypedef: android.os.HwParcel.Status: Don't expose @IntDef: @Status must be hidden.
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability: Don't expose @IntDef: @MmTelCapability must be hidden.
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult: Don't expose @IntDef: @ProcessCallResult must be hidden.
+
RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 17427a20b90e..484f82330055 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -250,6 +250,7 @@ cc_test {
"tests/external/GpuStatsPuller_test.cpp",
"tests/external/IncidentReportArgs_test.cpp",
"tests/external/puller_util_test.cpp",
+ "tests/external/StatsCallbackPuller_test.cpp",
"tests/external/StatsPuller_test.cpp",
"tests/external/SurfaceflingerStatsPuller_test.cpp",
"tests/FieldValue_test.cpp",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index a1fedd711a85..a20436d4bdda 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -113,8 +113,8 @@ message Atom {
WakeupAlarmOccurred wakeup_alarm_occurred = 35;
KernelWakeupReported kernel_wakeup_reported = 36;
WifiLockStateChanged wifi_lock_state_changed = 37 [(log_from_module) = "wifi"];
- WifiSignalStrengthChanged wifi_signal_strength_changed = 38;
- WifiScanStateChanged wifi_scan_state_changed = 39;
+ WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(log_from_module) = "wifi"];
+ WifiScanStateChanged wifi_scan_state_changed = 39 [(log_from_module) = "wifi"];
PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
SettingChanged setting_changed = 41;
ActivityForegroundStateChanged activity_foreground_state_changed = 42;
@@ -128,7 +128,7 @@ message Atom {
AppStartFullyDrawn app_start_fully_drawn = 50;
LmkKillOccurred lmk_kill_occurred = 51;
PictureInPictureStateChanged picture_in_picture_state_changed = 52;
- WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53;
+ WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53 [(log_from_module) = "wifi"];
LmkStateChanged lmk_state_changed = 54;
AppStartMemoryStateCaptured app_start_memory_state_captured = 55;
ShutdownSequenceReported shutdown_sequence_reported = 56;
@@ -356,7 +356,7 @@ message Atom {
}
// Pulled events will start at field 10000.
- // Next: 10065
+ // Next: 10067
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000;
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -423,6 +423,7 @@ message Atom {
SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
ProcessMemorySnapshot process_memory_snapshot = 10064;
VmsClientStats vms_client_stats = 10065;
+ NotificationRemoteViews notification_remote_views = 10066;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -4960,6 +4961,24 @@ message ProcStatsPkgProc {
optional ProcessStatsSectionProto proc_stats_section = 1;
}
+// Next Tag: 2
+message PackageRemoteViewInfoProto {
+ optional string package_name = 1;
+ // add per-package additional info here (like channels)
+}
+
+// Next Tag: 2
+message NotificationRemoteViewsProto {
+ repeated PackageRemoteViewInfoProto package_remote_view_info = 1;
+}
+
+/**
+ * Pulled from NotificationManagerService.java
+ */
+message NotificationRemoteViews {
+ optional NotificationRemoteViewsProto notification_remote_views = 1;
+}
+
message PowerProfileProto {
optional double cpu_suspend = 1;
@@ -7122,7 +7141,7 @@ message TextSelectionEvent {
// Event type of this event.
optional android.stats.textclassifier.EventType event_type = 2;
- // Name of the model that is involved in this event.
+ // Name of the annotator model that is involved in this event.
optional string model_name = 3;
// Type of widget that was involved in triggering this event.
@@ -7162,7 +7181,7 @@ message TextLinkifyEvent {
// Event type of this event.
optional android.stats.textclassifier.EventType event_type = 2;
- // Name of the model that is involved in this event.
+ // Name of the annotator model that is involved in this event.
optional string model_name = 3;
// Type of widget that was involved in triggering this event.
@@ -7202,7 +7221,7 @@ message ConversationActionsEvent {
// Event type of this event.
optional android.stats.textclassifier.EventType event_type = 2;
- // Name of the model that is involved in this event.
+ // Name of the actions model that is involved in this event.
optional string model_name = 3;
// Type of widget that was involved in triggering this event.
@@ -7222,6 +7241,9 @@ message ConversationActionsEvent {
// Name of source package.
optional string package_name = 9;
+
+ // Name of the annotator model that is involved in this event.
+ optional string annotator_model_name = 10;
}
/**
@@ -7236,7 +7258,7 @@ message LanguageDetectionEvent {
// Event type of this event.
optional android.stats.textclassifier.EventType event_type = 2;
- // Name of the model that is involved in this event.
+ // Name of the language detection model that is involved in this event.
optional string model_name = 3;
// Type of widget that was involved in triggering this event.
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
index f5b1e7f78736..0e6b677abb46 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.cpp
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -35,8 +35,9 @@ namespace android {
namespace os {
namespace statsd {
-StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback)
- : StatsPuller(tagId), mCallback(callback) {
+StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback,
+ int64_t timeoutNs)
+ : StatsPuller(tagId), mCallback(callback), mTimeoutNs(timeoutNs) {
VLOG("StatsCallbackPuller created for tag %d", tagId);
}
@@ -64,10 +65,9 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
{
lock_guard<mutex> lk(*cv_mutex);
for (const StatsEventParcel& parcel: output) {
- shared_ptr<LogEvent> event =
- make_shared<LogEvent>(const_cast<uint8_t*>(parcel.buffer.data()),
- parcel.buffer.size(),
- /*uid=*/ -1);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(
+ const_cast<uint8_t*>(parcel.buffer.data()), parcel.buffer.size(),
+ /*uid=*/-1, /*useNewSchema=*/true);
sharedData->push_back(event);
}
*pullSuccess = success;
@@ -76,7 +76,8 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
cv->notify_one();
});
- // Initiate the pull.
+ // Initiate the pull. This is a oneway call to a different process, except
+ // in unit tests. In process calls are not oneway.
Status status = mCallback->onPullAtom(mTagId, resultReceiver);
if (!status.isOk()) {
return false;
@@ -84,10 +85,8 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
{
unique_lock<mutex> unique_lk(*cv_mutex);
- int64_t pullTimeoutNs =
- StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).pullTimeoutNs;
// Wait until the pull finishes, or until the pull timeout.
- cv->wait_for(unique_lk, chrono::nanoseconds(pullTimeoutNs),
+ cv->wait_for(unique_lk, chrono::nanoseconds(mTimeoutNs),
[pullFinish] { return *pullFinish; });
if (!*pullFinish) {
// Note: The parent stats puller will also note that there was a timeout and that the
@@ -96,7 +95,7 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
return true;
} else {
// Only copy the data if we did not timeout and the pull was successful.
- if (pullSuccess) {
+ if (*pullSuccess) {
*data = std::move(*sharedData);
}
VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId);
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h
index ce506c7f9785..d943f9d189c5 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.h
+++ b/cmds/statsd/src/external/StatsCallbackPuller.h
@@ -27,11 +27,17 @@ namespace statsd {
class StatsCallbackPuller : public StatsPuller {
public:
- explicit StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback);
+ explicit StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback,
+ int64_t timeoutNs);
private:
bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
const sp<IPullAtomCallback> mCallback;
+ const int64_t mTimeoutNs;
+
+ FRIEND_TEST(StatsCallbackPullerTest, PullFail);
+ FRIEND_TEST(StatsCallbackPullerTest, PullSuccess);
+ FRIEND_TEST(StatsCallbackPullerTest, PullTimeout);
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index b5bad0530503..9ee627efa841 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -281,6 +281,9 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{{.atomTag = android::util::VMS_CLIENT_STATS},
{.additiveFields = {5, 6, 7, 8, 9, 10},
.puller = new CarStatsPuller(android::util::VMS_CLIENT_STATS)}},
+ // NotiifcationRemoteViews.
+ {{.atomTag = android::util::NOTIFICATION_REMOTE_VIEWS},
+ {.puller = new StatsCompanionServicePuller(android::util::NOTIFICATION_REMOTE_VIEWS)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
@@ -497,10 +500,11 @@ void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t a
VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
// TODO: linkToDeath with the callback so that we can remove it and delete the puller.
StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
- kAllPullAtomInfo[{.atomTag = atomTag}] = {.additiveFields = additiveFields,
- .coolDownNs = coolDownNs,
- .puller = new StatsCallbackPuller(atomTag, callback),
- .pullTimeoutNs = timeoutNs,
+ kAllPullAtomInfo[{.atomTag = atomTag}] = {
+ .additiveFields = additiveFields,
+ .coolDownNs = coolDownNs,
+ .puller = new StatsCallbackPuller(atomTag, callback, timeoutNs),
+ .pullTimeoutNs = timeoutNs,
};
}
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 67022a078b01..36f4623c4dcb 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -52,6 +52,17 @@ LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid)
#endif
}
+LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema)
+ : mBuf(msg), mRemainingLen(len), mLogdTimestampNs(time(nullptr)), mLogUid(uid) {
+ if (useNewSchema) {
+ initNew();
+ } else {
+ mContext = create_android_log_parser((char*)msg, len);
+ init(mContext);
+ if (mContext) android_log_destroy(&mContext); // set mContext to NULL
+ }
+}
+
LogEvent::LogEvent(const LogEvent& event) {
mTagId = event.mTagId;
mLogUid = event.mLogUid;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 1ff95f7240ac..596d623debe5 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -75,6 +75,11 @@ public:
explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid);
/**
+ * Temp constructor to use for pulled atoms until we flip the socket schema.
+ */
+ explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema);
+
+ /**
* Creates LogEvent from StatsLogEventWrapper.
*/
static void createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper,
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index eb78ebc521e1..2c9991125d89 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -159,7 +159,7 @@ ValueMetricProducer::ValueMetricProducer(
// Kicks off the puller immediately if condition is true and diff based.
if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
- pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
}
// Now that activations are processed, start the condition timer if needed.
mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
@@ -183,11 +183,9 @@ void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition
void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
StatsdStats::getInstance().noteBucketDropped(mMetricId);
- // We are going to flush the data without doing a pull first so we need to invalidte the data.
- bool pullNeeded = mIsPulled && mCondition == ConditionState::kTrue;
- if (pullNeeded) {
- invalidateCurrentBucket();
- }
+
+ // The current partial bucket is not flushed and does not require a pull,
+ // so the data is still valid.
flushIfNeededLocked(dropTimeNs);
clearPastBucketsLocked(dropTimeNs);
}
@@ -216,7 +214,7 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
invalidateCurrentBucket();
break;
case NO_TIME_CONSTRAINTS:
- pullAndMatchEventsLocked(dumpTimeNs, mCondition);
+ pullAndMatchEventsLocked(dumpTimeNs);
break;
}
}
@@ -366,7 +364,7 @@ void ValueMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs)
// Pull on active state changes.
if (!isEventTooLate) {
if (mIsPulled) {
- pullAndMatchEventsLocked(eventTimeNs, mCondition);
+ pullAndMatchEventsLocked(eventTimeNs);
}
// When active state changes from true to false, clear diff base but don't
// reset other counters as we may accumulate more value in the bucket.
@@ -425,7 +423,7 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
// called before #onDataPulled.
if (mIsPulled &&
(newCondition == ConditionState::kTrue || mCondition == ConditionState::kTrue)) {
- pullAndMatchEventsLocked(eventTimeNs, newCondition);
+ pullAndMatchEventsLocked(eventTimeNs);
}
// For metrics that use diff, when condition changes from true to false,
@@ -443,8 +441,7 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
}
-void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs,
- ConditionState condition) {
+void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
vector<std::shared_ptr<LogEvent>> allData;
if (!mPullerManager->Pull(mPullTagId, &allData)) {
ALOGE("Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
@@ -452,7 +449,7 @@ void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs,
return;
}
- accumulateEvents(allData, timestampNs, timestampNs, condition);
+ accumulateEvents(allData, timestampNs, timestampNs);
}
int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
@@ -474,7 +471,7 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
if (isEventLate) {
// If the event is late, we are in the middle of a bucket. Just
// process the data without trying to snap the data to the nearest bucket.
- accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition);
+ accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs);
} else {
// For scheduled pulled data, the effective event time is snap to the nearest
// bucket end. In the case of waking up from a deep sleep state, we will
@@ -488,7 +485,7 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
StatsdStats::getInstance().noteBucketBoundaryDelayNs(
mMetricId, originalPullTimeNs - bucketEndTime);
- accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition);
+ accumulateEvents(allData, originalPullTimeNs, bucketEndTime);
}
}
}
@@ -499,8 +496,7 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
}
void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
- int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
- ConditionState condition) {
+ int64_t originalPullTimeNs, int64_t eventElapsedTimeNs) {
bool isEventLate = eventElapsedTimeNs < mCurrentBucketStartTimeNs;
if (isEventLate) {
VLOG("Skip bucket end pull due to late arrival: %lld vs %lld",
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 206e602dd1c7..2033a2a0cd02 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -78,7 +78,7 @@ public:
return;
}
if (mIsPulled && mCondition) {
- pullAndMatchEventsLocked(eventTimeNs, mCondition);
+ pullAndMatchEventsLocked(eventTimeNs);
}
flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
};
@@ -188,11 +188,10 @@ private:
bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey);
- void pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition);
+ void pullAndMatchEventsLocked(const int64_t timestampNs);
void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
- int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
- ConditionState condition);
+ int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
ValueBucket buildPartialBucket(int64_t bucketEndTime,
const std::vector<Interval>& intervals);
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
index 2fa28c9846fd..80d398339ebb 100644
--- a/cmds/statsd/src/state/StateManager.cpp
+++ b/cmds/statsd/src/state/StateManager.cpp
@@ -29,18 +29,15 @@ StateManager& StateManager::getInstance() {
}
void StateManager::onLogEvent(const LogEvent& event) {
- std::lock_guard<std::mutex> lock(mMutex);
if (mStateTrackers.find(event.GetTagId()) != mStateTrackers.end()) {
mStateTrackers[event.GetTagId()]->onLogEvent(event);
}
}
bool StateManager::registerListener(int32_t atomId, wp<StateListener> listener) {
- std::lock_guard<std::mutex> lock(mMutex);
-
- // Check if state tracker already exists
+ // Check if state tracker already exists.
if (mStateTrackers.find(atomId) == mStateTrackers.end()) {
- // Create a new state tracker iff atom is a state atom
+ // Create a new state tracker iff atom is a state atom.
auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(atomId);
if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) {
mStateTrackers[atomId] = new StateTracker(atomId, it->second);
@@ -79,8 +76,6 @@ void StateManager::unregisterListener(int32_t atomId, wp<StateListener> listener
bool StateManager::getStateValue(int32_t atomId, const HashableDimensionKey& key,
FieldValue* output) const {
- std::lock_guard<std::mutex> lock(mMutex);
-
auto it = mStateTrackers.find(atomId);
if (it != mStateTrackers.end()) {
return it->second->getStateValue(key, output);
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
index 272724ceeb08..a6053e6f317e 100644
--- a/cmds/statsd/src/state/StateManager.h
+++ b/cmds/statsd/src/state/StateManager.h
@@ -27,6 +27,10 @@ namespace android {
namespace os {
namespace statsd {
+/**
+ * This class is NOT thread safe.
+ * It should only be used while StatsLogProcessor's lock is held.
+ */
class StateManager : public virtual RefBase {
public:
StateManager(){};
@@ -56,13 +60,10 @@ public:
FieldValue* output) const;
inline int getStateTrackersCount() const {
- std::lock_guard<std::mutex> lock(mMutex);
return mStateTrackers.size();
}
inline int getListenersCount(int32_t atomId) const {
- std::lock_guard<std::mutex> lock(mMutex);
-
auto it = mStateTrackers.find(atomId);
if (it != mStateTrackers.end()) {
return it->second->getListenersCount();
@@ -71,10 +72,10 @@ public:
}
private:
- mutable std::mutex mMutex;
+ mutable std::mutex mMutex;
- // Maps state atom ids to StateTrackers
- std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers;
+ // Maps state atom ids to StateTrackers
+ std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers;
};
} // namespace statsd
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index 90ce1e90142e..ef59c9242cb2 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -139,6 +139,13 @@ void StateTracker::handlePartialReset(const int64_t eventTimeNs,
const HashableDimensionKey& primaryKey) {
VLOG("StateTracker handle partial reset");
if (mStateMap.find(primaryKey) != mStateMap.end()) {
+ for (auto l : mListeners) {
+ auto sl = l.promote();
+ if (sl != nullptr) {
+ sl->onStateChanged(eventTimeNs, mAtomId, primaryKey,
+ mStateMap.find(primaryKey)->second.state, mDefaultState);
+ }
+ }
mStateMap.erase(primaryKey);
}
}
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index 544857f06711..e65325a52b98 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -80,10 +80,12 @@ private:
// Set of all StateListeners (objects listening for state changes)
std::set<wp<StateListener>> mListeners;
- // Reset all state values in map to default state
+ // Reset all state values in map to default state.
void handleReset(const int64_t eventTimeNs);
- // Reset only the state value mapped to primary key to default state
+ // Reset only the state value mapped to the given primary key to default state.
+ // Partial resets are used when we only need to update the state of one primary
+ // key instead of clearing/reseting every key in the map.
void handlePartialReset(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
// Update the StateMap based on the received state value.
diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
new file mode 100644
index 000000000000..2b0590d11f54
--- /dev/null
+++ b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
@@ -0,0 +1,210 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/external/StatsCallbackPuller.h"
+
+#include <android/os/BnPullAtomCallback.h>
+#include <android/os/IPullAtomResultReceiver.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include "../metrics/metrics_test_helper.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace testing;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using std::this_thread::sleep_for;
+using testing::Contains;
+
+namespace {
+int pullTagId = -12;
+bool pullSuccess;
+vector<int64_t> values;
+int64_t pullDelayNs;
+int64_t pullTimeoutNs;
+int64_t pullCoolDownNs;
+std::thread pullThread;
+
+stats_event* createSimpleEvent(int64_t value) {
+ stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, pullTagId);
+ stats_event_write_int64(event, value);
+ stats_event_build(event);
+ return event;
+}
+
+void executePull(const sp<IPullAtomResultReceiver>& resultReceiver) {
+ // Convert stats_events into StatsEventParcels.
+ std::vector<android::util::StatsEventParcel> parcels;
+ for (int i = 0; i < values.size(); i++) {
+ stats_event* event = createSimpleEvent(values[i]);
+ size_t size;
+ uint8_t* buffer = stats_event_get_buffer(event, &size);
+
+ android::util::StatsEventParcel p;
+ // vector.assign() creates a copy, but this is inevitable unless
+ // stats_event.h/c uses a vector as opposed to a buffer.
+ p.buffer.assign(buffer, buffer + size);
+ parcels.push_back(std::move(p));
+ stats_event_release(event);
+ }
+
+ sleep_for(std::chrono::nanoseconds(pullDelayNs));
+ resultReceiver->pullFinished(pullTagId, pullSuccess, parcels);
+}
+
+class FakePullAtomCallback : public BnPullAtomCallback {
+public:
+ binder::Status onPullAtom(int atomTag,
+ const sp<IPullAtomResultReceiver>& resultReceiver) override {
+ // Force pull to happen in separate thread to simulate binder.
+ pullThread = std::thread(executePull, resultReceiver);
+ return binder::Status::ok();
+ }
+};
+
+class StatsCallbackPullerTest : public ::testing::Test {
+public:
+ StatsCallbackPullerTest() {
+ }
+
+ void SetUp() override {
+ pullSuccess = false;
+ pullDelayNs = 0;
+ values.clear();
+ pullTimeoutNs = 10000000000LL; // 10 seconds.
+ pullCoolDownNs = 1000000000; // 1 second.
+ }
+
+ void TearDown() override {
+ if (pullThread.joinable()) {
+ pullThread.join();
+ }
+ values.clear();
+ }
+};
+} // Anonymous namespace.
+
+TEST_F(StatsCallbackPullerTest, PullSuccess) {
+ sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
+ int64_t value = 43;
+ pullSuccess = true;
+ values.push_back(value);
+
+ StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs);
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ int64_t startTimeNs = getElapsedRealtimeNs();
+ EXPECT_TRUE(puller.PullInternal(&dataHolder));
+ int64_t endTimeNs = getElapsedRealtimeNs();
+
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_LT(startTimeNs, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_GT(endTimeNs, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(value, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsCallbackPullerTest, PullFail) {
+ sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
+ pullSuccess = false;
+ int64_t value = 1234;
+ values.push_back(value);
+
+ StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs);
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.PullInternal(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsCallbackPullerTest, PullTimeout) {
+ sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
+ pullSuccess = true;
+ pullDelayNs = 500000000; // 500ms.
+ pullTimeoutNs = 10000; // 10 microseconds.
+ int64_t value = 4321;
+ values.push_back(value);
+
+ StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs);
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ int64_t startTimeNs = getElapsedRealtimeNs();
+ // Returns true to let StatsPuller code evaluate the timeout.
+ EXPECT_TRUE(puller.PullInternal(&dataHolder));
+ int64_t endTimeNs = getElapsedRealtimeNs();
+ int64_t actualPullDurationNs = endTimeNs - startTimeNs;
+
+ // Pull should take at least the timeout amount of time, but should stop early because the delay
+ // is bigger.
+ EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
+ EXPECT_GT(pullDelayNs, actualPullDurationNs);
+ EXPECT_EQ(0, dataHolder.size());
+
+ // Let the pull return and make sure that the dataHolder is not modified.
+ pullThread.join();
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+// Register a puller and ensure that the timeout logic works.
+TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) {
+ sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
+ pullSuccess = true;
+ pullDelayNs = 500000000; // 500 ms.
+ pullTimeoutNs = 10000; // 10 microsseconds.
+ int64_t value = 4321;
+ values.push_back(value);
+
+ StatsPullerManager pullerManager;
+ pullerManager.RegisterPullAtomCallback(/*uid=*/-1, pullTagId, pullCoolDownNs, pullTimeoutNs,
+ vector<int32_t>(), cb);
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ int64_t startTimeNs = getElapsedRealtimeNs();
+ // Returns false, since StatsPuller code will evaluate the timeout.
+ EXPECT_FALSE(pullerManager.Pull(pullTagId, &dataHolder));
+ int64_t endTimeNs = getElapsedRealtimeNs();
+ int64_t actualPullDurationNs = endTimeNs - startTimeNs;
+
+ // Pull should take at least the timeout amount of time, but should stop early because the delay
+ // is bigger.
+ EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
+ EXPECT_GT(pullDelayNs, actualPullDurationNs);
+ EXPECT_EQ(0, dataHolder.size());
+
+ // Let the pull return and make sure that the dataHolder is not modified.
+ pullThread.join();
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp
index 76e2097a90b8..c40719a17f62 100644
--- a/cmds/statsd/tests/external/StatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/StatsPuller_test.cpp
@@ -35,6 +35,7 @@ using std::vector;
using std::this_thread::sleep_for;
using testing::Contains;
+namespace {
// cooldown time 1sec.
int pullTagId = 10014;
@@ -76,7 +77,9 @@ public:
}
};
-TEST_F(StatsPullerTest, PullSucces) {
+} // Anonymous namespace.
+
+TEST_F(StatsPullerTest, PullSuccess) {
pullData.push_back(createSimpleEvent(1111L, 33));
pullSuccess = true;
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 1173d57e5e3f..3a260639de0f 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -22,6 +22,7 @@ droiddoc {
"android.test.runner",
"junit",
"android.test.base",
+ "unsupportedappusage",
],
custom_template: "droiddoc-templates-sdk",
installable: false,
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 0394a7a489ba..97f009c09217 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -878,7 +878,7 @@ android.content.pm.-$$Lambda$jpya2qgMDDEok2GAoKRDqPM5lIE
android.content.pm.ActivityInfo$1
android.content.pm.ActivityInfo$WindowLayout
android.content.pm.ActivityInfo
-android.content.pm.AndroidHidlUpdater
+android.content.pm.parsing.library.AndroidHidlUpdater
android.content.pm.ApplicationInfo$1
android.content.pm.ApplicationInfo
android.content.pm.BaseParceledListSlice
@@ -922,10 +922,10 @@ android.content.pm.LauncherApps$1
android.content.pm.LauncherApps
android.content.pm.ModuleInfo$1
android.content.pm.ModuleInfo
-android.content.pm.OrgApacheHttpLegacyUpdater
-android.content.pm.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater
-android.content.pm.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary
-android.content.pm.PackageBackwardCompatibility
+android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater
+android.content.pm.parsing.library.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater
+android.content.pm.parsing.library.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary
+android.content.pm.parsing.library.PackageBackwardCompatibility
android.content.pm.PackageInfo$1
android.content.pm.PackageInfo
android.content.pm.PackageInstaller$Session
@@ -960,7 +960,7 @@ android.content.pm.PackageParser$SigningDetails$1
android.content.pm.PackageParser$SigningDetails
android.content.pm.PackageParser$SplitNameComparator
android.content.pm.PackageParser
-android.content.pm.PackageSharedLibraryUpdater
+android.content.pm.parsing.library.PackageSharedLibraryUpdater
android.content.pm.PackageStats$1
android.content.pm.PackageStats
android.content.pm.PackageUserState
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index f4cadfd8bbc1..d79740b49b3d 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -141,6 +141,16 @@ public final class AccessibilityShortcutInfo {
}
/**
+ * The {@link ComponentName} of the accessibility shortcut target.
+ *
+ * @return The component name
+ */
+ @NonNull
+ public ComponentName getComponentName() {
+ return mComponentName;
+ }
+
+ /**
* The localized summary of the accessibility shortcut target.
*
* @return The localized summary if available, and {@code null} if a summary
diff --git a/core/java/android/annotation/Hide.java b/core/java/android/annotation/Hide.java
new file mode 100644
index 000000000000..c8e5a4a97ae7
--- /dev/null
+++ b/core/java/android/annotation/Hide.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that an API is hidden by default, in a similar fashion to the
+ * <pre>@hide</pre> javadoc tag.
+ *
+ * <p>Note that, in order for this to work, metalava has to be invoked with
+ * the flag {@code --hide-annotation android.annotation.Hide}.
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
+@Retention(RetentionPolicy.CLASS)
+public @interface Hide {
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6bea68b446a4..577272e38707 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -726,7 +726,7 @@ public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
- Window.OnWindowDismissedCallback, WindowControllerCallback,
+ Window.OnWindowDismissedCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
private static final String TAG = "Activity";
private static final boolean DEBUG_LIFECYCLE = false;
@@ -938,6 +938,62 @@ public class Activity extends ContextThemeWrapper
private Boolean mLastDispatchedIsInMultiWindowMode;
private Boolean mLastDispatchedIsInPictureInPictureMode;
+ private final WindowControllerCallback mWindowControllerCallback =
+ new WindowControllerCallback() {
+ /**
+ * Moves the activity between {@link WindowConfiguration#WINDOWING_MODE_FREEFORM} windowing
+ * mode and {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
+ *
+ * @hide
+ */
+ @Override
+ public void toggleFreeformWindowingMode() throws RemoteException {
+ ActivityTaskManager.getService().toggleFreeformWindowingMode(mToken);
+ }
+
+ /**
+ * Puts the activity in picture-in-picture mode if the activity supports.
+ * @see android.R.attr#supportsPictureInPicture
+ * @hide
+ */
+ @Override
+ public void enterPictureInPictureModeIfPossible() {
+ if (mActivityInfo.supportsPictureInPicture()) {
+ enterPictureInPictureMode();
+ }
+ }
+
+ @Override
+ public boolean isTaskRoot() {
+ try {
+ return ActivityTaskManager.getService().getTaskForActivity(mToken, true) >= 0;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Update the forced status bar color.
+ * @hide
+ */
+ @Override
+ public void updateStatusBarColor(int color) {
+ mTaskDescription.setStatusBarColor(color);
+ setTaskDescription(mTaskDescription);
+ }
+
+ /**
+ * Update the forced navigation bar color.
+ * @hide
+ */
+ @Override
+ public void updateNavigationBarColor(int color) {
+ mTaskDescription.setNavigationBarColor(color);
+ setTaskDescription(mTaskDescription);
+ }
+
+ };
+
private static native String getDlWarning();
/** Return the intent that started this activity. */
@@ -3915,49 +3971,6 @@ public class Activity extends ContextThemeWrapper
/**
- * Moves the activity between {@link WindowConfiguration#WINDOWING_MODE_FREEFORM} windowing mode
- * and {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
- *
- * @hide
- */
- @Override
- public void toggleFreeformWindowingMode() throws RemoteException {
- ActivityTaskManager.getService().toggleFreeformWindowingMode(mToken);
- }
-
- /**
- * Update the forced status bar color.
- * @hide
- */
- @Override
- public void updateStatusBarColor(int color) {
- mTaskDescription.setStatusBarColor(color);
- setTaskDescription(mTaskDescription);
- }
-
- /**
- * Update the forced navigation bar color.
- * @hide
- */
- @Override
- public void updateNavigationBarColor(int color) {
- mTaskDescription.setNavigationBarColor(color);
- setTaskDescription(mTaskDescription);
- }
-
- /**
- * Puts the activity in picture-in-picture mode if the activity supports.
- * @see android.R.attr#supportsPictureInPicture
- * @hide
- */
- @Override
- public void enterPictureInPictureModeIfPossible() {
- if (mActivityInfo.supportsPictureInPicture()) {
- enterPictureInPictureMode();
- }
- }
-
- /**
* Called to process key events. You can override this to intercept all
* key events before they are dispatched to the window. Be sure to call
* this implementation for key events that should be handled normally.
@@ -6603,13 +6616,8 @@ public class Activity extends ContextThemeWrapper
*
* @return True if this is the root activity, else false.
*/
- @Override
public boolean isTaskRoot() {
- try {
- return ActivityTaskManager.getService().getTaskForActivity(mToken, true) >= 0;
- } catch (RemoteException e) {
- return false;
- }
+ return mWindowControllerCallback.isTaskRoot();
}
/**
@@ -7801,7 +7809,7 @@ public class Activity extends ContextThemeWrapper
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
- mWindow.setWindowControllerCallback(this);
+ mWindow.setWindowControllerCallback(mWindowControllerCallback);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 35a48a82cd5e..49a8e2f3f816 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -6254,6 +6254,7 @@ public final class ActivityThread extends ClientTransactionHandler {
// send up app name; do this *before* waiting for debugger
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
+ data.appInfo.packageName,
UserHandle.myUserId());
VMRuntime.setProcessPackageName(data.appInfo.packageName);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 5032f776f8f0..f2fa4fd6845c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2008,7 +2008,7 @@ public class AppOpsManager {
false, // WRITE_MEDIA_VIDEO
false, // READ_MEDIA_IMAGES
false, // WRITE_MEDIA_IMAGES
- false, // LEGACY_STORAGE
+ true, // LEGACY_STORAGE
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
false, // ACCESS_MEDIA_LOCATION
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index d3d7c68d0992..254657e26f3a 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -84,6 +84,19 @@ oneway interface IBackupAgent {
long appVersionCode, in ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder);
+ /**
+ * Restore an entire data snapshot to the application and pass the list of excluded keys to the
+ * backup agent.
+ *
+ * @param excludedKeys List of keys to be excluded from the restore. It will be passed to the
+ * backup agent to make it aware of what data has been removed (in case it has any
+ * application-level implications) as well as the data that should be removed by the
+ * agent itself.
+ */
+ void doRestoreWithExcludedKeys(in ParcelFileDescriptor data,
+ long appVersionCode, in ParcelFileDescriptor newState,
+ int token, IBackupManager callbackBinder, in List<String> excludedKeys);
+
/**
* Perform a "full" backup to the given file descriptor. The output file is presumed
* to be a socket or other non-seekable, write-only data sink. When this method is
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 0957dba4eac1..86f52af1a13b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -207,4 +207,6 @@ interface INotificationManager
void setPrivateNotificationsAllowed(boolean allow);
boolean getPrivateNotificationsAllowed();
+
+ long pullStats(long startNs, int report, boolean doAgg, out List<ParcelFileDescriptor> stats);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 588aceecf4d8..690e9567c1ef 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -493,6 +493,7 @@ public class Instrumentation {
public Activity startActivitySync(@NonNull Intent intent, @Nullable Bundle options) {
validateNotAppThread();
+ final Activity activity;
synchronized (mSync) {
intent = new Intent(intent);
@@ -527,16 +528,18 @@ public class Instrumentation {
} catch (InterruptedException e) {
}
} while (mWaitingActivities.contains(aw));
+ activity = aw.activity;
+ }
- waitForEnterAnimationComplete(aw.activity);
+ // Do not call this method within mSync, lest it could block the main thread.
+ waitForEnterAnimationComplete(activity);
- // Apply an empty transaction to ensure SF has a chance to update before
- // the Activity is ready (b/138263890).
- try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
- t.apply(true);
- }
- return aw.activity;
+ // Apply an empty transaction to ensure SF has a chance to update before
+ // the Activity is ready (b/138263890).
+ try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
+ t.apply(true);
}
+ return activity;
}
/**
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 24580b40aa29..20aa0647d261 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -45,7 +45,10 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -327,6 +330,28 @@ public abstract class BackupAgent extends ContextWrapper {
}
/**
+ * New version of {@link #onRestore(BackupDataInput, long, android.os.ParcelFileDescriptor)}
+ * that has a list of keys to be excluded from the restore. Key/value pairs for which the key
+ * is present in {@code excludedKeys} have already been excluded from the restore data by the
+ * system. The list is passed to the agent to make it aware of what data has been removed (in
+ * case it has any application-level consequences) as well as the data that should be removed
+ * by the agent itself.
+ *
+ * The default implementation calls {@link #onRestore(BackupDataInput, long,
+ * android.os.ParcelFileDescriptor)}.
+ *
+ * @param excludedKeys A list of keys to be excluded from restore.
+ *
+ * @hide
+ */
+ public void onRestore(BackupDataInput data, long appVersionCode,
+ ParcelFileDescriptor newState,
+ Set<String> excludedKeys)
+ throws IOException {
+ onRestore(data, appVersionCode, newState);
+ }
+
+ /**
* The application is having its entire file system contents backed up. {@code data}
* points to the backup destination, and the app has the opportunity to choose which
* files are to be stored. To commit a file as part of the backup, call the
@@ -1016,8 +1041,22 @@ public abstract class BackupAgent extends ContextWrapper {
@Override
public void doRestore(ParcelFileDescriptor data, long appVersionCode,
- ParcelFileDescriptor newState,
- int token, IBackupManager callbackBinder) throws RemoteException {
+ ParcelFileDescriptor newState, int token, IBackupManager callbackBinder)
+ throws RemoteException {
+ doRestoreInternal(data, appVersionCode, newState, token, callbackBinder,
+ /* excludedKeys */ null);
+ }
+
+ @Override
+ public void doRestoreWithExcludedKeys(ParcelFileDescriptor data, long appVersionCode,
+ ParcelFileDescriptor newState, int token, IBackupManager callbackBinder,
+ List<String> excludedKeys) throws RemoteException {
+ doRestoreInternal(data, appVersionCode, newState, token, callbackBinder, excludedKeys);
+ }
+
+ private void doRestoreInternal(ParcelFileDescriptor data, long appVersionCode,
+ ParcelFileDescriptor newState, int token, IBackupManager callbackBinder,
+ List<String> excludedKeys) throws RemoteException {
// Ensure that we're running with the app's normal permission level
long ident = Binder.clearCallingIdentity();
@@ -1029,7 +1068,9 @@ public abstract class BackupAgent extends ContextWrapper {
BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
try {
- BackupAgent.this.onRestore(input, appVersionCode, newState);
+ BackupAgent.this.onRestore(input, appVersionCode, newState,
+ excludedKeys != null ? new HashSet<>(excludedKeys)
+ : Collections.emptySet());
} catch (IOException ex) {
Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
throw new RuntimeException(ex);
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 471606da4d75..55f92be14cd0 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -56,6 +56,7 @@ public final class ManualTimeSuggestion implements Parcelable {
public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
mUtcTime = Objects.requireNonNull(utcTime);
+ Objects.requireNonNull(utcTime.getValue());
}
private static ManualTimeSuggestion createFromParcel(Parcel in) {
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index dd02af7a3ac7..4a89a1245473 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -166,7 +166,12 @@ public final class PhoneTimeSuggestion implements Parcelable {
}
/** Returns the builder for call chaining. */
- public Builder setUtcTime(TimestampedValue<Long> utcTime) {
+ public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) {
+ if (utcTime != null) {
+ // utcTime can be null, but the value it holds cannot.
+ Objects.requireNonNull(utcTime.getValue());
+ }
+
mUtcTime = utcTime;
return this;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d370a380bc3b..7b580c3bde79 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4973,7 +4973,7 @@ public abstract class Context {
* {@link android.content.pm.DataLoaderManager}.
* @hide
*/
- public static final String DATA_LOADER_MANAGER_SERVICE = "dataloadermanager";
+ public static final String DATA_LOADER_MANAGER_SERVICE = "dataloader_manager";
/**
* Use with {@link #getSystemService(String)} to retrieve an
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7815a330217f..ca2de6a8d1e4 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4000,9 +4000,15 @@ public class Intent implements Parcelable, Cloneable {
* Broadcast Action: The sim card state has changed.
* For more details see TelephonyIntents.ACTION_SIM_STATE_CHANGED. This is here
* because TelephonyIntents is an internal class.
- * @hide
+ * The intent will have following extras.</p>
+ * <p>
+ * @see #EXTRA_SIM_STATE
+ * @see #EXTRA_SIM_LOCKED_REASON
+ *
* @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or
* {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ *
+ * @hide
*/
@Deprecated
@SystemApi
@@ -4010,6 +4016,170 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
/**
+ * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for broadcasting SIM STATE.
+ * This will have one of the following intent values.
+ * @see #SIM_STATE_UNKNOWN
+ * @see #SIM_STATE_NOT_READY
+ * @see #SIM_STATE_ABSENT
+ * @see #SIM_STATE_PRESENT
+ * @see #SIM_STATE_CARD_IO_ERROR
+ * @see #SIM_STATE_CARD_RESTRICTED
+ * @see #SIM_STATE_LOCKED
+ * @see #SIM_STATE_READY
+ * @see #SIM_STATE_IMSI
+ * @see #SIM_STATE_LOADED
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String EXTRA_SIM_STATE = "ss";
+
+ /**
+ * The intent value UNKNOWN represents the SIM state unknown
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_UNKNOWN = "UNKNOWN";
+
+ /**
+ * The intent value NOT_READY means that the SIM is not ready eg. radio is off or powering on
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_NOT_READY = "NOT_READY";
+
+ /**
+ * The intent value ABSENT means the SIM card is missing
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_ABSENT = "ABSENT";
+
+ /**
+ * The intent value PRESENT means the device has a SIM card inserted
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_PRESENT = "PRESENT";
+
+ /**
+ * The intent value CARD_IO_ERROR means for three consecutive times there was SIM IO error
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ static public final String SIM_STATE_CARD_IO_ERROR = "CARD_IO_ERROR";
+
+ /**
+ * The intent value CARD_RESTRICTED means card is present but not usable due to carrier
+ * restrictions
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ static public final String SIM_STATE_CARD_RESTRICTED = "CARD_RESTRICTED";
+
+ /**
+ * The intent value LOCKED means the SIM is locked by PIN or by network
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_LOCKED = "LOCKED";
+
+ /**
+ * The intent value READY means the SIM is ready to be accessed
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_READY = "READY";
+
+ /**
+ * The intent value IMSI means the SIM IMSI is ready in property
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_IMSI = "IMSI";
+
+ /**
+ * The intent value LOADED means all SIM records, including IMSI, are loaded
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_LOADED = "LOADED";
+
+ /**
+ * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for broadcasting SIM STATE.
+ * This extra will have one of the following intent values.
+ * <p>
+ * @see #SIM_LOCKED_ON_PIN
+ * @see #SIM_LOCKED_ON_PUK
+ * @see #SIM_LOCKED_NETWORK
+ * @see #SIM_ABSENT_ON_PERM_DISABLED
+ *
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String EXTRA_SIM_LOCKED_REASON = "reason";
+
+ /**
+ * The intent value PIN means the SIM is locked on PIN1
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_LOCKED_ON_PIN = "PIN";
+
+ /**
+ * The intent value PUK means the SIM is locked on PUK1
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ /* PUK means ICC is locked on PUK1 */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_LOCKED_ON_PUK = "PUK";
+
+ /**
+ * The intent value NETWORK means the SIM is locked on NETWORK PERSONALIZATION
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_LOCKED_NETWORK = "NETWORK";
+
+ /**
+ * The intent value PERM_DISABLED means SIM is permanently disabled due to puk fails
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
+
+ /**
* Broadcast Action: indicate that the phone service state has changed.
* The intent will have the following extra values:</p>
* <p>
diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java
index c8e164f1f232..574a93ff9355 100644
--- a/core/java/android/content/integrity/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -44,6 +44,7 @@ public abstract class AtomicFormula implements Formula {
private static final String TAG = "AtomicFormula";
+ /** @hide */
@IntDef(
value = {
PACKAGE_NAME,
@@ -56,6 +57,7 @@ public abstract class AtomicFormula implements Formula {
@Retention(RetentionPolicy.SOURCE)
public @interface Key {}
+ /** @hide */
@IntDef(value = {EQ, LT, LE, GT, GE})
@Retention(RetentionPolicy.SOURCE)
public @interface Operator {}
diff --git a/core/java/android/content/integrity/CompoundFormula.java b/core/java/android/content/integrity/CompoundFormula.java
index 53a99534906c..2a651d9e90d8 100644
--- a/core/java/android/content/integrity/CompoundFormula.java
+++ b/core/java/android/content/integrity/CompoundFormula.java
@@ -47,6 +47,7 @@ import java.util.Objects;
public final class CompoundFormula implements Formula, Parcelable {
private static final String TAG = "OpenFormula";
+ /** @hide */
@IntDef(
value = {
AND, OR, NOT,
diff --git a/core/java/android/content/integrity/Formula.java b/core/java/android/content/integrity/Formula.java
index 030ff6b66e1f..b092a22c0191 100644
--- a/core/java/android/content/integrity/Formula.java
+++ b/core/java/android/content/integrity/Formula.java
@@ -38,6 +38,7 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
@VisibleForTesting
public interface Formula {
+ /** @hide */
@IntDef(
value = {
COMPOUND_FORMULA_TAG,
diff --git a/core/java/android/content/integrity/Rule.java b/core/java/android/content/integrity/Rule.java
index 914f1479edf3..39a0909321d0 100644
--- a/core/java/android/content/integrity/Rule.java
+++ b/core/java/android/content/integrity/Rule.java
@@ -42,6 +42,7 @@ import java.util.Objects;
@VisibleForTesting
public final class Rule implements Parcelable {
+ /** @hide */
@IntDef(
value = {
DENY,
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e72444399dd0..26193f6ebb3d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1376,7 +1376,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
this.minHeight = minHeight;
}
- WindowLayout(Parcel source) {
+ /** @hide */
+ public WindowLayout(Parcel source) {
width = source.readInt();
widthFraction = source.readFloat();
height = source.readInt();
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index d6fb28f694fd..aa0002df2c3a 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -373,8 +373,9 @@ public class PackageInfo implements Parcelable {
/**
* Whether the overlay is static, meaning it cannot be enabled/disabled at runtime.
+ * @hide
*/
- boolean mOverlayIsStatic;
+ public boolean mOverlayIsStatic;
/**
* The user-visible SDK version (ex. 26) of the framework against which the application claims
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e9fc8f6acfc6..f017aad25c0c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -185,7 +185,8 @@ public class PackageInstaller {
* {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
* {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
* {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID},
- * {@link #STATUS_FAILURE_STORAGE}.
+ * {@link #STATUS_FAILURE_STORAGE}, {@link #STATUS_FAILURE_NAME_NOT_FOUND},
+ * {@link #STATUS_FAILURE_ILLEGAL_STATE} or {@link #STATUS_FAILURE_SECURITY}.
* <p>
* More information about a status may be available through additional
* extras; see the individual status documentation for details.
@@ -1130,9 +1131,14 @@ public class PackageInstaller {
*
* @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
* permission.
- * @param statusReceiver Called when the state of the session changes. Intents sent to this
- * receiver contain {@link #EXTRA_STATUS}. Refer to the individual
- * transfer status codes on how to handle them.
+ * @param statusReceiver Called when the state of the session changes. Intents sent to
+ * this receiver contain {@link #EXTRA_STATUS}. Possible statuses:
+ * {@link #STATUS_FAILURE_NAME_NOT_FOUND},
+ * {@link #STATUS_FAILURE_ILLEGAL_STATE},
+ * {@link #STATUS_FAILURE_SECURITY},
+ * {@link #STATUS_FAILURE}.
+ * Refer to the individual transfer status codes on how to handle
+ * them.
*
* @throws PackageManager.NameNotFoundException if the new owner could not be found.
* @throws SecurityException if called after the session has been committed or abandoned.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cf21e9665c71..65ee1e5f0370 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -57,6 +57,12 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageParserCacheHelper.ReadHelper;
import android.content.pm.PackageParserCacheHelper.WriteHelper;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
@@ -67,7 +73,6 @@ 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.FileUtils;
@@ -156,21 +161,22 @@ import java.util.concurrent.atomic.AtomicInteger;
* @hide
*/
public class PackageParser {
- private static final boolean DEBUG_JAR = false;
- private static final boolean DEBUG_PARSER = false;
- private static final boolean DEBUG_BACKUP = false;
- private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
- private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
+
+ public static final boolean DEBUG_JAR = false;
+ public static final boolean DEBUG_PARSER = false;
+ public static final boolean DEBUG_BACKUP = false;
+ public static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
+ public static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
"persist.sys.child_packages_enabled";
- private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
+ public static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
- private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
- private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f;
- private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f;
+ public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
+ public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f;
+ public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f;
private static final int DEFAULT_MIN_SDK_VERSION = 1;
private static final int DEFAULT_TARGET_SDK_VERSION = 0;
@@ -182,37 +188,38 @@ public class PackageParser {
public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
/** Path prefix for apps on expanded storage */
- private static final String MNT_EXPAND = "/mnt/expand/";
-
- private static final String TAG_MANIFEST = "manifest";
- private static final String TAG_APPLICATION = "application";
- private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
- private static final String TAG_OVERLAY = "overlay";
- private static final String TAG_KEY_SETS = "key-sets";
- private static final String TAG_PERMISSION_GROUP = "permission-group";
- private static final String TAG_PERMISSION = "permission";
- private static final String TAG_PERMISSION_TREE = "permission-tree";
- private static final String TAG_USES_PERMISSION = "uses-permission";
- private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
- private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
- private static final String TAG_USES_CONFIGURATION = "uses-configuration";
- private static final String TAG_USES_FEATURE = "uses-feature";
- private static final String TAG_FEATURE_GROUP = "feature-group";
- private static final String TAG_USES_SDK = "uses-sdk";
- private static final String TAG_SUPPORT_SCREENS = "supports-screens";
- private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
- private static final String TAG_INSTRUMENTATION = "instrumentation";
- private static final String TAG_ORIGINAL_PACKAGE = "original-package";
- private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
- private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
- private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
- private static final String TAG_SUPPORTS_INPUT = "supports-input";
- private static final String TAG_EAT_COMMENT = "eat-comment";
- private static final String TAG_PACKAGE = "package";
- private static final String TAG_RESTRICT_UPDATE = "restrict-update";
- private static final String TAG_USES_SPLIT = "uses-split";
-
- private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
+ 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_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_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_PROTECTED_BROADCAST = "protected-broadcast";
+ public static final String TAG_QUERIES = "queries";
+ public static final String TAG_RESTRICT_UPDATE = "restrict-update";
+ public static final String TAG_SUPPORT_SCREENS = "supports-screens";
+ public static final String TAG_SUPPORTS_INPUT = "supports-input";
+ 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";
/**
* Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
@@ -222,25 +229,25 @@ public class PackageParser {
ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
// These are the tags supported by child packages
- private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
+ public static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
static {
CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
- CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
- CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
- CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
- CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
- CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
+ CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
+ CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
- CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
- CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
- CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
- CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
+ CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
- CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
+ CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
+ CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
+ CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
+ CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
+ CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
+ CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
+ CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
}
- private static final boolean LOG_UNSAFE_BROADCASTS = false;
+ public static final boolean LOG_UNSAFE_BROADCASTS = false;
/**
* Total number of packages that were read from the cache. We use it only for logging.
@@ -248,7 +255,7 @@ public class PackageParser {
public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
// Set of broadcast actions that are safe for manifest receivers
- private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
+ public static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
static {
SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
}
@@ -295,26 +302,29 @@ public class PackageParser {
* @deprecated callers should move to explicitly passing around source path.
*/
@Deprecated
- private String mArchiveSourcePath;
+ public String mArchiveSourcePath;
- private String[] mSeparateProcesses;
+ public String[] mSeparateProcesses;
private boolean mOnlyCoreApps;
private DisplayMetrics mMetrics;
@UnsupportedAppUsage
- private Callback mCallback;
+ public Callback mCallback;
private File mCacheDir;
- private static final int SDK_VERSION = Build.VERSION.SDK_INT;
- private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+ public static final int SDK_VERSION = Build.VERSION.SDK_INT;
+ public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+
+ public int mParseError = PackageManager.INSTALL_SUCCEEDED;
- private int mParseError = PackageManager.INSTALL_SUCCEEDED;
+ public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult
+ = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new);
- private static boolean sCompatibilityModeEnabled = true;
- private static boolean sUseRoundIcon = false;
+ public static boolean sCompatibilityModeEnabled = true;
+ public static boolean sUseRoundIcon = false;
- private static final int PARSE_DEFAULT_INSTALL_LOCATION =
+ public static final int PARSE_DEFAULT_INSTALL_LOCATION =
PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
- private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
+ public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
static class ParsePackageItemArgs {
final Package owner;
@@ -536,7 +546,7 @@ public class PackageParser {
* 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. */
- private static final boolean RIGID_PARSER = false;
+ public static final boolean RIGID_PARSER = false;
private static final String TAG = "PackageParser";
@@ -887,7 +897,7 @@ public class PackageParser {
@Retention(RetentionPolicy.SOURCE)
public @interface ParseFlags {}
- private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
+ public static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
/**
* Used to sort a set of APKs based on their split names, always placing the
@@ -1033,7 +1043,7 @@ public class PackageParser {
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(Package, int)}.
+ * must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, 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
@@ -1041,21 +1051,54 @@ public class PackageParser {
* has changed since the last parse, it's up to callers to do so.
*
* @see #parsePackageLite(File, int)
+ * @deprecated use {@link #parseParsedPackage(File, int, boolean)}
*/
@UnsupportedAppUsage
+ @Deprecated
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
- Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
+ if (packageFile.isDirectory()) {
+ return parseClusterPackage(packageFile, flags);
+ } else {
+ return parseMonolithicPackage(packageFile, flags);
+ }
+ }
+
+ /**
+ * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
+ * @deprecated use {@link #parseParsedPackage(File, int, boolean)}
+ */
+ @UnsupportedAppUsage
+ @Deprecated
+ public Package parsePackage(File packageFile, int flags) throws PackageParserException {
+ return parsePackage(packageFile, flags, false /* useCaches */);
+ }
+
+ /**
+ * Updated method which returns {@link ParsedPackage}, the current representation of a
+ * package parsed from disk.
+ *
+ * @see #parsePackage(File, int, boolean)
+ */
+ public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches)
+ throws PackageParserException {
+ ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
- if (packageFile.isDirectory()) {
- parsed = parseClusterPackage(packageFile, flags);
- } else {
- parsed = parseMonolithicPackage(packageFile, flags);
- }
+ ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset();
+ parsed = ApkParseUtils.parsePackage(
+ parseInput,
+ mSeparateProcesses,
+ mCallback,
+ mMetrics,
+ mOnlyCoreApps,
+ packageFile,
+ flags
+ )
+ .hideAsParsed();
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
cacheResult(packageFile, flags, parsed);
@@ -1067,19 +1110,12 @@ public class PackageParser {
+ "ms, update_cache=" + cacheTime + " ms");
}
}
- return parsed;
- }
- /**
- * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
- */
- @UnsupportedAppUsage
- public Package parsePackage(File packageFile, int flags) throws PackageParserException {
- return parsePackage(packageFile, flags, false /* useCaches */);
+ return parsed;
}
/**
- * Returns the cache key for a specificied {@code packageFile} and {@code flags}.
+ * Returns the cache key for a specified {@code packageFile} and {@code flags}.
*/
private String getCacheKey(File packageFile, int flags) {
StringBuilder sb = new StringBuilder(packageFile.getName());
@@ -1090,13 +1126,13 @@ public class PackageParser {
}
@VisibleForTesting
- protected Package fromCacheEntry(byte[] bytes) {
+ protected ParsedPackage fromCacheEntry(byte[] bytes) {
return fromCacheEntryStatic(bytes);
}
/** static version of {@link #fromCacheEntry} for unit tests. */
@VisibleForTesting
- public static Package fromCacheEntryStatic(byte[] bytes) {
+ public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
final Parcel p = Parcel.obtain();
p.unmarshall(bytes, 0, bytes.length);
p.setDataPosition(0);
@@ -1104,7 +1140,8 @@ public class PackageParser {
final ReadHelper helper = new ReadHelper(p);
helper.startAndInstall();
- PackageParser.Package pkg = new PackageParser.Package(p);
+ // TODO(b/135203078): Hide PackageImpl constructor?
+ ParsedPackage pkg = new PackageImpl(p);
p.recycle();
@@ -1114,14 +1151,14 @@ public class PackageParser {
}
@VisibleForTesting
- protected byte[] toCacheEntry(Package pkg) {
+ protected byte[] toCacheEntry(ParsedPackage pkg) {
return toCacheEntryStatic(pkg);
}
/** static version of {@link #toCacheEntry} for unit tests. */
@VisibleForTesting
- public static byte[] toCacheEntryStatic(Package pkg) {
+ public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
final Parcel p = Parcel.obtain();
final WriteHelper helper = new WriteHelper(p);
@@ -1170,7 +1207,7 @@ public class PackageParser {
* Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
* or {@code null} if no cached result exists.
*/
- private Package getCachedResult(File packageFile, int flags) {
+ public ParsedPackage getCachedResult(File packageFile, int flags) {
if (mCacheDir == null) {
return null;
}
@@ -1199,7 +1236,7 @@ public class PackageParser {
/**
* Caches the parse result for {@code packageFile} with flags {@code flags}.
*/
- private void cacheResult(File packageFile, int flags, Package parsed) {
+ public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
if (mCacheDir == null) {
return;
}
@@ -1238,7 +1275,8 @@ public class PackageParser {
* split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(Package, int)}.
+ * must be done separately in
+ * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
*/
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
@@ -1302,10 +1340,11 @@ public class PackageParser {
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(Package, int)}.
+ * must be done separately in
+ * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
*
* @deprecated external callers should move to
- * {@link #parsePackage(File, int)}. Eventually this method will
+ * {@link #parseParsedPackage(File, int, boolean)}. Eventually this method will
* be marked private.
*/
@Deprecated
@@ -1505,8 +1544,11 @@ public class PackageParser {
* Collect certificates from all the APKs described in the given package,
* populating {@link Package#mSigningDetails}. Also asserts that all APK
* contents are signed correctly and consistently.
+ *
+ * @deprecated use {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}
*/
@UnsupportedAppUsage
+ @Deprecated
public static void collectCertificates(Package pkg, boolean skipVerify)
throws PackageParserException {
collectCertificatesInternal(pkg, skipVerify);
@@ -1685,7 +1727,7 @@ public class PackageParser {
? null : "must have at least one '.' separator";
}
- private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
+ public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
AttributeSet attrs) throws IOException, XmlPullParserException,
PackageParserException {
@@ -2454,8 +2496,6 @@ public class PackageParser {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
- } else if (tagName.equals("queries")) {
- parseQueries(pkg, res, parser, flags, outError);
} else {
Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
@@ -2925,7 +2965,7 @@ public class PackageParser {
return true;
}
- private static String buildClassName(String pkg, CharSequence clsSeq,
+ public static String buildClassName(String pkg, CharSequence clsSeq,
String[] outError) {
if (clsSeq == null || clsSeq.length() <= 0) {
outError[0] = "Empty class name in package " + pkg;
@@ -2973,7 +3013,7 @@ public class PackageParser {
return proc;
}
- private static String buildProcessName(String pkg, String defProc,
+ public static String buildProcessName(String pkg, String defProc,
CharSequence procSeq, int flags, String[] separateProcesses,
String[] outError) {
if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
@@ -2993,7 +3033,7 @@ public class PackageParser {
return TextUtils.safeIntern(buildCompoundName(pkg, procSeq, "process", outError));
}
- private static String buildTaskAffinityName(String pkg, String defProc,
+ public static String buildTaskAffinityName(String pkg, String defProc,
CharSequence procSeq, String[] outError) {
if (procSeq == null) {
return defProc;
@@ -3555,9 +3595,6 @@ public class PackageParser {
owner.mRequiredAccountType = requiredAccountType;
}
- owner.mForceQueryable =
- sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
-
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
false)) {
@@ -4019,89 +4056,6 @@ public class PackageParser {
return true;
}
- private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags,
- String[] outError)
- throws IOException, XmlPullParserException {
-
- 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;
- }
- if (parser.getName().equals("intent")) {
- QueriesIntentInfo intentInfo = new QueriesIntentInfo();
- if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
- intentInfo, outError)) {
- return false;
- }
-
- Uri data = null;
- String dataType = null;
- String host = "";
- 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)) {
- outError[0] = "intent tags must contain either an action or data.";
- return false;
- }
- if (numActions > 1) {
- outError[0] = "intent tag may have at most one action.";
- return false;
- }
- if (numTypes > 1) {
- outError[0] = "intent tag may have at most one data type.";
- return false;
- }
- if (numSchemes > 1) {
- outError[0] = "intent tag may have at most one data scheme.";
- return false;
- }
- if (numHosts > 1) {
- outError[0] = "intent tag may have at most one data host.";
- return false;
- }
- 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)
- .build();
- }
- if (numTypes == 1) {
- dataType = intentInfo.getDataType(0);
- }
- intent.setDataAndType(data, dataType);
- if (numActions == 1) {
- intent.setAction(intentInfo.getAction(0));
- }
- owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent);
- } else if (parser.getName().equals("package")) {
- final TypedArray sa = res.obtainAttributes(parser,
- com.android.internal.R.styleable.AndroidManifestQueriesPackage);
- final String packageName =
- sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
- if (TextUtils.isEmpty(packageName)) {
- outError[0] = "Package name is missing from package tag.";
- return false;
- }
- owner.mQueriesPackages =
- ArrayUtils.add(owner.mQueriesPackages, packageName.intern());
- }
- }
- return true;
- }
-
/**
* Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
*/
@@ -5813,7 +5767,7 @@ public class PackageParser {
return null;
}
- private static final String ANDROID_RESOURCES
+ public static final String ANDROID_RESOURCES
= "http://schemas.android.com/apk/res/android";
private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs,
@@ -6508,7 +6462,10 @@ public class PackageParser {
/**
* Representation of a full package parsed from APK files on disk. A package
* consists of a single base APK, and zero or more split APKs.
+ *
+ * @deprecated use an {@link AndroidPackage}
*/
+ @Deprecated
public final static class Package implements Parcelable {
@UnsupportedAppUsage
@@ -6616,9 +6573,6 @@ public class PackageParser {
// The major version code declared for this package.
public int mVersionCodeMajor;
- // Whether the package declares that it should be queryable by all normal apps on device.
- public boolean mForceQueryable;
-
// Return long containing mVersionCode and mVersionCodeMajor.
public long getLongVersionCode() {
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
@@ -6724,9 +6678,6 @@ public class PackageParser {
/** Whether or not the package is a stub and must be replaced by the full version. */
public boolean isStub;
- public ArrayList<String> mQueriesPackages;
- public ArrayList<Intent> mQueriesIntents;
-
@UnsupportedAppUsage
public Package(String packageName) {
this.packageName = packageName;
@@ -7230,9 +7181,6 @@ public class PackageParser {
use32bitAbi = (dest.readInt() == 1);
restrictUpdateHash = dest.createByteArray();
visibleToInstantApps = dest.readInt() == 1;
- mForceQueryable = dest.readBoolean();
- mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR);
- mQueriesPackages = dest.createStringArrayList();
}
private static void internStringArrayList(List<String> list) {
@@ -7248,7 +7196,7 @@ public class PackageParser {
* Sets the package owner and the the {@code applicationInfo} for every component
* owner by this package.
*/
- private void fixupOwner(List<? extends Component<?>> list) {
+ public void fixupOwner(List<? extends Component<?>> list) {
if (list != null) {
for (Component<?> c : list) {
c.owner = this;
@@ -7358,12 +7306,8 @@ public class PackageParser {
dest.writeInt(use32bitAbi ? 1 : 0);
dest.writeByteArray(restrictUpdateHash);
dest.writeInt(visibleToInstantApps ? 1 : 0);
- dest.writeBoolean(mForceQueryable);
- dest.writeTypedList(mQueriesIntents);
- dest.writeList(mQueriesPackages);
}
-
/**
* Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
*/
@@ -7435,6 +7379,10 @@ public class PackageParser {
};
}
+ /**
+ * @deprecated use a {@link ComponentParseUtils.ParsedComponent}
+ */
+ @Deprecated
public static abstract class Component<II extends IntentInfo> {
@UnsupportedAppUsage
public final ArrayList<II> intents;
@@ -7615,6 +7563,10 @@ public class PackageParser {
}
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedPermission}
+ */
+ @Deprecated
public final static class Permission extends Component<IntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final PermissionInfo info;
@@ -7689,6 +7641,10 @@ public class PackageParser {
};
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedPermissionGroup}
+ */
+ @Deprecated
public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final PermissionGroupInfo info;
@@ -7788,7 +7744,12 @@ public class PackageParser {
return false;
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+ * AndroidPackage, int, PackageUserState, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
PackageUserState state) {
return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
@@ -7845,7 +7806,12 @@ public class PackageParser {
ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes;
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+ * AndroidPackage, int, PackageUserState, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
PackageUserState state, int userId) {
if (p == null) return null;
@@ -7885,6 +7851,11 @@ public class PackageParser {
return ai;
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+ * AndroidPackage, int, PackageUserState, int)}
+ */
+ @Deprecated
public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
PackageUserState state, int userId) {
if (ai == null) return null;
@@ -7904,7 +7875,12 @@ public class PackageParser {
return ai;
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generatePermissionInfo(
+ * ComponentParseUtils.ParsedPermission, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static final PermissionInfo generatePermissionInfo(
Permission p, int flags) {
if (p == null) return null;
@@ -7916,7 +7892,12 @@ public class PackageParser {
return pi;
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generatePermissionGroupInfo(
+ * ComponentParseUtils.ParsedPermissionGroup, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static final PermissionGroupInfo generatePermissionGroupInfo(
PermissionGroup pg, int flags) {
if (pg == null) return null;
@@ -7928,6 +7909,10 @@ public class PackageParser {
return pgi;
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedActivity}
+ */
+ @Deprecated
public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final ActivityInfo info;
@@ -8043,7 +8028,12 @@ public class PackageParser {
};
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateActivityInfo(
+ * AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static final ActivityInfo generateActivityInfo(Activity a, int flags,
PackageUserState state, int userId) {
if (a == null) return null;
@@ -8061,6 +8051,11 @@ public class PackageParser {
return ai;
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateActivityInfo(
+ * AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)}
+ */
+ @Deprecated
public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
PackageUserState state, int userId) {
if (ai == null) return null;
@@ -8074,6 +8069,10 @@ public class PackageParser {
return ai;
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedService}
+ */
+ @Deprecated
public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final ServiceInfo info;
@@ -8135,7 +8134,12 @@ public class PackageParser {
};
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateServiceInfo(
+ * AndroidPackage, ComponentParseUtils.ParsedService, int, PackageUserState, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static final ServiceInfo generateServiceInfo(Service s, int flags,
PackageUserState state, int userId) {
if (s == null) return null;
@@ -8153,6 +8157,10 @@ public class PackageParser {
return si;
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedProvider}
+ */
+ @Deprecated
public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final ProviderInfo info;
@@ -8233,7 +8241,12 @@ public class PackageParser {
};
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateProviderInfo(
+ * AndroidPackage, ComponentParseUtils.ParsedProvider, int, PackageUserState, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static final ProviderInfo generateProviderInfo(Provider p, int flags,
PackageUserState state, int userId) {
if (p == null) return null;
@@ -8256,6 +8269,10 @@ public class PackageParser {
return pi;
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedInstrumentation}
+ */
+ @Deprecated
public final static class Instrumentation extends Component<IntentInfo> implements
Parcelable {
@UnsupportedAppUsage
@@ -8316,7 +8333,12 @@ public class PackageParser {
};
}
+ /**
+ * @deprecated use {@link PackageInfoUtils#generateInstrumentationInfo(
+ * ComponentParseUtils.ParsedInstrumentation, int)}
+ */
@UnsupportedAppUsage
+ @Deprecated
public static final InstrumentationInfo generateInstrumentationInfo(
Instrumentation i, int flags) {
if (i == null) return null;
@@ -8328,6 +8350,10 @@ public class PackageParser {
return ii;
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedIntentInfo}
+ */
+ @Deprecated
public static abstract class IntentInfo extends IntentFilter {
@UnsupportedAppUsage
public boolean hasDefault;
@@ -8371,8 +8397,10 @@ public class PackageParser {
}
}
- public static final class QueriesIntentInfo extends IntentInfo {}
-
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedActivityIntentInfo}
+ */
+ @Deprecated
public final static class ActivityIntentInfo extends IntentInfo {
@UnsupportedAppUsage
public Activity activity;
@@ -8396,6 +8424,10 @@ public class PackageParser {
}
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedServiceIntentInfo}
+ */
+ @Deprecated
public final static class ServiceIntentInfo extends IntentInfo {
@UnsupportedAppUsage
public Service service;
@@ -8419,6 +8451,10 @@ public class PackageParser {
}
}
+ /**
+ * @deprecated use {@link ComponentParseUtils.ParsedProviderIntentInfo}
+ */
+ @Deprecated
public static final class ProviderIntentInfo extends IntentInfo {
@UnsupportedAppUsage
public Provider provider;
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 5c74efb8ff1b..55574c3cb880 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -28,6 +28,7 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPON
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import android.annotation.UnsupportedAppUsage;
+import android.content.pm.parsing.ComponentParseUtils;
import android.os.BaseBundle;
import android.os.Debug;
import android.os.PersistableBundle;
@@ -127,6 +128,18 @@ public class PackageUserState {
&& (!this.hidden || matchUninstalled));
}
+ public boolean isMatch(ComponentInfo componentInfo, int flags) {
+ return isMatch(componentInfo.applicationInfo.isSystemApp(),
+ componentInfo.applicationInfo.enabled, componentInfo.enabled,
+ componentInfo.directBootAware, componentInfo.name, flags);
+ }
+
+ public boolean isMatch(boolean isSystem, boolean isPackageEnabled,
+ ComponentParseUtils.ParsedComponent component, int flags) {
+ return isMatch(isSystem, isPackageEnabled, component.isEnabled(),
+ component.isDirectBootAware(), component.getName(), flags);
+ }
+
/**
* Test if the given component is considered installed, enabled and a match
* for the given flags.
@@ -135,28 +148,33 @@ public class PackageUserState {
* Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
* {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
* </p>
+ *
*/
- public boolean isMatch(ComponentInfo componentInfo, int flags) {
- final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
+ public boolean isMatch(boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled,
+ boolean isComponentDirectBootAware, String componentName, int flags) {
final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
- if (!isAvailable(flags)
- && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags);
- if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags);
+ if (!isAvailable(flags) && !(isSystem && matchUninstalled)) {
+ return reportIfDebug(false, flags);
+ }
+
+ if (!isEnabled(isPackageEnabled, isComponentEnabled, componentName, flags)) {
+ return reportIfDebug(false, flags);
+ }
if ((flags & MATCH_SYSTEM_ONLY) != 0) {
- if (!isSystemApp) {
+ if (!isSystem) {
return reportIfDebug(false, flags);
}
}
final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
- && !componentInfo.directBootAware;
+ && !isComponentDirectBootAware;
final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
- && componentInfo.directBootAware;
+ && isComponentDirectBootAware;
return reportIfDebug(matchesUnaware || matchesAware, flags);
}
- private boolean reportIfDebug(boolean result, int flags) {
+ public boolean reportIfDebug(boolean result, int flags) {
if (DEBUG && !result) {
Slog.i(LOG_TAG, "No match!; flags: "
+ DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
@@ -165,10 +183,22 @@ public class PackageUserState {
return result;
}
+ public boolean isEnabled(ComponentInfo componentInfo, int flags) {
+ return isEnabled(componentInfo.applicationInfo.enabled, componentInfo.enabled,
+ componentInfo.name, flags);
+ }
+
+ public boolean isEnabled(boolean isPackageEnabled,
+ ComponentParseUtils.ParsedComponent parsedComponent, int flags) {
+ return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(),
+ flags);
+ }
+
/**
* Test if the given component is considered enabled.
*/
- public boolean isEnabled(ComponentInfo componentInfo, int flags) {
+ public boolean isEnabled(boolean isPackageEnabled, boolean isComponentEnabled,
+ String componentName, int flags) {
if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
return true;
}
@@ -183,24 +213,26 @@ public class PackageUserState {
if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
return false;
}
+ // fallthrough
case COMPONENT_ENABLED_STATE_DEFAULT:
- if (!componentInfo.applicationInfo.enabled) {
+ if (!isPackageEnabled) {
return false;
}
+ // fallthrough
case COMPONENT_ENABLED_STATE_ENABLED:
break;
}
// Check if component has explicit state before falling through to
// the manifest default
- if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) {
+ if (ArrayUtils.contains(this.enabledComponents, componentName)) {
return true;
}
- if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) {
+ if (ArrayUtils.contains(this.disabledComponents, componentName)) {
return false;
}
- return componentInfo.enabled;
+ return isComponentEnabled;
}
@Override
diff --git a/core/java/android/content/pm/ParceledListSlice.aidl b/core/java/android/content/pm/ParceledListSlice.aidl
index c02cc6a5472e..5031fbaca9e6 100644
--- a/core/java/android/content/pm/ParceledListSlice.aidl
+++ b/core/java/android/content/pm/ParceledListSlice.aidl
@@ -16,4 +16,4 @@
package android.content.pm;
-parcelable ParceledListSlice;
+parcelable ParceledListSlice<T>;
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 3488cc30892c..2863b268e795 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,20 +39,24 @@ import java.util.List;
public final class SharedLibraryInfo implements Parcelable {
/** @hide */
- public static SharedLibraryInfo createForStatic(PackageParser.Package pkg) {
- return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(),
- pkg.staticSharedLibName,
- pkg.staticSharedLibVersion,
+ public static SharedLibraryInfo createForStatic(AndroidPackage pkg) {
+ return new SharedLibraryInfo(null, pkg.getPackageName(),
+ pkg.makeListAllCodePaths(),
+ pkg.getStaticSharedLibName(),
+ pkg.getStaticSharedLibVersion(),
TYPE_STATIC,
- new VersionedPackage(pkg.manifestPackageName, pkg.getLongVersionCode()),
+ new VersionedPackage(pkg.getManifestPackageName(),
+ pkg.getLongVersionCode()),
null, null);
}
/** @hide */
- public static SharedLibraryInfo createForDynamic(PackageParser.Package pkg, String name) {
- return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(), name,
+ public static SharedLibraryInfo createForDynamic(AndroidPackage pkg, String name) {
+ return new SharedLibraryInfo(null, pkg.getPackageName(),
+ pkg.makeListAllCodePaths(), name,
(long) VERSION_UNDEFINED,
- TYPE_DYNAMIC, new VersionedPackage(pkg.packageName, pkg.getLongVersionCode()),
+ TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(),
+ pkg.getLongVersionCode()),
null, null);
}
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index 5d10b8826b00..4cd201fbe538 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -22,6 +22,7 @@ import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.AndroidPackage;
import android.util.ArrayMap;
import android.util.jar.StrictJarFile;
@@ -86,8 +87,8 @@ public class DexMetadataHelper {
*
* NOTE: involves I/O checks.
*/
- public static Map<String, String> getPackageDexMetadata(PackageParser.Package pkg) {
- return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths());
+ public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) {
+ return buildPackageApkToDexMetadataMap(pkg.makeListAllCodePaths());
}
/**
@@ -160,7 +161,7 @@ public class DexMetadataHelper {
*
* @throws PackageParserException in case of errors.
*/
- public static void validatePackageDexMetadata(PackageParser.Package pkg)
+ public static void validatePackageDexMetadata(AndroidPackage pkg)
throws PackageParserException {
Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
for (String dexMetadata : apkToDexMetadataList) {
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.aidl b/core/java/android/content/pm/parsing/AndroidPackage.aidl
new file mode 100644
index 000000000000..ab3cf7cb8c65
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackage.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm.parsing;
+
+/* @hide */
+parcelable AndroidPackage;
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
new file mode 100644
index 000000000000..515185eaaf57
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import java.security.PublicKey;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * The last state of a package during parsing/install before it is available in
+ * {@link com.android.server.pm.PackageManagerService#mPackages}.
+ *
+ * It is the responsibility of the caller to understand what data is available at what step of the
+ * parsing or install process.
+ *
+ * TODO(b/135203078): Nullability annotations
+ * TODO(b/135203078): Remove get/setAppInfo differences
+ *
+ * @hide
+ */
+public interface AndroidPackage extends Parcelable {
+
+ /**
+ * This will eventually be removed. Avoid calling this at all costs.
+ */
+ @Deprecated
+ AndroidPackageWrite mutate();
+
+ boolean canHaveOatDir();
+
+ boolean cantSaveState();
+
+ List<String> getAdoptPermissions();
+
+ List<String> getAllCodePaths();
+
+ List<String> getAllCodePathsExcludingResourceOnly();
+
+ String getAppComponentFactory();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #getClassLoaderName()}
+ */
+ @Deprecated
+ String getAppInfoClassLoaderName();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #getCodePath()}
+ */
+ @Deprecated
+ String getAppInfoCodePath();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #getName()}
+ */
+ @Deprecated
+ String getAppInfoName();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #getPackageName()}
+ */
+ @Deprecated
+ String getAppInfoPackageName();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #getProcessName()}
+ */
+ @Deprecated
+ String getAppInfoProcessName();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #getCodePath()}
+ */
+ @Deprecated
+ String getAppInfoResourcePath();
+
+ Bundle getAppMetaData();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #getVolumeUuid()}
+ */
+ @Deprecated
+ String getApplicationInfoVolumeUuid();
+
+ String getBackupAgentName();
+
+ int getBanner();
+
+ String getBaseCodePath();
+
+ int getBaseRevisionCode();
+
+ int getCategory();
+
+ String getClassLoaderName();
+
+ String getClassName();
+
+ String getCodePath();
+
+ int getCompatibleWidthLimitDp();
+
+ int getCompileSdkVersion();
+
+ String getCompileSdkVersionCodeName();
+
+ @Nullable
+ List<ConfigurationInfo> getConfigPreferences();
+
+ String getCpuAbiOverride();
+
+ String getCredentialProtectedDataDir();
+
+ String getDataDir();
+
+ int getDescriptionRes();
+
+ String getDeviceProtectedDataDir();
+
+ List<FeatureGroupInfo> getFeatureGroups();
+
+ int getFlags();
+
+ int getFullBackupContent();
+
+ int getHiddenApiEnforcementPolicy();
+
+ int getIcon();
+
+ int getIconRes();
+
+ List<String> getImplicitPermissions();
+
+ int getInstallLocation();
+
+ Map<String, ArraySet<PublicKey>> getKeySetMapping();
+
+ int getLabelRes();
+
+ int getLargestWidthLimitDp();
+
+ long[] getLastPackageUsageTimeInMills();
+
+ long getLatestForegroundPackageUseTimeInMills();
+
+ long getLatestPackageUseTimeInMills();
+
+ List<String> getLibraryNames();
+
+ int getLogo();
+
+ long getLongVersionCode();
+
+ String getManageSpaceActivityName();
+
+ String getManifestPackageName();
+
+ float getMaxAspectRatio();
+
+ Bundle getMetaData(); // TODO(b/135203078): Make all the Bundles immutable
+
+ float getMinAspectRatio();
+
+ int getMinSdkVersion();
+
+ String getName();
+
+ String getNativeLibraryDir();
+
+ String getNativeLibraryRootDir();
+
+ int getNetworkSecurityConfigRes();
+
+ CharSequence getNonLocalizedLabel();
+
+ @Nullable
+ List<String> getOriginalPackages();
+
+ String getOverlayCategory();
+
+ int getOverlayPriority();
+
+ String getOverlayTarget();
+
+ String getOverlayTargetName();
+
+ // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods?
+ // The refactor makes them the same value with no known consequences, so should be redundant.
+ String getPackageName();
+
+ @Nullable
+ List<ParsedActivity> getActivities();
+
+ @Nullable
+ List<ParsedInstrumentation> getInstrumentations();
+
+ @Nullable
+ List<ParsedPermissionGroup> getPermissionGroups();
+
+ @Nullable
+ List<ParsedPermission> getPermissions();
+
+ @Nullable
+ List<ParsedProvider> getProviders();
+
+ @Nullable
+ List<ParsedActivity> getReceivers();
+
+ @Nullable
+ List<ParsedService> getServices();
+
+ String getPermission();
+
+ @Nullable
+ List<ParsedActivityIntentInfo> getPreferredActivityFilters();
+
+ int getPreferredOrder();
+
+ String getPrimaryCpuAbi();
+
+ int getPrivateFlags();
+
+ String getProcessName();
+
+ @Nullable
+ List<String> getProtectedBroadcasts();
+
+ String getPublicSourceDir();
+
+ List<Intent> getQueriesIntents();
+
+ List<String> getQueriesPackages();
+
+ String getRealPackage();
+
+ // TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambiguous whether "Req" is
+ // required or requested.
+ @Nullable
+ List<FeatureInfo> getReqFeatures();
+
+ List<String> getRequestedPermissions();
+
+ String getRequiredAccountType();
+
+ int getRequiresSmallestWidthDp();
+
+ byte[] getRestrictUpdateHash();
+
+ String getRestrictedAccountType();
+
+ int getRoundIconRes();
+
+ String getScanPublicSourceDir();
+
+ String getScanSourceDir();
+
+ String getSeInfo();
+
+ String getSeInfoUser();
+
+ String getSecondaryCpuAbi();
+
+ String getSecondaryNativeLibraryDir();
+
+ String getSharedUserId();
+
+ int getSharedUserLabel();
+
+ PackageParser.SigningDetails getSigningDetails();
+
+ String[] getSplitClassLoaderNames();
+
+ @Nullable
+ String[] getSplitCodePaths();
+
+ @Nullable
+ SparseArray<int[]> getSplitDependencies();
+
+ int[] getSplitFlags();
+
+ String[] getSplitNames();
+
+ String[] getSplitPublicSourceDirs();
+
+ int[] getSplitRevisionCodes();
+
+ String getStaticSharedLibName();
+
+ long getStaticSharedLibVersion();
+
+ // TODO(b/135203078): Return String directly
+ UUID getStorageUuid();
+
+ int getTargetSandboxVersion();
+
+ int getTargetSdkVersion();
+
+ String getTaskAffinity();
+
+ int getTheme();
+
+ int getUiOptions();
+
+ int getUid();
+
+ Set<String> getUpgradeKeySets();
+
+ @Nullable
+ List<String> getUsesLibraries();
+
+ @Nullable
+ String[] getUsesLibraryFiles();
+
+ List<SharedLibraryInfo> getUsesLibraryInfos();
+
+ @Nullable
+ List<String> getUsesOptionalLibraries();
+
+ @Nullable
+ List<String> getUsesStaticLibraries();
+
+ @Nullable
+ String[][] getUsesStaticLibrariesCertDigests();
+
+ @Nullable
+ long[] getUsesStaticLibrariesVersions();
+
+ int getVersionCode();
+
+ int getVersionCodeMajor();
+
+ String getVersionName();
+
+ String getVolumeUuid();
+
+ String getZygotePreloadName();
+
+ boolean hasComponentClassName(String className);
+
+ // App Info
+
+ boolean hasRequestedLegacyExternalStorage();
+
+ boolean isBaseHardwareAccelerated();
+
+ boolean isCoreApp();
+
+ boolean isDefaultToDeviceProtectedStorage();
+
+ boolean isDirectBootAware();
+
+ boolean isEmbeddedDexUsed();
+
+ boolean isEnabled();
+
+ boolean isEncryptionAware();
+
+ boolean isExternal();
+
+ boolean isForceQueryable();
+
+ boolean isForwardLocked();
+
+ boolean isHiddenUntilInstalled();
+
+ boolean isInstantApp();
+
+ boolean isInternal();
+
+ boolean isLibrary();
+
+ // TODO(b/135203078): Should probably be in a utility class
+ boolean isMatch(int flags);
+
+ boolean isNativeLibraryRootRequiresIsa();
+
+ boolean isOem();
+
+ boolean isOverlayIsStatic();
+
+ boolean isPrivileged();
+
+ boolean isProduct();
+
+ boolean isProfileableByShell();
+
+ boolean isRequiredForAllUsers();
+
+ boolean isStaticSharedLibrary();
+
+ boolean isStub();
+
+ boolean isSystem(); // TODO(b/135203078): Collapse with isSystemApp, should be exactly the same.
+
+ boolean isSystemApp();
+
+ boolean isSystemExt();
+
+ boolean isUpdatedSystemApp();
+
+ boolean isUse32BitAbi();
+
+ boolean isVendor();
+
+ boolean isVisibleToInstantApps();
+
+ List<String> makeListAllCodePaths(); // TODO(b/135203078): Collapse with getAllCodePaths
+
+ boolean requestsIsolatedSplitLoading();
+
+ /**
+ * Generates an {@link ApplicationInfo} object with only the data available in this object.
+ *
+ * This does not contain any system or user state data, and should be avoided. Prefer
+ * {@link PackageInfoUtils#generateApplicationInfo(AndroidPackage, int, PackageUserState, int)}.
+ */
+ ApplicationInfo toAppInfoWithoutState();
+
+ Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
+ @Override
+ public PackageImpl createFromParcel(Parcel source) {
+ return new PackageImpl(source);
+ }
+
+ @Override
+ public PackageImpl[] newArray(int size) {
+ return new PackageImpl[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/parsing/AndroidPackageWrite.java b/core/java/android/content/pm/parsing/AndroidPackageWrite.java
new file mode 100644
index 000000000000..b7595d2dd710
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackageWrite.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+
+import java.util.List;
+
+/**
+ * Contains remaining mutable fields after package parsing has completed.
+ *
+ * Most are state that can probably be tracked outside of the AndroidPackage object. New methods
+ * should never be added to this interface.
+ *
+ * TODO(b/135203078): Remove entirely
+ *
+ * @deprecated the eventual goal is that the object returned from parsing represents exactly what
+ * was parsed from the APK, and so further mutation should be disallowed,
+ * with any state being stored in another class
+ *
+ * @hide
+ */
+@Deprecated
+public interface AndroidPackageWrite extends AndroidPackage {
+
+ AndroidPackageWrite setUsesLibraryFiles(@Nullable String[] usesLibraryFiles);
+
+ // TODO(b/135203078): Remove or use a non-system wide representation of the shared libraries;
+ // this doesn't represent what was parsed from the APK
+ AndroidPackageWrite setUsesLibraryInfos(@Nullable List<SharedLibraryInfo> usesLibraryInfos);
+
+ AndroidPackageWrite setHiddenUntilInstalled(boolean hidden);
+
+ AndroidPackageWrite setUpdatedSystemApp(boolean updatedSystemApp);
+
+ AndroidPackageWrite setLastPackageUsageTimeInMills(int reason, long time);
+
+ AndroidPackageWrite setPrimaryCpuAbi(String primaryCpuAbi);
+
+ AndroidPackageWrite setSeInfo(String seInfo);
+
+ AndroidPackageWrite setSigningDetails(PackageParser.SigningDetails signingDetails);
+}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
new file mode 100644
index 000000000000..ac2e373f000d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import android.annotation.UnsupportedAppUsage;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.VerifierInfo;
+import android.content.res.ApkAssets;
+import android.content.res.XmlResourceParser;
+import android.os.Trace;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** @hide */
+public class ApkLiteParseUtils {
+
+ private static final String TAG = ApkParseUtils.TAG;
+
+ // TODO(b/135203078): Consolidate constants
+ private static final int DEFAULT_MIN_SDK_VERSION = 1;
+ private static final int DEFAULT_TARGET_SDK_VERSION = 0;
+
+ private static final int PARSE_DEFAULT_INSTALL_LOCATION =
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+
+ /**
+ * Parse only lightweight details about the package at the given location.
+ * Automatically detects if the package is a monolithic style (single APK
+ * file) or cluster style (directory of APKs).
+ * <p>
+ * This performs sanity checking on cluster style packages, such as
+ * requiring identical package name and version codes, a single base APK,
+ * and unique split names.
+ *
+ * @see PackageParser#parsePackage(File, int)
+ */
+ @UnsupportedAppUsage
+ public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags)
+ throws PackageParser.PackageParserException {
+ if (packageFile.isDirectory()) {
+ return parseClusterPackageLite(packageFile, flags);
+ } else {
+ return parseMonolithicPackageLite(packageFile, flags);
+ }
+ }
+
+ public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags)
+ throws PackageParser.PackageParserException {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+ final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags);
+ final String packagePath = packageFile.getAbsolutePath();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
+ null, null);
+ }
+
+ public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags)
+ throws PackageParser.PackageParserException {
+ final File[] files = packageDir.listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split");
+ }
+
+ String packageName = null;
+ int versionCode = 0;
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+ final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>();
+ for (File file : files) {
+ if (PackageParser.isApkFile(file)) {
+ final PackageParser.ApkLite lite = parseApkLite(file, flags);
+
+ // Assert that all package names and version codes are
+ // consistent with the first one we encounter.
+ if (packageName == null) {
+ packageName = lite.packageName;
+ versionCode = lite.versionCode;
+ } else {
+ if (!packageName.equals(lite.packageName)) {
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent package " + lite.packageName + " in " + file
+ + "; expected " + packageName);
+ }
+ if (versionCode != lite.versionCode) {
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent version " + lite.versionCode + " in " + file
+ + "; expected " + versionCode);
+ }
+ }
+
+ // Assert that each split is defined only oncuses-static-libe
+ if (apks.put(lite.splitName, lite) != null) {
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Split name " + lite.splitName
+ + " defined more than once; most recent was " + file);
+ }
+ }
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+ final PackageParser.ApkLite baseApk = apks.remove(null);
+ if (baseApk == null) {
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Missing base APK in " + packageDir);
+ }
+
+ // Always apply deterministic ordering based on splitName
+ final int size = apks.size();
+
+ String[] splitNames = null;
+ boolean[] isFeatureSplits = null;
+ String[] usesSplitNames = null;
+ String[] configForSplits = null;
+ String[] splitCodePaths = null;
+ int[] splitRevisionCodes = null;
+ if (size > 0) {
+ splitNames = new String[size];
+ isFeatureSplits = new boolean[size];
+ usesSplitNames = new String[size];
+ configForSplits = new String[size];
+ splitCodePaths = new String[size];
+ splitRevisionCodes = new int[size];
+
+ splitNames = apks.keySet().toArray(splitNames);
+ Arrays.sort(splitNames, PackageParser.sSplitNameComparator);
+
+ for (int i = 0; i < size; i++) {
+ final PackageParser.ApkLite apk = apks.get(splitNames[i]);
+ usesSplitNames[i] = apk.usesSplitName;
+ isFeatureSplits[i] = apk.isFeatureSplit;
+ configForSplits[i] = apk.configForSplit;
+ splitCodePaths[i] = apk.codePath;
+ splitRevisionCodes[i] = apk.revisionCode;
+ }
+ }
+
+ final String codePath = packageDir.getAbsolutePath();
+ return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits,
+ usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes);
+ }
+
+ /**
+ * Utility method that retrieves lightweight details about a single APK
+ * file, including package name, split name, and install location.
+ *
+ * @param apkFile path to a single APK
+ * @param flags optional parse flags, such as
+ * {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
+ */
+ public static PackageParser.ApkLite parseApkLite(File apkFile, int flags)
+ throws PackageParser.PackageParserException {
+ return parseApkLiteInner(apkFile, null, null, flags);
+ }
+
+ /**
+ * Utility method that retrieves lightweight details about a single APK
+ * file, including package name, split name, and install location.
+ *
+ * @param fd already open file descriptor of an apk file
+ * @param debugPathName arbitrary text name for this file, for debug output
+ * @param flags optional parse flags, such as
+ * {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
+ */
+ public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName,
+ int flags) throws PackageParser.PackageParserException {
+ return parseApkLiteInner(null, fd, debugPathName, flags);
+ }
+
+ private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd,
+ String debugPathName, int flags) throws PackageParser.PackageParserException {
+ final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
+
+ XmlResourceParser parser = null;
+ ApkAssets apkAssets = null;
+ try {
+ try {
+ apkAssets = fd != null
+ ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
+ : ApkAssets.loadFromPath(apkPath);
+ } catch (IOException e) {
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+ "Failed to parse " + apkPath, e);
+ }
+
+ parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME);
+
+ final PackageParser.SigningDetails signingDetails;
+ if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
+ final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+ try {
+ signingDetails =
+ ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify,
+ false, PackageParser.SigningDetails.UNKNOWN);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ } else {
+ signingDetails = PackageParser.SigningDetails.UNKNOWN;
+ }
+
+ final AttributeSet attrs = parser;
+ return parseApkLite(apkPath, parser, attrs, signingDetails);
+
+ } catch (XmlPullParserException | IOException | RuntimeException e) {
+ Slog.w(TAG, "Failed to parse " + apkPath, e);
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to parse " + apkPath, e);
+ } finally {
+ IoUtils.closeQuietly(parser);
+ if (apkAssets != null) {
+ try {
+ apkAssets.close();
+ } catch (Throwable ignored) {
+ }
+ }
+ // TODO(b/72056911): Implement AutoCloseable on ApkAssets.
+ }
+ }
+
+ private static PackageParser.ApkLite parseApkLite(
+ String codePath, XmlPullParser parser, AttributeSet attrs,
+ PackageParser.SigningDetails signingDetails)
+ throws IOException, XmlPullParserException, PackageParser.PackageParserException {
+ final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(
+ parser, attrs);
+
+ int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
+ int versionCode = 0;
+ int versionCodeMajor = 0;
+ int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION;
+ int minSdkVersion = DEFAULT_MIN_SDK_VERSION;
+ int revisionCode = 0;
+ boolean coreApp = false;
+ boolean debuggable = false;
+ boolean multiArch = false;
+ boolean use32bitAbi = false;
+ boolean extractNativeLibs = true;
+ boolean isolatedSplits = false;
+ boolean isFeatureSplit = false;
+ boolean isSplitRequired = false;
+ boolean useEmbeddedDex = false;
+ String configForSplit = null;
+ String usesSplitName = null;
+
+ for (int i = 0; i < attrs.getAttributeCount(); i++) {
+ final String attr = attrs.getAttributeName(i);
+ switch (attr) {
+ case "installLocation":
+ installLocation = attrs.getAttributeIntValue(i,
+ PARSE_DEFAULT_INSTALL_LOCATION);
+ break;
+ case "versionCode":
+ versionCode = attrs.getAttributeIntValue(i, 0);
+ break;
+ case "versionCodeMajor":
+ versionCodeMajor = attrs.getAttributeIntValue(i, 0);
+ break;
+ case "revisionCode":
+ revisionCode = attrs.getAttributeIntValue(i, 0);
+ break;
+ case "coreApp":
+ coreApp = attrs.getAttributeBooleanValue(i, false);
+ break;
+ case "isolatedSplits":
+ isolatedSplits = attrs.getAttributeBooleanValue(i, false);
+ break;
+ case "configForSplit":
+ configForSplit = attrs.getAttributeValue(i);
+ break;
+ case "isFeatureSplit":
+ isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
+ break;
+ case "isSplitRequired":
+ isSplitRequired = attrs.getAttributeBooleanValue(i, false);
+ break;
+ }
+ }
+
+ // Only search the tree when the tag is the direct child of <manifest> tag
+ int type;
+ final int searchDepth = parser.getDepth() + 1;
+
+ final List<VerifierInfo> verifiers = new ArrayList<>();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ if (parser.getDepth() != searchDepth) {
+ continue;
+ }
+
+ if (PackageParser.TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
+ final VerifierInfo verifier = parseVerifier(attrs);
+ if (verifier != null) {
+ verifiers.add(verifier);
+ }
+ } else if (PackageParser.TAG_APPLICATION.equals(parser.getName())) {
+ for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+ final String attr = attrs.getAttributeName(i);
+ switch (attr) {
+ case "debuggable":
+ debuggable = attrs.getAttributeBooleanValue(i, false);
+ break;
+ case "multiArch":
+ multiArch = attrs.getAttributeBooleanValue(i, false);
+ break;
+ case "use32bitAbi":
+ use32bitAbi = attrs.getAttributeBooleanValue(i, false);
+ break;
+ case "extractNativeLibs":
+ extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
+ break;
+ case "useEmbeddedDex":
+ useEmbeddedDex = attrs.getAttributeBooleanValue(i, false);
+ break;
+ }
+ }
+ } else if (PackageParser.TAG_USES_SPLIT.equals(parser.getName())) {
+ if (usesSplitName != null) {
+ Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
+ continue;
+ }
+
+ usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name");
+ if (usesSplitName == null) {
+ throw new PackageParser.PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "<uses-split> tag requires 'android:name' attribute");
+ }
+ } else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) {
+ for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+ final String attr = attrs.getAttributeName(i);
+ if ("targetSdkVersion".equals(attr)) {
+ targetSdkVersion = attrs.getAttributeIntValue(i,
+ DEFAULT_TARGET_SDK_VERSION);
+ }
+ if ("minSdkVersion".equals(attr)) {
+ minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
+ }
+ }
+ }
+ }
+
+ return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
+ isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
+ versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
+ coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
+ isolatedSplits, minSdkVersion, targetSdkVersion);
+ }
+
+ public static VerifierInfo parseVerifier(AttributeSet attrs) {
+ String packageName = null;
+ String encodedPublicKey = null;
+
+ final int attrCount = attrs.getAttributeCount();
+ for (int i = 0; i < attrCount; i++) {
+ final int attrResId = attrs.getAttributeNameResource(i);
+ switch (attrResId) {
+ case R.attr.name:
+ packageName = attrs.getAttributeValue(i);
+ break;
+
+ case R.attr.publicKey:
+ encodedPublicKey = attrs.getAttributeValue(i);
+ break;
+ }
+ }
+
+ if (packageName == null || packageName.length() == 0) {
+ Slog.i(TAG, "verifier package name was null; skipping");
+ return null;
+ }
+
+ final PublicKey publicKey = PackageParser.parsePublicKey(encodedPublicKey);
+ if (publicKey == null) {
+ Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
+ return null;
+ }
+
+ return new VerifierInfo(packageName, publicKey);
+ }
+}
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
new file mode 100644
index 000000000000..edbf73a0c0da
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -0,0 +1,3187 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+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_UNEXPECTED_EXCEPTION;
+import static android.os.Build.VERSION_CODES.O;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+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.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.Signature;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
+import android.content.pm.split.DefaultSplitAssetLoader;
+import android.content.pm.split.SplitAssetDependencyLoader;
+import android.content.pm.split.SplitAssetLoader;
+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.FileUtils;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.Trace;
+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.TypedValue;
+import android.util.apk.ApkSignatureVerifier;
+
+import com.android.internal.R;
+import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/** @hide */
+public class ApkParseUtils {
+
+ // TODO(b/135203078): Consolidate log tags
+ static final String TAG = "PackageParsing";
+
+ /**
+ * 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).
+ * <p>
+ * This performs sanity checking on cluster style packages, such as
+ * requiring identical package name and version codes, a single base APK,
+ * and unique split names.
+ * <p>
+ * Note that this <em>does not</em> perform signature verification; that
+ * must be done separately in {@link #collectCertificates(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.
+ *
+ * @see PackageParser#parsePackageLite(File, int)
+ */
+ public static ParsingPackage parsePackage(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ PackageParser.Callback callback,
+ DisplayMetrics displayMetrics,
+ boolean onlyCoreApps,
+ File packageFile,
+ int flags
+ ) throws PackageParserException {
+ if (packageFile.isDirectory()) {
+ return parseClusterPackage(parseInput, separateProcesses, callback, displayMetrics,
+ onlyCoreApps, packageFile, flags);
+ } else {
+ return parseMonolithicPackage(parseInput, separateProcesses, callback, displayMetrics,
+ onlyCoreApps, packageFile, flags);
+ }
+ }
+
+ /**
+ * Parse all APKs contained in the given directory, treating them as a
+ * single package. This also performs sanity checking, such as requiring
+ * identical package name and version codes, a single base APK, and unique
+ * split names.
+ * <p>
+ * Note that this <em>does not</em> perform signature verification; that
+ * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
+ */
+ private static ParsingPackage parseClusterPackage(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ PackageParser.Callback callback,
+ DisplayMetrics displayMetrics,
+ boolean onlyCoreApps,
+ File packageDir,
+ int flags
+ ) throws PackageParserException {
+ final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
+ 0);
+ if (onlyCoreApps && !lite.coreApp) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Not a coreApp: " + packageDir);
+ }
+
+ // Build the split dependency tree.
+ SparseArray<int[]> splitDependencies = null;
+ final SplitAssetLoader assetLoader;
+ if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
+ try {
+ splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
+ assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
+ } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
+ }
+ } else {
+ assetLoader = new DefaultSplitAssetLoader(lite, flags);
+ }
+
+ try {
+ final AssetManager assets = assetLoader.getBaseAssetManager();
+ final File baseApk = new File(lite.baseCodePath);
+ ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback,
+ displayMetrics, baseApk, assets, flags);
+ if (parsingPackage == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Failed to parse base APK: " + baseApk);
+ }
+
+ if (!ArrayUtils.isEmpty(lite.splitNames)) {
+ parsingPackage.asSplit(
+ lite.splitNames,
+ lite.splitCodePaths,
+ lite.splitRevisionCodes,
+ splitDependencies
+ );
+ final int num = lite.splitNames.length;
+
+ for (int i = 0; i < num; i++) {
+ final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
+ parseSplitApk(parseInput, displayMetrics, separateProcesses, parsingPackage, i,
+ splitAssets, flags);
+ }
+ }
+
+ return parsingPackage.setCodePath(packageDir.getCanonicalPath())
+ .setUse32BitAbi(lite.use32bitAbi);
+ } catch (IOException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to get path: " + lite.baseCodePath, e);
+ } finally {
+ IoUtils.closeQuietly(assetLoader);
+ }
+ }
+
+ /**
+ * Parse the given APK file, treating it as as a single monolithic package.
+ * <p>
+ * Note that this <em>does not</em> perform signature verification; that
+ * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}.
+ */
+ public static ParsingPackage parseMonolithicPackage(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ PackageParser.Callback callback,
+ DisplayMetrics displayMetrics,
+ boolean onlyCoreApps,
+ File apkFile,
+ int flags
+ ) throws PackageParserException {
+ final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
+ flags);
+ if (onlyCoreApps) {
+ if (!lite.coreApp) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Not a coreApp: " + apkFile);
+ }
+ }
+
+ final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
+ try {
+ return parseBaseApk(parseInput, separateProcesses, callback,
+ displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags)
+ .setCodePath(apkFile.getCanonicalPath())
+ .setUse32BitAbi(lite.use32bitAbi);
+ } catch (IOException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to get path: " + apkFile, e);
+ } finally {
+ IoUtils.closeQuietly(assetLoader);
+ }
+ }
+
+ private static ParsingPackage parseBaseApk(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ PackageParser.Callback callback,
+ DisplayMetrics displayMetrics,
+ File apkFile,
+ AssetManager assets,
+ int flags
+ ) throws PackageParserException {
+ final String apkPath = apkFile.getAbsolutePath();
+
+ String volumeUuid = null;
+ if (apkPath.startsWith(PackageParser.MNT_EXPAND)) {
+ final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length());
+ volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end);
+ }
+
+ if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
+
+ XmlResourceParser parser = null;
+ try {
+ final int cookie = assets.findCookieForPath(apkPath);
+ if (cookie == 0) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
+ }
+ parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
+ final Resources res = new Resources(assets, displayMetrics, null);
+
+ ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res,
+ parser, flags);
+ if (!result.isSuccess()) {
+ throw new PackageParserException(result.getParseError(),
+ apkPath + " (at " + parser.getPositionDescription() + "): "
+ + result.getErrorMessage());
+ }
+
+ return result.getResultAndNull()
+ .setVolumeUuid(volumeUuid)
+ .setApplicationVolumeUuid(volumeUuid)
+ .setSigningDetails(SigningDetails.UNKNOWN);
+ } catch (PackageParserException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to read manifest from " + apkPath, e);
+ } finally {
+ IoUtils.closeQuietly(parser);
+ }
+ }
+
+ private static void parseSplitApk(
+ ParseInput parseInput,
+ DisplayMetrics displayMetrics,
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ int splitIndex,
+ AssetManager assets,
+ int flags
+ ) throws PackageParserException {
+ final String apkPath = parsingPackage.getSplitCodePaths()[splitIndex];
+
+ if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
+
+ final Resources res;
+ XmlResourceParser parser = null;
+ try {
+ // This must always succeed, as the path has been added to the AssetManager before.
+ final int cookie = assets.findCookieForPath(apkPath);
+ if (cookie == 0) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
+ }
+
+ parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
+ res = new Resources(assets, displayMetrics, null);
+
+ final String[] outError = new String[1];
+ ParseResult parseResult = parseSplitApk(parseInput, separateProcesses, parsingPackage,
+ res, parser, flags, splitIndex, outError);
+ if (!parseResult.isSuccess()) {
+ throw new PackageParserException(parseResult.getParseError(),
+ apkPath + " (at " + parser.getPositionDescription() + "): "
+ + parseResult.getErrorMessage());
+ }
+ } catch (PackageParserException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to read manifest from " + apkPath, e);
+ } finally {
+ IoUtils.closeQuietly(parser);
+ }
+ }
+
+ /**
+ * Parse the manifest of a <em>base APK</em>. 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
+ * @return Parsed package or null on error.
+ */
+ private static ParseResult parseBaseApk(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ PackageParser.Callback callback,
+ String apkPath,
+ Resources res,
+ XmlResourceParser parser,
+ int flags
+ ) throws XmlPullParserException, IOException {
+ final String splitName;
+ final String pkgName;
+
+ try {
+ Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
+ parser);
+ pkgName = packageSplit.first;
+ splitName = packageSplit.second;
+
+ if (!TextUtils.isEmpty(splitName)) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Expected base APK, but found split " + splitName
+ );
+ }
+ } catch (PackageParserException e) {
+ return parseInput.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
+ }
+
+ TypedArray manifestArray = null;
+
+ try {
+ manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
+
+ boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
+
+ ParsingPackage parsingPackage = PackageImpl.forParsing(
+ pkgName,
+ apkPath,
+ manifestArray,
+ isCoreApp
+ );
+
+ ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback,
+ parsingPackage, manifestArray, res, parser, flags);
+ if (!result.isSuccess()) {
+ return result;
+ }
+
+ return parseInput.success(parsingPackage);
+ } finally {
+ if (manifestArray != null) {
+ manifestArray.recycle();
+ }
+ }
+ }
+
+ /**
+ * Parse the manifest of a <em>split APK</em>.
+ * <p>
+ * 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 parsingPackage builder to fill
+ * @return false on failure
+ */
+ private static ParseResult parseSplitApk(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ int flags,
+ int splitIndex,
+ String[] outError
+ ) throws XmlPullParserException, IOException, PackageParserException {
+ AttributeSet attrs = parser;
+
+ // We parsed manifest tag earlier; just skip past it
+ PackageParser.parsePackageSplitNames(parser, attrs);
+
+ int type;
+
+ boolean foundApp = false;
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(PackageParser.TAG_APPLICATION)) {
+ if (foundApp) {
+ if (PackageParser.RIGID_PARSER) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "<manifest> has more than one <application>"
+ );
+ } else {
+ Slog.w(TAG, "<manifest> has more than one <application>");
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+
+ foundApp = true;
+ ParseResult parseResult = parseSplitApplication(parseInput, separateProcesses,
+ parsingPackage, res,
+ parser, flags,
+ splitIndex, outError);
+ if (!parseResult.isSuccess()) {
+ return parseResult;
+ }
+
+ } else if (PackageParser.RIGID_PARSER) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Bad element under <manifest>: " + parser.getName()
+ );
+
+ } else {
+ Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+
+ if (!foundApp) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+ "<manifest> does not contain an <application>"
+ );
+ }
+
+ return parseInput.success(parsingPackage);
+ }
+
+ /**
+ * Parse the {@code application} XML tree at the current parse location in a
+ * <em>split APK</em> manifest.
+ * <p>
+ * 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 static ParseResult parseSplitApplication(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ int flags,
+ int splitIndex,
+ String[] outError
+ ) throws XmlPullParserException, IOException {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
+
+ parsingPackage.setSplitHasCode(splitIndex, sa.getBoolean(
+ R.styleable.AndroidManifestApplication_hasCode, true));
+
+ final String classLoaderName = sa.getString(
+ R.styleable.AndroidManifestApplication_classLoader);
+ if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+ parsingPackage.setSplitClassLoaderName(splitIndex, classLoaderName);
+ } else {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Invalid class loader name: " + classLoaderName
+ );
+ }
+
+ final int innerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ ComponentParseUtils.ParsedComponent parsedComponent = null;
+
+ String tagName = parser.getName();
+ switch (tagName) {
+ case "activity":
+ ComponentParseUtils.ParsedActivity activity =
+ ComponentParseUtils.parseActivity(separateProcesses,
+ parsingPackage,
+ res, parser, flags,
+ outError,
+ false,
+ parsingPackage.isBaseHardwareAccelerated());
+ if (activity == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addActivity(activity);
+ parsedComponent = activity;
+ break;
+ case "receiver":
+ activity = ComponentParseUtils.parseActivity(
+ separateProcesses, parsingPackage,
+ res, parser, flags, outError,
+ true, false);
+ if (activity == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addReceiver(activity);
+ parsedComponent = activity;
+ break;
+ case "service":
+ ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
+ separateProcesses,
+ parsingPackage,
+ res, parser, flags, outError
+ );
+ if (s == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addService(s);
+ parsedComponent = s;
+ break;
+ case "provider":
+ ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
+ separateProcesses,
+ parsingPackage,
+ res, parser, flags, outError);
+ if (p == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addProvider(p);
+ parsedComponent = p;
+ break;
+ case "activity-alias":
+ activity = ComponentParseUtils.parseActivityAlias(
+ parsingPackage,
+ res,
+ parser,
+ outError
+ );
+ if (activity == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addActivity(activity);
+ parsedComponent = activity;
+ break;
+ 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)
+ Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
+ parsingPackage.getAppMetaData(),
+ outError);
+ if (appMetaData == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.setAppMetaData(appMetaData);
+ break;
+ case "uses-static-library":
+ ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
+ res, parser);
+ if (!parseResult.isSuccess()) {
+ return parseResult;
+ }
+
+ break;
+ case "uses-library":
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary);
+
+ // 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);
+
+ sa.recycle();
+
+ if (lname != null) {
+ lname = lname.intern();
+ if (req) {
+ // Upgrade to treat as stronger constraint
+ parsingPackage.addUsesLibrary(lname)
+ .removeUsesOptionalLibrary(lname);
+ } else {
+ // Ignore if someone already defined as required
+ if (!ArrayUtils.contains(parsingPackage.getUsesLibraries(), lname)) {
+ parsingPackage.addUsesOptionalLibrary(lname);
+ }
+ }
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ case "uses-package":
+ // Dependencies for app installers; we don't currently try to
+ // enforce this.
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ default:
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under <application>: " + tagName
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Bad element under <application>: " + tagName
+ );
+ }
+ }
+
+ if (parsedComponent != null && parsedComponent.getSplitName() == null) {
+ // 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.
+ parsedComponent.setSplitName(parsingPackage.getSplitNames()[splitIndex]);
+ }
+ }
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static ParseResult parseBaseApkTags(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ PackageParser.Callback callback,
+ ParsingPackage parsingPackage,
+ TypedArray manifestArray,
+ Resources res,
+ XmlResourceParser parser,
+ int flags
+ ) throws XmlPullParserException, IOException {
+ int type;
+ boolean foundApp = false;
+
+ TypedArray sa = manifestArray;
+
+ ParseResult sharedUserResult = parseSharedUser(parseInput, parsingPackage, sa);
+ if (!sharedUserResult.isSuccess()) {
+ return sharedUserResult;
+ }
+
+ parseManifestAttributes(sa, parsingPackage, flags);
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+
+ // All methods return a boolean, even if they can't fail. This can be enforced
+ // by making this final and not assigned, forcing the switch to assign success
+ // once in every branch.
+ final boolean success;
+ ParseResult parseResult = null;
+
+ // TODO(b/135203078): Either use all booleans or all ParseResults
+ // TODO(b/135203078): Convert to instance methods to share variables
+ switch (tagName) {
+ case PackageParser.TAG_APPLICATION:
+ if (foundApp) {
+ if (PackageParser.RIGID_PARSER) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "<manifest> has more than one <application>"
+ );
+ } else {
+ Slog.w(TAG, "<manifest> has more than one <application>");
+ XmlUtils.skipCurrentTag(parser);
+ success = true;
+ }
+ } else {
+ foundApp = true;
+ parseResult = parseBaseApplication(parseInput, separateProcesses,
+ callback,
+ parsingPackage, res, parser, flags);
+ success = parseResult.isSuccess();
+ }
+ break;
+ case PackageParser.TAG_OVERLAY:
+ parseResult = parseOverlay(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_KEY_SETS:
+ parseResult = parseKeySets(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_PERMISSION_GROUP:
+ parseResult = parsePermissionGroup(parseInput, parsingPackage, res,
+ parser);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_PERMISSION:
+ parseResult = parsePermission(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_PERMISSION_TREE:
+ parseResult = parsePermissionTree(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_USES_PERMISSION:
+ case PackageParser.TAG_USES_PERMISSION_SDK_M:
+ case PackageParser.TAG_USES_PERMISSION_SDK_23:
+ parseResult = parseUsesPermission(parseInput, parsingPackage, res, parser,
+ callback);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_USES_CONFIGURATION:
+ success = parseUsesConfiguration(parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_USES_FEATURE:
+ success = parseUsesFeature(parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_FEATURE_GROUP:
+ success = parseFeatureGroup(parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_USES_SDK:
+ parseResult = parseUsesSdk(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_SUPPORT_SCREENS:
+ success = parseSupportScreens(parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_PROTECTED_BROADCAST:
+ success = parseProtectedBroadcast(parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_INSTRUMENTATION:
+ parseResult = parseInstrumentation(parseInput, parsingPackage, res,
+ parser);
+ success = parseResult.isSuccess();
+ break;
+ case PackageParser.TAG_ORIGINAL_PACKAGE:
+ success = parseOriginalPackage(parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_ADOPT_PERMISSIONS:
+ success = parseAdoptPermissions(parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_USES_GL_TEXTURE:
+ case PackageParser.TAG_COMPATIBLE_SCREENS:
+ case PackageParser.TAG_SUPPORTS_INPUT:
+ case PackageParser.TAG_EAT_COMMENT:
+ // Just skip this tag
+ XmlUtils.skipCurrentTag(parser);
+ success = true;
+ break;
+ case PackageParser.TAG_RESTRICT_UPDATE:
+ success = parseRestrictUpdateHash(flags, parsingPackage, res, parser);
+ break;
+ case PackageParser.TAG_QUERIES:
+ parseResult = parseQueries(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
+ default:
+ parseResult = parseUnknownTag(parseInput, parsingPackage, parser);
+ success = parseResult.isSuccess();
+ break;
+ }
+
+ if (parseResult != null && !parseResult.isSuccess()) {
+ return parseResult;
+ }
+
+ if (!success) {
+ return parseResult;
+ }
+ }
+
+ if (!foundApp && ArrayUtils.size(parsingPackage.getInstrumentations()) == 0) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+ "<manifest> does not contain an <application> or <instrumentation>"
+ );
+ }
+
+ convertNewPermissions(parsingPackage);
+
+ convertSplitPermissions(parsingPackage);
+
+ // 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 (parsingPackage.usesCompatibilityMode()) {
+ adjustPackageToBeUnresizeableAndUnpipable(parsingPackage);
+ }
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static ParseResult parseUnknownTag(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ if (PackageParser.RIGID_PARSER) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Bad element under <manifest>: " + parser.getName()
+ );
+ } else {
+ Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ return parseInput.success(parsingPackage);
+ }
+ }
+
+ private static ParseResult parseSharedUser(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ TypedArray manifestArray
+ ) {
+ String str = manifestArray.getNonConfigurationString(
+ R.styleable.AndroidManifest_sharedUserId, 0);
+ if (TextUtils.isEmpty(str)) {
+ return parseInput.success(parsingPackage);
+ }
+
+ String nameError = validateName(str, true, true);
+ if (nameError != null && !"android".equals(parsingPackage.getPackageName())) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+ "<manifest> specifies bad sharedUserId name \"" + str + "\": "
+ + nameError
+ );
+ }
+
+ int sharedUserLabel = manifestArray.getResourceId(
+ R.styleable.AndroidManifest_sharedUserLabel, 0);
+ parsingPackage.setSharedUserId(str.intern())
+ .setSharedUserLabel(sharedUserLabel);
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static void parseManifestAttributes(
+ TypedArray manifestArray,
+ ParsingPackage parsingPackage,
+ int flags
+ ) {
+ int installLocation = manifestArray.getInteger(R.styleable.AndroidManifest_installLocation,
+ PackageParser.PARSE_DEFAULT_INSTALL_LOCATION);
+
+ final int targetSandboxVersion = manifestArray.getInteger(
+ R.styleable.AndroidManifest_targetSandboxVersion,
+ PackageParser.PARSE_DEFAULT_TARGET_SANDBOX);
+
+ parsingPackage.setInstallLocation(installLocation)
+ .setTargetSandboxVersion(targetSandboxVersion);
+
+ /* Set the global "on SD card" flag */
+ parsingPackage.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0);
+
+ parsingPackage.setIsolatedSplitLoading(manifestArray.getBoolean(
+ R.styleable.AndroidManifest_isolatedSplits, false));
+ }
+
+ private static ParseResult parseKeySets(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ 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<String, PublicKey> publicKeys = new ArrayMap<>();
+ ArraySet<String> upgradeKeySets = new ArraySet<>();
+ ArrayMap<String, ArraySet<String>> definedKeySets =
+ new ArrayMap<>();
+ ArraySet<String> 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();
+ if (tagName.equals("key-set")) {
+ if (currentKeySet != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
+ );
+ }
+ final TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestKeySet);
+ final String keysetName = sa.getNonResourceString(
+ R.styleable.AndroidManifestKeySet_name);
+ definedKeySets.put(keysetName, new ArraySet<>());
+ currentKeySet = keysetName;
+ currentKeySetDepth = parser.getDepth();
+ sa.recycle();
+ } else if (tagName.equals("public-key")) {
+ if (currentKeySet == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
+ );
+ }
+ final TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestPublicKey);
+ final String publicKeyName = sa.getNonResourceString(
+ R.styleable.AndroidManifestPublicKey_name);
+ final String encodedKey = sa.getNonResourceString(
+ R.styleable.AndroidManifestPublicKey_value);
+ if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
+ sa.recycle();
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "'public-key' " + publicKeyName + " must define a public-key value"
+ + " on first use at " + parser.getPositionDescription()
+ );
+ } else if (encodedKey != null) {
+ PublicKey currentKey = PackageParser.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.");
+ sa.recycle();
+ 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 {
+ sa.recycle();
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Value of 'public-key' " + publicKeyName
+ + " conflicts with previously defined value at "
+ + parser.getPositionDescription()
+ );
+ }
+ }
+ definedKeySets.get(currentKeySet).add(publicKeyName);
+ sa.recycle();
+ XmlUtils.skipCurrentTag(parser);
+ } else if (tagName.equals("upgrade-key-set")) {
+ final TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestUpgradeKeySet);
+ String name = sa.getNonResourceString(
+ R.styleable.AndroidManifestUpgradeKeySet_name);
+ upgradeKeySets.add(name);
+ sa.recycle();
+ XmlUtils.skipCurrentTag(parser);
+ } else if (PackageParser.RIGID_PARSER) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Bad element under <key-sets>: " + parser.getName()
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription()
+ );
+ } else {
+ Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+ String packageName = parsingPackage.getPackageName();
+ Set<String> publicKeyNames = publicKeys.keySet();
+ if (publicKeyNames.removeAll(definedKeySets.keySet())) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Package" + packageName + " AndroidManifest.xml "
+ + "'key-set' and 'public-key' names must be distinct."
+ );
+ }
+
+ for (ArrayMap.Entry<String, ArraySet<String>> 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()) {
+ parsingPackage.addKeySet(keySetName, publicKeys.get(s));
+ }
+ }
+ if (parsingPackage.getKeySetMapping().keySet().containsAll(upgradeKeySets)) {
+ parsingPackage.setUpgradeKeySets(upgradeKeySets);
+ } else {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Package" + packageName + " AndroidManifest.xml "
+ + "does not define all 'upgrade-key-set's ."
+ );
+ }
+
+ return parseInput.success(parsingPackage);
+ }
+
+ public static boolean parsePackageItemInfo(String packageName, PackageItemInfo outInfo,
+ String[] outError, String tag, TypedArray sa, boolean nameRequired,
+ int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
+ // This case can only happen in unit tests where we sometimes need to create fakes
+ // of various package parser data structures.
+ if (sa == null) {
+ outError[0] = tag + " does not contain any attributes";
+ return false;
+ }
+
+ String name = sa.getNonConfigurationString(nameRes, 0);
+ if (name == null) {
+ if (nameRequired) {
+ outError[0] = tag + " does not specify android:name";
+ return false;
+ }
+ } else {
+ String outInfoName = buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
+ outError[0] = tag + " invalid android:name";
+ return false;
+ }
+ outInfo.name = outInfoName;
+ if (outInfoName == null) {
+ return false;
+ }
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+ if (roundIconVal != 0) {
+ outInfo.icon = roundIconVal;
+ outInfo.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(iconRes, 0);
+ if (iconVal != 0) {
+ outInfo.icon = iconVal;
+ outInfo.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(logoRes, 0);
+ if (logoVal != 0) {
+ outInfo.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(bannerRes, 0);
+ if (bannerVal != 0) {
+ outInfo.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(labelRes);
+ if (v != null && (outInfo.labelRes = v.resourceId) == 0) {
+ outInfo.nonLocalizedLabel = v.coerceToString();
+ }
+
+ outInfo.packageName = packageName;
+
+ return true;
+ }
+
+ private static ParseResult parsePackageItemInfo(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ String tag,
+ TypedArray sa,
+ boolean nameRequired,
+ int nameRes,
+ int labelRes,
+ int iconRes,
+ int roundIconRes,
+ int logoRes,
+ int bannerRes
+ ) {
+ // 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 parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ tag + " does not contain any attributes"
+ );
+ }
+
+ String name = sa.getNonConfigurationString(nameRes, 0);
+ if (name == null) {
+ if (nameRequired) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ tag + " does not specify android:name"
+ );
+ }
+ } else {
+ String packageName = parsingPackage.getPackageName();
+ String outInfoName = buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ tag + " invalid android:name"
+ );
+ } else if (outInfoName == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Empty class name in package " + packageName
+ );
+ }
+
+ parsingPackage.setName(outInfoName);
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+ if (roundIconVal != 0) {
+ parsingPackage.setIcon(roundIconVal)
+ .setNonLocalizedLabel(null);
+ } else {
+ int iconVal = sa.getResourceId(iconRes, 0);
+ if (iconVal != 0) {
+ parsingPackage.setIcon(iconVal)
+ .setNonLocalizedLabel(null);
+ }
+ }
+
+ int logoVal = sa.getResourceId(logoRes, 0);
+ if (logoVal != 0) {
+ parsingPackage.setLogo(logoVal);
+ }
+
+ int bannerVal = sa.getResourceId(bannerRes, 0);
+ if (bannerVal != 0) {
+ parsingPackage.setBanner(bannerVal);
+ }
+
+ TypedValue v = sa.peekValue(labelRes);
+ if (v != null) {
+ parsingPackage.setLabelRes(v.resourceId);
+ if (v.resourceId == 0) {
+ parsingPackage.setNonLocalizedLabel(v.coerceToString());
+ }
+ }
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static ParseResult parsePermissionGroup(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws XmlPullParserException, IOException {
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+
+ ComponentParseUtils.ParsedPermissionGroup parsedPermissionGroup =
+ ComponentParseUtils.parsePermissionGroup(parsingPackage,
+ res, parser, outError);
+
+ if (parsedPermissionGroup == null || outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addPermissionGroup(parsedPermissionGroup);
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static ParseResult parsePermission(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws XmlPullParserException, IOException {
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+
+ ComponentParseUtils.ParsedPermission parsedPermission =
+ ComponentParseUtils.parsePermission(parsingPackage,
+ res, parser, outError);
+
+ if (parsedPermission == null || outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addPermission(parsedPermission);
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static ParseResult parsePermissionTree(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws XmlPullParserException, IOException {
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+
+ ComponentParseUtils.ParsedPermission parsedPermission =
+ ComponentParseUtils.parsePermissionTree(parsingPackage,
+ res, parser, outError);
+
+ if (parsedPermission == null || outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addPermission(parsedPermission);
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static ParseResult parseUsesPermission(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ PackageParser.Callback callback
+ )
+ throws XmlPullParserException, IOException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestUsesPermission);
+
+ // Note: don't allow this value to be a reference to a resource
+ // that may change.
+ String name = sa.getNonResourceString(
+ R.styleable.AndroidManifestUsesPermission_name);
+
+ int maxSdkVersion = 0;
+ TypedValue val = sa.peekValue(
+ R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+ if (val != null) {
+ if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+ maxSdkVersion = val.data;
+ }
+ }
+
+ final String requiredFeature = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+
+ final String requiredNotfeature = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
+ 0);
+
+ sa.recycle();
+
+ XmlUtils.skipCurrentTag(parser);
+
+ // Can only succeed from here on out
+ ParseResult success = parseInput.success(parsingPackage);
+
+ if (name == null) {
+ return success;
+ }
+
+ if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
+ return success;
+ }
+
+ // Only allow requesting this permission if the platform supports the given feature.
+ if (requiredFeature != null && callback != null && !callback.hasFeature(requiredFeature)) {
+ return success;
+ }
+
+ // Only allow requesting this permission if the platform doesn't support the given feature.
+ if (requiredNotfeature != null && callback != null
+ && callback.hasFeature(requiredNotfeature)) {
+ return success;
+ }
+
+ if (!parsingPackage.getRequestedPermissions().contains(name)) {
+ parsingPackage.addRequestedPermission(name.intern());
+ } else {
+ Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+ + name + " in package: " + parsingPackage.getPackageName() + " at: "
+ + parser.getPositionDescription());
+ }
+
+ return success;
+ }
+
+ private static boolean parseUsesConfiguration(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ ConfigurationInfo cPref = new ConfigurationInfo();
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestUsesConfiguration);
+ 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;
+ }
+ sa.recycle();
+ parsingPackage.addConfigPreference(cPref);
+
+ XmlUtils.skipCurrentTag(parser);
+ return true;
+ }
+
+ private static boolean parseUsesFeature(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ FeatureInfo fi = parseFeatureInfo(res, parser);
+ parsingPackage.addReqFeature(fi);
+
+ if (fi.name == null) {
+ ConfigurationInfo cPref = new ConfigurationInfo();
+ cPref.reqGlEsVersion = fi.reqGlEsVersion;
+ parsingPackage.addConfigPreference(cPref);
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ return true;
+ }
+
+ private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) {
+ FeatureInfo fi = new FeatureInfo();
+ TypedArray sa = res.obtainAttributes(attrs,
+ R.styleable.AndroidManifestUsesFeature);
+ // 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;
+ }
+ sa.recycle();
+ return fi;
+ }
+
+ private static boolean parseFeatureGroup(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ FeatureGroupInfo group = new FeatureGroupInfo();
+ ArrayList<FeatureInfo> features = null;
+ final int innerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ final String innerTagName = parser.getName();
+ if (innerTagName.equals("uses-feature")) {
+ FeatureInfo featureInfo = parseFeatureInfo(res, parser);
+ // FeatureGroups are stricter and mandate that
+ // any <uses-feature> declared are mandatory.
+ featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
+ features = ArrayUtils.add(features, featureInfo);
+ } else {
+ Slog.w(TAG,
+ "Unknown element under <feature-group>: " + innerTagName +
+ " at " + parsingPackage.getBaseCodePath() + " " +
+ parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ if (features != null) {
+ group.features = new FeatureInfo[features.size()];
+ group.features = features.toArray(group.features);
+ }
+
+ parsingPackage.addFeatureGroup(group);
+ return true;
+ }
+
+ private static ParseResult parseUsesSdk(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ if (PackageParser.SDK_VERSION > 0) {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestUsesSdk);
+
+ int minVers = 1;
+ String minCode = null;
+ int targetVers = 0;
+ String targetCode = null;
+
+ TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+ if (val != null) {
+ if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+ minCode = val.string.toString();
+ } else {
+ // If it's not a string, it's an integer.
+ minVers = val.data;
+ }
+ }
+
+ val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+ if (val != null) {
+ if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+ targetCode = val.string.toString();
+ if (minCode == null) {
+ minCode = targetCode;
+ }
+ } else {
+ // If it's not a string, it's an integer.
+ targetVers = val.data;
+ }
+ } else {
+ targetVers = minVers;
+ targetCode = minCode;
+ }
+
+ sa.recycle();
+
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+ final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers,
+ minCode,
+ PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, outError);
+ if (minSdkVersion < 0) {
+ return parseInput.error(
+ PackageManager.INSTALL_FAILED_OLDER_SDK
+ );
+ }
+
+ final int targetSdkVersion = PackageParser.computeTargetSdkVersion(
+ targetVers,
+ targetCode, PackageParser.SDK_CODENAMES, outError);
+ if (targetSdkVersion < 0) {
+ return parseInput.error(
+ PackageManager.INSTALL_FAILED_OLDER_SDK
+ );
+ }
+
+ parsingPackage.setMinSdkVersion(minSdkVersion)
+ .setTargetSdkVersion(targetSdkVersion);
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ return parseInput.success(parsingPackage);
+ }
+
+ private static boolean parseRestrictUpdateHash(
+ int flags,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestRestrictUpdate);
+ final String hash = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestRestrictUpdate_hash,
+ 0);
+ sa.recycle();
+
+ 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));
+ }
+ parsingPackage.setRestrictUpdateHash(hashBytes);
+ } else {
+ parsingPackage.setRestrictUpdateHash(null);
+ }
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ return true;
+ }
+
+ private static ParseResult parseQueries(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+
+ 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;
+ }
+ if (parser.getName().equals("intent")) {
+ String[] outError = new String[1];
+ ComponentParseUtils.ParsedQueriesIntentInfo intentInfo =
+ ComponentParseUtils.parsedParsedQueriesIntentInfo(
+ parsingPackage, res, parser, outError
+ );
+ if (intentInfo == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ Uri data = null;
+ String dataType = null;
+ String host = "";
+ 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)) {
+ outError[0] = "intent tags must contain either an action or data.";
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+ if (numActions > 1) {
+ outError[0] = "intent tag may have at most one action.";
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+ if (numTypes > 1) {
+ outError[0] = "intent tag may have at most one data type.";
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+ if (numSchemes > 1) {
+ outError[0] = "intent tag may have at most one data scheme.";
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+ if (numHosts > 1) {
+ outError[0] = "intent tag may have at most one data host.";
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+ 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)
+ .build();
+ }
+ if (numTypes == 1) {
+ dataType = intentInfo.getDataType(0);
+ }
+ intent.setDataAndType(data, dataType);
+ if (numActions == 1) {
+ intent.setAction(intentInfo.getAction(0));
+ }
+ parsingPackage.addQueriesIntent(intent);
+ } else if (parser.getName().equals("package")) {
+ final TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestQueriesPackage);
+ final String packageName =
+ sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
+ if (TextUtils.isEmpty(packageName)) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Package name is missing from package tag."
+ );
+ }
+ parsingPackage.addQueriesPackage(packageName.intern());
+ }
+ }
+ return parseInput.success(parsingPackage);
+ }
+
+ /**
+ * Parse the {@code application} XML tree at the current parse location in a
+ * <em>base APK</em> manifest.
+ * <p>
+ * When adding new features, carefully consider if they should also be
+ * supported by split APKs.
+ *
+ * @hide
+ */
+ public static ParseResult parseBaseApplication(
+ ParseInput parseInput,
+ String[] separateProcesses,
+ PackageParser.Callback callback,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ int flags
+ ) throws XmlPullParserException, IOException {
+ final String pkgName = parsingPackage.getPackageName();
+
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+ TypedArray sa = null;
+
+ try {
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestApplication);
+
+
+ parsingPackage
+ .setIconRes(
+ sa.getResourceId(R.styleable.AndroidManifestApplication_icon, 0))
+ .setRoundIconRes(
+ sa.getResourceId(R.styleable.AndroidManifestApplication_roundIcon, 0));
+
+ ParseResult result = parsePackageItemInfo(
+ parseInput,
+ parsingPackage,
+ "<application>",
+ sa, false /*nameRequired*/,
+ R.styleable.AndroidManifestApplication_name,
+ R.styleable.AndroidManifestApplication_label,
+ R.styleable.AndroidManifestApplication_icon,
+ R.styleable.AndroidManifestApplication_roundIcon,
+ R.styleable.AndroidManifestApplication_logo,
+ R.styleable.AndroidManifestApplication_banner
+ );
+ if (!result.isSuccess()) {
+ return result;
+ }
+
+ String name = parsingPackage.getName();
+ if (name != null) {
+ parsingPackage.setClassName(name);
+ }
+
+ String manageSpaceActivity = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestApplication_manageSpaceActivity,
+ Configuration.NATIVE_CONFIG_VERSION);
+ if (manageSpaceActivity != null) {
+ String manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity);
+
+ if (manageSpaceActivityName == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Empty class name in package " + pkgName
+ );
+ }
+
+ parsingPackage.setManageSpaceActivityName(manageSpaceActivityName);
+ }
+
+ boolean allowBackup = sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowBackup, true);
+ parsingPackage.setAllowBackup(allowBackup);
+
+ if (allowBackup) {
+ // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
+ // and restoreAnyVersion are only relevant if backup is possible for the
+ // given application.
+ String backupAgent = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestApplication_backupAgent,
+ Configuration.NATIVE_CONFIG_VERSION);
+ if (backupAgent != null) {
+ String backupAgentName = buildClassName(pkgName, backupAgent);
+ if (backupAgentName == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Empty class name in package " + pkgName
+ );
+ }
+
+ if (PackageParser.DEBUG_BACKUP) {
+ Slog.v(TAG, "android:backupAgent = " + backupAgentName
+ + " from " + pkgName + "+" + backupAgent);
+ }
+
+ parsingPackage.setBackupAgentName(backupAgentName);
+
+ parsingPackage.setKillAfterRestore(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_killAfterRestore, true));
+
+ parsingPackage.setRestoreAnyVersion(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_restoreAnyVersion, false));
+
+ parsingPackage.setFullBackupOnly(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_fullBackupOnly, false));
+
+ parsingPackage.setBackupInForeground(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_backupInForeground,
+ false));
+ }
+
+ TypedValue v = sa.peekValue(
+ R.styleable.AndroidManifestApplication_fullBackupContent);
+ int fullBackupContent = 0;
+
+ if (v != null) {
+ fullBackupContent = v.resourceId;
+
+ if (v.resourceId == 0) {
+ if (PackageParser.DEBUG_BACKUP) {
+ Slog.v(TAG, "fullBackupContent specified as boolean=" +
+ (v.data == 0 ? "false" : "true"));
+ }
+ // "false" => -1, "true" => 0
+ fullBackupContent = v.data == 0 ? -1 : 0;
+ }
+
+ parsingPackage.setFullBackupContent(fullBackupContent);
+ }
+ if (PackageParser.DEBUG_BACKUP) {
+ Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
+ }
+ }
+
+ parsingPackage
+ .setTheme(
+ sa.getResourceId(R.styleable.AndroidManifestApplication_theme, 0))
+ .setDescriptionRes(
+ sa.getResourceId(R.styleable.AndroidManifestApplication_description,
+ 0));
+
+ 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);
+ parsingPackage.setPersistent(requiredFeature == null
+ || callback.hasFeature(requiredFeature));
+ }
+
+ boolean requiredForAllUsers = sa.getBoolean(
+ R.styleable.AndroidManifestApplication_requiredForAllUsers,
+ false);
+ parsingPackage.setRequiredForAllUsers(requiredForAllUsers);
+
+ String restrictedAccountType = sa.getString(R.styleable
+ .AndroidManifestApplication_restrictedAccountType);
+ if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
+ parsingPackage.setRestrictedAccountType(restrictedAccountType);
+ }
+
+ String requiredAccountType = sa.getString(R.styleable
+ .AndroidManifestApplication_requiredAccountType);
+ if (requiredAccountType != null && requiredAccountType.length() > 0) {
+ parsingPackage.setRequiredAccountType(requiredAccountType);
+ }
+
+ parsingPackage.setForceQueryable(
+ sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false)
+ );
+
+ boolean debuggable = sa.getBoolean(
+ R.styleable.AndroidManifestApplication_debuggable,
+ false
+ );
+
+ parsingPackage.setDebuggable(debuggable);
+
+ if (debuggable) {
+ // Debuggable implies profileable
+ parsingPackage.setProfileableByShell(true);
+ }
+
+ parsingPackage.setVmSafeMode(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_vmSafeMode, false));
+
+ boolean baseHardwareAccelerated = sa.getBoolean(
+ R.styleable.AndroidManifestApplication_hardwareAccelerated,
+ parsingPackage.getTargetSdkVersion()
+ >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
+ parsingPackage.setBaseHardwareAccelerated(baseHardwareAccelerated);
+
+ parsingPackage.setHasCode(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_hasCode, true));
+
+ parsingPackage.setAllowTaskReparenting(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowTaskReparenting, false));
+
+ parsingPackage.setAllowClearUserData(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowClearUserData, true));
+
+ parsingPackage.setTestOnly(sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
+ false));
+
+ parsingPackage.setLargeHeap(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_largeHeap, false));
+
+ parsingPackage.setUsesCleartextTraffic(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_usesCleartextTraffic,
+ parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.P));
+
+ parsingPackage.setSupportsRtl(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_supportsRtl,
+ false /* default is no RTL support*/));
+
+ parsingPackage.setMultiArch(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_multiArch, false));
+
+ parsingPackage.setExtractNativeLibs(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_extractNativeLibs, true));
+
+ parsingPackage.setUseEmbeddedDex(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_useEmbeddedDex, false));
+
+ parsingPackage.setDefaultToDeviceProtectedStorage(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
+ false));
+
+ parsingPackage.setDirectBootAware(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_directBootAware, false));
+
+ if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
+ parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_resizeableActivity, true));
+ } else {
+ parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion(
+ parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N);
+ }
+
+ parsingPackage.setAllowClearUserDataOnFailedRestore(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore,
+ true));
+
+
+ parsingPackage.setAllowAudioPlaybackCapture(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture,
+ parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q));
+
+ parsingPackage.setRequestLegacyExternalStorage(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
+ parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q));
+
+ parsingPackage
+ .setMaxAspectRatio(
+ sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0))
+ .setMinAspectRatio(
+ sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0))
+ .setNetworkSecurityConfigRes(sa.getResourceId(
+ R.styleable.AndroidManifestApplication_networkSecurityConfig, 0))
+ .setCategory(sa.getInt(R.styleable.AndroidManifestApplication_appCategory,
+ ApplicationInfo.CATEGORY_UNDEFINED));
+
+ String str;
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestApplication_permission, 0);
+ parsingPackage.setPermission((str != null && str.length() > 0) ? str.intern() : null);
+
+ if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+ str = 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.
+ str = sa.getNonResourceString(
+ R.styleable.AndroidManifestApplication_taskAffinity);
+ }
+ String packageName = parsingPackage.getPackageName();
+ String taskAffinity = PackageParser.buildTaskAffinityName(packageName,
+ packageName,
+ str, outError);
+
+ if (outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.setTaskAffinity(taskAffinity);
+ String factory = sa.getNonResourceString(
+ R.styleable.AndroidManifestApplication_appComponentFactory);
+ if (factory != null) {
+ String appComponentFactory = buildClassName(packageName, factory);
+ if (appComponentFactory == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Empty class name in package " + pkgName
+ );
+ }
+
+ parsingPackage.setAppComponentFactory(appComponentFactory);
+ }
+
+ parsingPackage.setUsesNonSdkApi(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_usesNonSdkApi, false));
+
+ parsingPackage.setHasFragileUserData(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_hasFragileUserData, false));
+
+ CharSequence pname;
+ if (parsingPackage.getTargetSdkVersion() >= 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);
+ }
+ String processName = PackageParser.buildProcessName(packageName, null, pname, flags,
+ separateProcesses, outError);
+
+ if (outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage
+ .setProcessName(processName)
+ .setEnabled(
+ sa.getBoolean(R.styleable.AndroidManifestApplication_enabled,
+ true));
+
+ parsingPackage.setIsGame(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_isGame, false));
+
+ boolean cantSaveState = sa.getBoolean(
+ R.styleable.AndroidManifestApplication_cantSaveState, false);
+ parsingPackage.setCantSaveState(cantSaveState);
+ if (cantSaveState) {
+ // 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(packageName)) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "cantSaveState applications can not use custom processes"
+ );
+ }
+ }
+
+ String classLoaderName = sa.getString(
+ R.styleable.AndroidManifestApplication_classLoader);
+ parsingPackage
+ .setUiOptions(sa.getInt(R.styleable.AndroidManifestApplication_uiOptions, 0))
+ .setClassLoaderName(classLoaderName)
+ .setZygotePreloadName(
+ sa.getString(R.styleable.AndroidManifestApplication_zygotePreloadName));
+
+ if (classLoaderName != null
+ && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Invalid class loader name: " + classLoaderName
+ );
+ }
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+ final int innerDepth = parser.getDepth();
+ int type;
+ boolean hasActivityOrder = false;
+ boolean hasReceiverOrder = false;
+ boolean hasServiceOrder = false;
+
+ 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();
+ switch (tagName) {
+ case "activity":
+ ComponentParseUtils.ParsedActivity activity =
+ ComponentParseUtils.parseActivity(separateProcesses,
+ parsingPackage,
+ res, parser, flags,
+ outError, false,
+ parsingPackage.isBaseHardwareAccelerated());
+ if (activity == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ hasActivityOrder |= (activity.order != 0);
+ parsingPackage.addActivity(activity);
+ break;
+ case "receiver":
+ activity = ComponentParseUtils.parseActivity(separateProcesses,
+ parsingPackage,
+ res, parser,
+ flags, outError,
+ true, false);
+ if (activity == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ hasReceiverOrder |= (activity.order != 0);
+ parsingPackage.addReceiver(activity);
+ break;
+ case "service":
+ ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
+ separateProcesses,
+ parsingPackage,
+ res, parser, flags,
+ outError);
+ if (s == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ hasServiceOrder |= (s.order != 0);
+ parsingPackage.addService(s);
+ break;
+ case "provider":
+ ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
+ separateProcesses,
+ parsingPackage,
+ res, parser, flags,
+ outError
+ );
+ if (p == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addProvider(p);
+ break;
+ case "activity-alias":
+ activity = ComponentParseUtils.parseActivityAlias(
+ parsingPackage,
+ res,
+ parser,
+ outError
+ );
+ if (activity == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ hasActivityOrder |= (activity.order != 0);
+ parsingPackage.addActivity(activity);
+ break;
+ 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)
+ Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
+ parsingPackage.getAppMetaData(),
+ outError);
+ if (appMetaData == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.setAppMetaData(appMetaData);
+ break;
+ case "static-library":
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestStaticLibrary);
+
+ // 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);
+
+ sa.recycle();
+
+ // Since the app canot run without a static lib - fail if malformed
+ if (lname == null || version < 0) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Bad static-library declaration name: " + lname
+ + " version: " + version
+ );
+ }
+
+ if (parsingPackage.getSharedUserId() != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+ "sharedUserId not allowed in static shared library"
+ );
+ }
+
+ if (parsingPackage.getStaticSharedLibName() != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Multiple static-shared libs for package " + pkgName
+ );
+ }
+
+ parsingPackage.setStaticSharedLibName(lname.intern());
+ if (version >= 0) {
+ parsingPackage.setStaticSharedLibVersion(
+ PackageInfo.composeLongVersionCode(versionMajor, version));
+ } else {
+ parsingPackage.setStaticSharedLibVersion(version);
+ }
+ parsingPackage.setStaticSharedLibrary(true);
+
+ XmlUtils.skipCurrentTag(parser);
+
+ break;
+ case "library":
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestLibrary);
+
+ // Note: don't allow this value to be a reference to a resource
+ // that may change.
+ lname = sa.getNonResourceString(
+ R.styleable.AndroidManifestLibrary_name);
+
+ sa.recycle();
+
+ if (lname != null) {
+ lname = lname.intern();
+ if (!ArrayUtils.contains(parsingPackage.getLibraryNames(), lname)) {
+ parsingPackage.addLibraryName(lname);
+ }
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+
+ break;
+ case "uses-static-library":
+ ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
+ res, parser);
+ if (!parseResult.isSuccess()) {
+ return parseResult;
+ }
+ break;
+ case "uses-library":
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestUsesLibrary);
+
+ // Note: don't allow this value to be a reference to a resource
+ // that may change.
+ lname = sa.getNonResourceString(
+ R.styleable.AndroidManifestUsesLibrary_name);
+ boolean req = sa.getBoolean(
+ R.styleable.AndroidManifestUsesLibrary_required,
+ true);
+
+ sa.recycle();
+
+ if (lname != null) {
+ lname = lname.intern();
+ if (req) {
+ parsingPackage.addUsesLibrary(lname);
+ } else {
+ parsingPackage.addUsesOptionalLibrary(lname);
+ }
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+
+ break;
+ case "uses-package":
+ // Dependencies for app installers; we don't currently try to
+ // enforce this.
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ case "profileable":
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestProfileable);
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestProfileable_shell, false)) {
+ parsingPackage.setProfileableByShell(true);
+ }
+ XmlUtils.skipCurrentTag(parser);
+
+ default:
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under <application>: " + tagName
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Bad element under <application>: " + tagName
+ );
+ }
+ }
+ }
+
+ if (TextUtils.isEmpty(parsingPackage.getStaticSharedLibName())) {
+ // Add a hidden app detail activity to normal apps which forwards user to App Details
+ // page.
+ ComponentParseUtils.ParsedActivity a = generateAppDetailsHiddenActivity(
+ parsingPackage,
+ outError
+ );
+ // Ignore errors here
+ parsingPackage.addActivity(a);
+ }
+
+ if (hasActivityOrder) {
+ parsingPackage.sortActivities();
+ }
+ if (hasReceiverOrder) {
+ parsingPackage.sortReceivers();
+ }
+ if (hasServiceOrder) {
+ parsingPackage.sortServices();
+ }
+ // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
+ // every activity info has had a chance to set it from its attributes.
+ setMaxAspectRatio(parsingPackage);
+ setMinAspectRatio(parsingPackage, callback);
+
+ parsingPackage.setHasDomainUrls(hasDomainURLs(parsingPackage));
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static ParseResult parseUsesStaticLibrary(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws XmlPullParserException, IOException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestUsesStaticLibrary);
+
+ // 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(com.android.internal.R.styleable
+ .AndroidManifestUsesStaticLibrary_certDigest);
+ sa.recycle();
+
+ // Since an APK providing a static shared lib can only provide the lib - fail if malformed
+ if (lname == null || version < 0 || certSha256Digest == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Bad uses-static-library declaration name: " + lname + " version: "
+ + version + " certDigest" + certSha256Digest
+ );
+ }
+
+ // Can depend only on one version of the same library
+ List<String> usesStaticLibraries = parsingPackage.getUsesStaticLibraries();
+ if (usesStaticLibraries != null && usesStaticLibraries.contains(lname)) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "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 (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) {
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+ additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError);
+ if (additionalCertSha256Digests == null || outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
+ certSha256Digests[0] = certSha256Digest;
+ System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
+ 1, additionalCertSha256Digests.length);
+
+ parsingPackage.addUsesStaticLibrary(lname)
+ .addUsesStaticLibraryVersion(version)
+ .addUsesStaticLibraryCertDigests(certSha256Digests);
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static String[] parseAdditionalCertificates(
+ Resources resources,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws XmlPullParserException, IOException {
+ String[] certSha256Digests = EmptyArray.STRING;
+
+ 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 String nodeName = parser.getName();
+ if (nodeName.equals("additional-certificate")) {
+ final TypedArray sa = resources.obtainAttributes(parser, com.android.internal.
+ R.styleable.AndroidManifestAdditionalCertificate);
+ String certSha256Digest = sa.getNonResourceString(com.android.internal.
+ R.styleable.AndroidManifestAdditionalCertificate_certDigest);
+ sa.recycle();
+
+ if (TextUtils.isEmpty(certSha256Digest)) {
+ outError[0] = "Bad additional-certificate declaration with empty"
+ + " certDigest:" + certSha256Digest;
+ XmlUtils.skipCurrentTag(parser);
+ sa.recycle();
+ return null;
+ }
+
+ // 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);
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ return 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.
+ *
+ * @hide
+ */
+ @NonNull
+ private static ComponentParseUtils.ParsedActivity generateAppDetailsHiddenActivity(
+ ParsingPackage parsingPackage,
+ String[] outError
+ ) {
+ String packageName = parsingPackage.getPackageName();
+ String processName = parsingPackage.getProcessName();
+ boolean hardwareAccelerated = parsingPackage.isBaseHardwareAccelerated();
+ int uiOptions = parsingPackage.getUiOptions();
+
+ // Build custom App Details activity info instead of parsing it from xml
+ ComponentParseUtils.ParsedActivity activity = new ComponentParseUtils.ParsedActivity();
+ activity.setPackageName(packageName);
+
+ activity.theme = android.R.style.Theme_NoDisplay;
+ activity.exported = true;
+ activity.className = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME;
+ activity.setProcessName(processName, processName);
+ activity.uiOptions = uiOptions;
+ activity.taskAffinity = PackageParser.buildTaskAffinityName(packageName,
+ packageName,
+ ":app_details", outError);
+ activity.enabled = true;
+ activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE;
+ activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic();
+ activity.configChanges = PackageParser.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.directBootAware = false;
+ activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
+ activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+ if (hardwareAccelerated) {
+ activity.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
+ }
+
+ return activity;
+ }
+
+ /**
+ * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
+ */
+ private static boolean hasDomainURLs(
+ ParsingPackage parsingPackage) {
+ final List<ComponentParseUtils.ParsedActivity> activities = parsingPackage.getActivities();
+ final int countActivities = activities.size();
+ for (int n = 0; n < countActivities; n++) {
+ ComponentParseUtils.ParsedActivity activity = activities.get(n);
+ List<ComponentParseUtils.ParsedActivityIntentInfo> filters = activity.intents;
+ if (filters == null) continue;
+ final int countFilters = filters.size();
+ for (int m = 0; m < countFilters; m++) {
+ ComponentParseUtils.ParsedActivityIntentInfo aii = filters.get(m);
+ 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 parsingPackage) {
+ // 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 = parsingPackage.getTargetSdkVersion() < O
+ ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
+
+ float packageMaxAspectRatio = parsingPackage.getMaxAspectRatio();
+ if (packageMaxAspectRatio != 0) {
+ // Use the application max aspect ration as default if set.
+ maxAspectRatio = packageMaxAspectRatio;
+ } else {
+ Bundle appMetaData = parsingPackage.getAppMetaData();
+ if (appMetaData != null && appMetaData.containsKey(
+ PackageParser.METADATA_MAX_ASPECT_RATIO)) {
+ maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+ maxAspectRatio);
+ }
+ }
+
+ if (parsingPackage.getActivities() != null) {
+ for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
+ // If the max aspect ratio for the activity has already been set, skip.
+ if (activity.hasMaxAspectRatio()) {
+ 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.metaData != null
+ ? activity.metaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+ maxAspectRatio)
+ : maxAspectRatio;
+
+ activity.setMaxAspectRatio(activity.resizeMode, activityAspectRatio);
+ }
+ }
+ }
+
+ /**
+ * Sets the min aspect ratio of every child activity that doesn't already have an aspect
+ * ratio set.
+ */
+ private static void setMinAspectRatio(
+ ParsingPackage parsingPackage,
+ PackageParser.Callback callback
+ ) {
+ final float minAspectRatio;
+ float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
+ if (packageMinAspectRatio != 0) {
+ // Use the application max aspect ration as default if set.
+ minAspectRatio = packageMinAspectRatio;
+ } else {
+ // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater.
+ // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD,
+ // except for watches which always supported 1:1.
+ minAspectRatio = parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q
+ ? 0
+ : (callback != null && callback.hasFeature(FEATURE_WATCH))
+ ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH
+ : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO;
+ }
+
+ if (parsingPackage.getActivities() != null) {
+ for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
+ if (activity.hasMinAspectRatio()) {
+ continue;
+ }
+ activity.setMinAspectRatio(activity.resizeMode, minAspectRatio);
+ }
+ }
+ }
+
+ private static ParseResult parseOverlay(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay);
+ String target = sa.getString(
+ R.styleable.AndroidManifestResourceOverlay_targetPackage);
+ String targetName = sa.getString(
+ R.styleable.AndroidManifestResourceOverlay_targetName);
+ String category = sa.getString(
+ R.styleable.AndroidManifestResourceOverlay_category);
+ int priority = sa.getInt(R.styleable.AndroidManifestResourceOverlay_priority,
+ 0);
+ boolean isStatic = sa.getBoolean(
+ R.styleable.AndroidManifestResourceOverlay_isStatic, false);
+
+ if (target == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "<overlay> does not specify a target package"
+ );
+ }
+
+ if (priority < 0 || priority > 9999) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "<overlay> 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 (!checkOverlayRequiredSystemProperty(propName, propValue)) {
+ Slog.i(TAG, "Skipping target and overlay pair " + target + " and "
+ + parsingPackage.getBaseCodePath()
+ + ": overlay ignored due to required system property: "
+ + propName + " with value: " + propValue);
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Skipping target and overlay pair " + target + " and "
+ + parsingPackage.getBaseCodePath()
+ + ": overlay ignored due to required system property: "
+ + propName + " with value: " + propValue
+ );
+ }
+
+ parsingPackage
+ .setIsOverlay(true)
+ .setOverlayTarget(target)
+ .setOverlayTargetName(targetName)
+ .setOverlayCategory(category)
+ .setOverlayPriority(priority)
+ .setOverlayIsStatic(isStatic);
+
+ sa.recycle();
+
+ XmlUtils.skipCurrentTag(parser);
+ return parseInput.success(parsingPackage);
+ }
+
+ private static boolean parseProtectedBroadcast(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestProtectedBroadcast);
+
+ // Note: don't allow this value to be a reference to a resource
+ // that may change.
+ String name = sa.getNonResourceString(R.styleable.AndroidManifestProtectedBroadcast_name);
+
+ sa.recycle();
+
+ if (name != null) {
+ parsingPackage.addProtectedBroadcast(name);
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ return true;
+ }
+
+ private static boolean parseSupportScreens(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestSupportsScreens);
+
+ int requiresSmallestWidthDp = sa.getInteger(
+ R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
+ 0);
+ int compatibleWidthLimitDp = sa.getInteger(
+ R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
+ 0);
+ int largestWidthLimitDp = sa.getInteger(
+ R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
+ 0);
+
+ // This is a trick to get a boolean and still able to detect
+ // if a value was actually set.
+ parsingPackage
+ .setSupportsSmallScreens(
+ sa.getInteger(R.styleable.AndroidManifestSupportsScreens_smallScreens, 1))
+ .setSupportsNormalScreens(
+ sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1))
+ .setSupportsLargeScreens(
+ sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1))
+ .setSupportsXLargeScreens(
+ sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1))
+ .setResizeable(
+ sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1))
+ .setAnyDensity(
+ sa.getInteger(R.styleable.AndroidManifestSupportsScreens_anyDensity, 1))
+ .setRequiresSmallestWidthDp(requiresSmallestWidthDp)
+ .setCompatibleWidthLimitDp(compatibleWidthLimitDp)
+ .setLargestWidthLimitDp(largestWidthLimitDp);
+
+ sa.recycle();
+
+ XmlUtils.skipCurrentTag(parser);
+ return true;
+ }
+
+ private static ParseResult parseInstrumentation(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws XmlPullParserException, IOException {
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+
+ ComponentParseUtils.ParsedInstrumentation parsedInstrumentation =
+ ComponentParseUtils.parseInstrumentation(parsingPackage,
+ res, parser, outError);
+
+ if (parsedInstrumentation == null || outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addInstrumentation(parsedInstrumentation);
+
+ return parseInput.success(parsingPackage);
+ }
+
+ private static boolean parseOriginalPackage(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestOriginalPackage);
+
+ String orig = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestOriginalPackage_name,
+ 0);
+ if (!parsingPackage.getPackageName().equals(orig)) {
+ if (parsingPackage.getOriginalPackages() == null) {
+ parsingPackage.setRealPackage(parsingPackage.getPackageName());
+ }
+ parsingPackage.addOriginalPackage(orig);
+ }
+
+ sa.recycle();
+
+ XmlUtils.skipCurrentTag(parser);
+ return true;
+ }
+
+ private static boolean parseAdoptPermissions(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestOriginalPackage);
+
+ String name = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestOriginalPackage_name,
+ 0);
+
+ sa.recycle();
+
+ if (name != null) {
+ parsingPackage.addAdoptPermission(name);
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ return true;
+ }
+
+ private static void convertNewPermissions(
+ ParsingPackage packageToParse) {
+ final int NP = PackageParser.NEW_PERMISSIONS.length;
+ StringBuilder newPermsMsg = null;
+ for (int ip = 0; ip < NP; ip++) {
+ final PackageParser.NewPermissionInfo npi
+ = PackageParser.NEW_PERMISSIONS[ip];
+ if (packageToParse.getTargetSdkVersion() >= npi.sdkVersion) {
+ break;
+ }
+ if (!packageToParse.getRequestedPermissions().contains(npi.name)) {
+ if (newPermsMsg == null) {
+ newPermsMsg = new StringBuilder(128);
+ newPermsMsg.append(packageToParse.getPackageName());
+ newPermsMsg.append(": compat added ");
+ } else {
+ newPermsMsg.append(' ');
+ }
+ newPermsMsg.append(npi.name);
+ packageToParse.addRequestedPermission(npi.name);
+ packageToParse.addImplicitPermission(npi.name);
+ }
+ }
+ if (newPermsMsg != null) {
+ Slog.i(TAG, newPermsMsg.toString());
+ }
+ }
+
+ private static void convertSplitPermissions(ParsingPackage packageToParse) {
+ List<SplitPermissionInfoParcelable> splitPermissions;
+
+ try {
+ splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ final int listSize = splitPermissions.size();
+ for (int is = 0; is < listSize; is++) {
+ final SplitPermissionInfoParcelable spi = splitPermissions.get(is);
+ List<String> requestedPermissions = packageToParse.getRequestedPermissions();
+ if (packageToParse.getTargetSdkVersion() >= spi.getTargetSdk()
+ || !requestedPermissions.contains(spi.getSplitPermission())) {
+ continue;
+ }
+ final List<String> newPerms = spi.getNewPermissions();
+ for (int in = 0; in < newPerms.size(); in++) {
+ final String perm = newPerms.get(in);
+ if (!requestedPermissions.contains(perm)) {
+ packageToParse.addRequestedPermission(perm);
+ packageToParse.addImplicitPermission(perm);
+ }
+ }
+ }
+ }
+
+ private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
+ if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
+ if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
+ // malformed condition - incomplete
+ Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
+ + "=" + propValue + "' - require both requiredSystemPropertyName"
+ + " AND requiredSystemPropertyValue to be specified.");
+ return false;
+ }
+ // no valid condition set - so no exclusion criteria, overlay will be included.
+ return true;
+ }
+
+ // check property value - make sure it is both set and equal to expected value
+ final String currValue = SystemProperties.get(propName);
+ return (currValue != null && currValue.equals(propValue));
+ }
+
+ /**
+ * This is a pre-density application which will get scaled - instead of being pixel perfect.
+ * This type of application is not resizable.
+ *
+ * @param parsingPackage The package which needs to be marked as unresizable.
+ */
+ private static void adjustPackageToBeUnresizeableAndUnpipable(
+ ParsingPackage parsingPackage) {
+ if (parsingPackage.getActivities() != null) {
+ for (ComponentParseUtils.ParsedActivity a : parsingPackage.getActivities()) {
+ a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ a.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+ }
+ }
+ }
+
+ private static String validateName(String name, boolean requireSeparator,
+ boolean requireFilename) {
+ final int N = name.length();
+ boolean hasSep = false;
+ boolean front = true;
+ for (int i = 0; i < N; i++) {
+ final char c = name.charAt(i);
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ front = false;
+ continue;
+ }
+ if (!front) {
+ if ((c >= '0' && c <= '9') || c == '_') {
+ continue;
+ }
+ }
+ if (c == '.') {
+ hasSep = true;
+ front = true;
+ continue;
+ }
+ return "bad character '" + c + "'";
+ }
+ if (requireFilename && !FileUtils.isValidExtFilename(name)) {
+ return "Invalid filename";
+ }
+ return hasSep || !requireSeparator
+ ? null : "must have at least one '.' separator";
+ }
+
+ public static Bundle parseMetaData(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser, Bundle data, String[] outError)
+ throws XmlPullParserException, IOException {
+
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestMetaData);
+
+ if (data == null) {
+ data = new Bundle();
+ }
+
+ String name = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestMetaData_name, 0);
+ if (name == null) {
+ outError[0] = "<meta-data> requires an android:name attribute";
+ sa.recycle();
+ return null;
+ }
+
+ name = name.intern();
+
+ TypedValue v = sa.peekValue(
+ R.styleable.AndroidManifestMetaData_resource);
+ if (v != null && v.resourceId != 0) {
+ //Slog.i(TAG, "Meta data ref " + name + ": " + v);
+ data.putInt(name, v.resourceId);
+ } else {
+ v = sa.peekValue(
+ R.styleable.AndroidManifestMetaData_value);
+ //Slog.i(TAG, "Meta data " + name + ": " + v);
+ if (v != null) {
+ if (v.type == TypedValue.TYPE_STRING) {
+ CharSequence cs = v.coerceToString();
+ data.putString(name, cs != null ? cs.toString() : null);
+ } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
+ data.putBoolean(name, v.data != 0);
+ } else if (v.type >= TypedValue.TYPE_FIRST_INT
+ && v.type <= TypedValue.TYPE_LAST_INT) {
+ data.putInt(name, v.data);
+ } else if (v.type == TypedValue.TYPE_FLOAT) {
+ data.putFloat(name, v.getFloat());
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG,
+ "<meta-data> only supports string, integer, float, color, "
+ + "boolean, and resource reference types: "
+ + parser.getName() + " at "
+ + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ } else {
+ outError[0] =
+ "<meta-data> only supports string, integer, float, color, "
+ + "boolean, and resource reference types";
+ data = null;
+ }
+ }
+ } else {
+ outError[0] = "<meta-data> requires an android:value or android:resource attribute";
+ data = null;
+ }
+ }
+
+ sa.recycle();
+
+ XmlUtils.skipCurrentTag(parser);
+
+ return data;
+ }
+
+ /**
+ * Collect certificates from all the APKs described in the given package,
+ * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that
+ * all APK contents are signed correctly and consistently.
+ */
+ public static void collectCertificates(AndroidPackage pkg, boolean skipVerify)
+ throws PackageParserException {
+ pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN);
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+ try {
+ pkg.mutate().setSigningDetails(collectCertificates(
+ pkg.getBaseCodePath(),
+ skipVerify,
+ pkg.isStaticSharedLibrary(),
+ pkg.getSigningDetails()
+ ));
+
+ String[] splitCodePaths = pkg.getSplitCodePaths();
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ for (int i = 0; i < splitCodePaths.length; i++) {
+ pkg.mutate().setSigningDetails(collectCertificates(
+ splitCodePaths[i],
+ skipVerify,
+ pkg.isStaticSharedLibrary(),
+ pkg.getSigningDetails()
+ ));
+ }
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ public static SigningDetails collectCertificates(
+ String baseCodePath,
+ boolean skipVerify,
+ boolean isStaticSharedLibrary,
+ @NonNull SigningDetails existingSigningDetails
+ ) throws PackageParserException {
+ int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR;
+ if (isStaticSharedLibrary) {
+ // must use v2 signing scheme
+ minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
+ }
+ SigningDetails verified;
+ if (skipVerify) {
+ // systemDir APKs are already trusted, save time by not verifying
+ verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+ baseCodePath, minSignatureScheme);
+ } else {
+ verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+ }
+
+ // 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.signatures, verified.signatures)) {
+ throw new PackageParserException(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ baseCodePath + " has mismatched certificates");
+ }
+
+ return existingSigningDetails;
+ }
+ }
+
+ @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;
+ }
+
+ public interface ParseInput {
+ ParseResult success(ParsingPackage result);
+
+ ParseResult error(int parseError);
+
+ ParseResult error(int parseError, String errorMessage);
+ }
+
+ public static class ParseResult implements ParseInput {
+
+ private static final boolean DEBUG_FILL_STACK_TRACE = false;
+
+ private ParsingPackage result;
+
+ private int parseError;
+ private String errorMessage;
+
+ public ParseInput reset() {
+ this.result = null;
+ this.parseError = PackageManager.INSTALL_SUCCEEDED;
+ this.errorMessage = null;
+ return this;
+ }
+
+ @Override
+ public ParseResult success(ParsingPackage result) {
+ if (parseError != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) {
+ throw new IllegalStateException("Cannot set to success after set to error");
+ }
+ this.result = result;
+ return this;
+ }
+
+ @Override
+ public ParseResult error(int parseError) {
+ return error(parseError, null);
+ }
+
+ @Override
+ public ParseResult error(int parseError, String errorMessage) {
+ this.parseError = parseError;
+ this.errorMessage = errorMessage;
+
+ if (DEBUG_FILL_STACK_TRACE) {
+ this.errorMessage += Arrays.toString(new Exception().getStackTrace());
+ }
+
+ return this;
+ }
+
+ public ParsingPackage getResultAndNull() {
+ ParsingPackage result = this.result;
+ this.result = null;
+ return result;
+ }
+
+ public boolean isSuccess() {
+ return parseError == PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ public int getParseError() {
+ return parseError;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+ }
+}
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
new file mode 100644
index 000000000000..5364313f5760
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -0,0 +1,3250 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+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 android.annotation.CallSuper;
+import android.annotation.UnsupportedAppUsage;
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PathPermission;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+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.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.view.Gravity;
+
+import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * TODO(b/135203078): Move the inner classes out to separate files.
+ * TODO(b/135203078): Expose inner classes as immutable through interface methods.
+ *
+ * @hide
+ */
+public class ComponentParseUtils {
+
+ private static final String TAG = ApkParseUtils.TAG;
+
+ // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
+ public static class ParsedIntentInfo extends IntentFilter {
+
+ /**
+ * <p>
+ * Implementation note: The serialized form for the intent list also contains the name
+ * of the concrete class that's stored in the list, and assumes that every element of the
+ * list is of the same type. This is very similar to the original parcelable mechanism.
+ * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
+ * and is public API. It also declares Parcelable related methods as final which means
+ * we can't extend them. The approach of using composition instead of inheritance leads to
+ * a large set of cascading changes in the PackageManagerService, which seem undesirable.
+ *
+ * <p>
+ * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
+ * to make sure their owner fields are consistent. See {@code fixupOwner}.
+ */
+ public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out,
+ int flags) {
+ if (list == null) {
+ out.writeInt(-1);
+ return;
+ }
+
+ final int size = list.size();
+ out.writeInt(size);
+
+ // Don't bother writing the component name if the list is empty.
+ if (size > 0) {
+ ParsedIntentInfo info = list.get(0);
+ out.writeString(info.getClass().getName());
+
+ for (int i = 0; i < size; i++) {
+ list.get(i).writeIntentInfoToParcel(out, flags);
+ }
+ }
+ }
+
+ public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) {
+ int size = in.readInt();
+ if (size == -1) {
+ return null;
+ }
+
+ if (size == 0) {
+ return new ArrayList<>(0);
+ }
+
+ String className = in.readString();
+ final ArrayList<T> intentsList;
+ try {
+ final Class<T> cls = (Class<T>) Class.forName(className);
+ final Constructor<T> cons = cls.getConstructor(Parcel.class);
+
+ intentsList = new ArrayList<>(size);
+ for (int i = 0; i < size; ++i) {
+ intentsList.add(cons.newInstance(in));
+ }
+ } catch (ReflectiveOperationException ree) {
+ throw new AssertionError("Unable to construct intent list for: "
+ + className, ree);
+ }
+
+ return intentsList;
+ }
+
+ protected String packageName;
+ protected final String className;
+
+ public boolean hasDefault;
+ public int labelRes;
+ public CharSequence nonLocalizedLabel;
+ public int icon;
+
+ protected List<String> rawDataTypes;
+
+ public void addRawDataType(String dataType) throws MalformedMimeTypeException {
+ if (rawDataTypes == null) {
+ rawDataTypes = new ArrayList<>();
+ }
+
+ rawDataTypes.add(dataType);
+ addDataType(dataType);
+ }
+
+ public ParsedIntentInfo(String packageName, String className) {
+ this.packageName = packageName;
+ this.className = className;
+ }
+
+ public ParsedIntentInfo(Parcel in) {
+ super(in);
+ packageName = in.readString();
+ className = in.readString();
+ hasDefault = (in.readInt() == 1);
+ labelRes = in.readInt();
+ nonLocalizedLabel = in.readCharSequence();
+ icon = in.readInt();
+ }
+
+ public void writeIntentInfoToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeString(packageName);
+ dest.writeString(className);
+ dest.writeInt(hasDefault ? 1 : 0);
+ dest.writeInt(labelRes);
+ dest.writeCharSequence(nonLocalizedLabel);
+ dest.writeInt(icon);
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+ }
+
+ public static class ParsedActivityIntentInfo extends ParsedIntentInfo {
+
+ public ParsedActivityIntentInfo(String packageName, String className) {
+ super(packageName, className);
+ }
+
+ public ParsedActivityIntentInfo(Parcel in) {
+ super(in);
+ }
+
+ public static final Creator<ParsedActivityIntentInfo> CREATOR =
+ new Creator<ParsedActivityIntentInfo>() {
+ @Override
+ public ParsedActivityIntentInfo createFromParcel(Parcel source) {
+ return new ParsedActivityIntentInfo(source);
+ }
+
+ @Override
+ public ParsedActivityIntentInfo[] newArray(int size) {
+ return new ParsedActivityIntentInfo[size];
+ }
+ };
+ }
+
+ public static class ParsedServiceIntentInfo extends ParsedIntentInfo {
+
+ public ParsedServiceIntentInfo(String packageName, String className) {
+ super(packageName, className);
+ }
+
+ public ParsedServiceIntentInfo(Parcel in) {
+ super(in);
+ }
+
+ public static final Creator<ParsedServiceIntentInfo> CREATOR =
+ new Creator<ParsedServiceIntentInfo>() {
+ @Override
+ public ParsedServiceIntentInfo createFromParcel(Parcel source) {
+ return new ParsedServiceIntentInfo(source);
+ }
+
+ @Override
+ public ParsedServiceIntentInfo[] newArray(int size) {
+ return new ParsedServiceIntentInfo[size];
+ }
+ };
+ }
+
+ public static class ParsedProviderIntentInfo extends ParsedIntentInfo {
+
+ public ParsedProviderIntentInfo(String packageName, String className) {
+ super(packageName, className);
+ }
+
+ public ParsedProviderIntentInfo(Parcel in) {
+ super(in);
+ }
+
+ public static final Creator<ParsedProviderIntentInfo> CREATOR =
+ new Creator<ParsedProviderIntentInfo>() {
+ @Override
+ public ParsedProviderIntentInfo createFromParcel(Parcel source) {
+ return new ParsedProviderIntentInfo(source);
+ }
+
+ @Override
+ public ParsedProviderIntentInfo[] newArray(int size) {
+ return new ParsedProviderIntentInfo[size];
+ }
+ };
+ }
+
+ public static class ParsedQueriesIntentInfo extends ParsedIntentInfo {
+
+ public ParsedQueriesIntentInfo(String packageName, String className) {
+ super(packageName, className);
+ }
+
+ public ParsedQueriesIntentInfo(Parcel in) {
+ super(in);
+ }
+
+ public static final Creator<ParsedQueriesIntentInfo> CREATOR =
+ new Creator<ParsedQueriesIntentInfo>() {
+ @Override
+ public ParsedQueriesIntentInfo createFromParcel(Parcel source) {
+ return new ParsedQueriesIntentInfo(source);
+ }
+
+ @Override
+ public ParsedQueriesIntentInfo[] newArray(int size) {
+ return new ParsedQueriesIntentInfo[size];
+ }
+ };
+ }
+
+ public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements
+ Parcelable {
+
+ // TODO(b/135203078): Replace with "name", as not all usages are an actual class
+ public String className;
+ public int icon;
+ public int labelRes;
+ public CharSequence nonLocalizedLabel;
+ public int logo;
+ public int banner;
+
+ public int descriptionRes;
+
+ // TODO(b/135203078): Make subclass that contains these fields only for the necessary
+ // subtypes
+ protected boolean enabled = true;
+ protected boolean directBootAware;
+ public int flags;
+
+ private String packageName;
+ private String splitName;
+
+ // TODO(b/135203078): Make nullable
+ public List<IntentInfoType> intents = new ArrayList<>();
+
+ private transient ComponentName componentName;
+
+ protected Bundle metaData;
+
+ public void setSplitName(String splitName) {
+ this.splitName = splitName;
+ }
+
+ public String getSplitName() {
+ return splitName;
+ }
+
+ @CallSuper
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ this.componentName = null;
+ }
+
+ void setPackageNameInternal(String packageName) {
+ this.packageName = packageName;
+ this.componentName = null;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public final boolean isDirectBootAware() {
+ return directBootAware;
+ }
+
+ public final boolean isEnabled() {
+ return enabled;
+ }
+
+ public final String getName() {
+ return className;
+ }
+
+ public final Bundle getMetaData() {
+ return metaData;
+ }
+
+ @UnsupportedAppUsage
+ public ComponentName getComponentName() {
+ if (componentName != null) {
+ return componentName;
+ }
+ if (className != null) {
+ componentName = new ComponentName(getPackageName(),
+ className);
+ }
+ return componentName;
+ }
+
+ public void setFrom(ParsedComponent other) {
+ this.metaData = other.metaData;
+ this.className = other.className;
+ this.icon = other.icon;
+ this.labelRes = other.labelRes;
+ this.nonLocalizedLabel = other.nonLocalizedLabel;
+ this.logo = other.logo;
+ this.banner = other.banner;
+
+ this.descriptionRes = other.descriptionRes;
+
+ this.enabled = other.enabled;
+ this.directBootAware = other.directBootAware;
+ this.flags = other.flags;
+
+ this.setPackageName(other.packageName);
+ this.setSplitName(other.getSplitName());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(this.className);
+ dest.writeInt(this.icon);
+ dest.writeInt(this.labelRes);
+ dest.writeCharSequence(this.nonLocalizedLabel);
+ dest.writeInt(this.logo);
+ dest.writeInt(this.banner);
+ dest.writeInt(this.descriptionRes);
+ dest.writeBoolean(this.enabled);
+ dest.writeBoolean(this.directBootAware);
+ dest.writeInt(this.flags);
+ dest.writeString(this.packageName);
+ dest.writeString(this.splitName);
+ ParsedIntentInfo.writeIntentsList(this.intents, dest, flags);
+ dest.writeBundle(this.metaData);
+ }
+
+ public ParsedComponent() {
+ }
+
+ protected ParsedComponent(Parcel in) {
+ // We use the boot classloader for all classes that we load.
+ final ClassLoader boot = Object.class.getClassLoader();
+ this.className = 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.enabled = in.readByte() != 0;
+ this.directBootAware = in.readByte() != 0;
+ this.flags = in.readInt();
+ this.packageName = in.readString();
+ this.splitName = in.readString();
+ this.intents = ParsedIntentInfo.createIntentsList(in);
+ this.metaData = in.readBundle(boot);
+ }
+ }
+
+ // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components
+ // that can have their own processes, rather than something like permission which cannot.
+ public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends
+ ParsedComponent<IntentInfoType> {
+
+ private String processName;
+ private String permission;
+
+ public void setProcessName(String appProcessName, String processName) {
+ // TODO(b/135203078): Is this even necessary anymore?
+ this.processName = TextUtils.safeIntern(
+ processName == null ? appProcessName : processName);
+ }
+
+ public String getProcessName() {
+ return processName;
+ }
+
+ public void setPermission(String permission) {
+ this.permission = TextUtils.safeIntern(permission);
+ }
+
+ public String getPermission() {
+ return permission;
+ }
+
+ @Override
+ public void setFrom(ParsedComponent other) {
+ super.setFrom(other);
+ if (other instanceof ParsedMainComponent) {
+ ParsedMainComponent otherMainComponent = (ParsedMainComponent) other;
+ this.setProcessName(otherMainComponent.getProcessName(),
+ otherMainComponent.getProcessName());
+ this.setPermission(otherMainComponent.getPermission());
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeString(this.processName);
+ dest.writeString(this.permission);
+ }
+
+ public ParsedMainComponent() {
+ }
+
+ protected ParsedMainComponent(Parcel in) {
+ super(in);
+ this.processName = TextUtils.safeIntern(in.readString());
+ this.permission = TextUtils.safeIntern(in.readString());
+ }
+
+ public static final Creator<ParsedMainComponent> CREATOR =
+ new Creator<ParsedMainComponent>() {
+ @Override
+ public ParsedMainComponent createFromParcel(Parcel source) {
+ return new ParsedMainComponent(source);
+ }
+
+ @Override
+ public ParsedMainComponent[] newArray(int size) {
+ return new ParsedMainComponent[size];
+ }
+ };
+ }
+
+ public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo>
+ implements Parcelable {
+
+ public boolean exported;
+ public int theme;
+ public int uiOptions;
+
+ public String targetActivity;
+
+ public String parentActivityName;
+ public String taskAffinity;
+ public int privateFlags;
+
+ public int launchMode;
+ public int documentLaunchMode;
+ public int maxRecents;
+ public int configChanges;
+ public int softInputMode;
+ public int persistableMode;
+ public int lockTaskLaunchMode;
+
+ public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+
+ public float maxAspectRatio;
+ public boolean hasMaxAspectRatio;
+
+ public float minAspectRatio;
+ public boolean hasMinAspectRatio;
+
+ public String requestedVrComponent;
+ public int rotationAnimation = -1;
+ public int colorMode;
+ public int order;
+
+ public ActivityInfo.WindowLayout windowLayout;
+
+ @Override
+ public void setPackageName(String packageName) {
+ super.setPackageName(packageName);
+ for (ParsedIntentInfo intent : this.intents) {
+ intent.packageName = packageName;
+ }
+ }
+
+ public boolean hasMaxAspectRatio() {
+ return hasMaxAspectRatio;
+ }
+
+ public boolean hasMinAspectRatio() {
+ return hasMinAspectRatio;
+ }
+
+ public void 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;
+ }
+
+ if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
+ // Ignore any value lesser than 1.0.
+ return;
+ }
+
+ this.maxAspectRatio = maxAspectRatio;
+ hasMaxAspectRatio = true;
+ }
+
+ public void 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;
+ }
+
+ if (minAspectRatio < 1.0f && minAspectRatio != 0) {
+ // Ignore any value lesser than 1.0.
+ return;
+ }
+
+ this.minAspectRatio = minAspectRatio;
+ hasMinAspectRatio = true;
+ }
+
+ public void addIntent(ParsedActivityIntentInfo intent) {
+ this.intents.add(intent);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeBoolean(this.exported);
+ dest.writeInt(this.theme);
+ dest.writeInt(this.uiOptions);
+ dest.writeString(this.targetActivity);
+ dest.writeString(this.parentActivityName);
+ dest.writeString(this.taskAffinity);
+ dest.writeInt(this.privateFlags);
+ 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.writeFloat(this.maxAspectRatio);
+ dest.writeBoolean(this.hasMaxAspectRatio);
+ dest.writeFloat(this.minAspectRatio);
+ dest.writeBoolean(this.hasMinAspectRatio);
+ dest.writeString(this.requestedVrComponent);
+ dest.writeInt(this.rotationAnimation);
+ dest.writeInt(this.colorMode);
+ dest.writeInt(this.order);
+ dest.writeBundle(this.metaData);
+
+ if (windowLayout != null) {
+ dest.writeInt(1);
+ dest.writeInt(windowLayout.width);
+ dest.writeFloat(windowLayout.widthFraction);
+ dest.writeInt(windowLayout.height);
+ dest.writeFloat(windowLayout.heightFraction);
+ dest.writeInt(windowLayout.gravity);
+ dest.writeInt(windowLayout.minWidth);
+ dest.writeInt(windowLayout.minHeight);
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ public ParsedActivity() {
+ }
+
+ protected ParsedActivity(Parcel in) {
+ super(in);
+ this.exported = in.readByte() != 0;
+ 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.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 = in.readFloat();
+ this.hasMaxAspectRatio = in.readByte() != 0;
+ this.minAspectRatio = in.readFloat();
+ this.hasMinAspectRatio = in.readByte() != 0;
+ this.requestedVrComponent = in.readString();
+ this.rotationAnimation = in.readInt();
+ this.colorMode = in.readInt();
+ this.order = in.readInt();
+ this.metaData = in.readBundle();
+ if (in.readInt() == 1) {
+ windowLayout = new ActivityInfo.WindowLayout(in);
+ }
+ }
+
+ public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
+ @Override
+ public ParsedActivity createFromParcel(Parcel source) {
+ return new ParsedActivity(source);
+ }
+
+ @Override
+ public ParsedActivity[] newArray(int size) {
+ return new ParsedActivity[size];
+ }
+ };
+ }
+
+ public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> {
+
+ public boolean exported;
+ public int flags;
+ public int foregroundServiceType;
+ public int order;
+
+ @Override
+ public void setPackageName(String packageName) {
+ super.setPackageName(packageName);
+ for (ParsedIntentInfo intent : this.intents) {
+ intent.packageName = packageName;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeBoolean(this.exported);
+ dest.writeBundle(this.metaData);
+ dest.writeInt(this.flags);
+ dest.writeInt(this.foregroundServiceType);
+ dest.writeInt(this.order);
+ }
+
+ public ParsedService() {
+ }
+
+ protected ParsedService(Parcel in) {
+ super(in);
+ this.exported = in.readByte() != 0;
+ this.metaData = in.readBundle();
+ this.flags = in.readInt();
+ this.foregroundServiceType = in.readInt();
+ this.order = in.readInt();
+ }
+
+ public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
+ @Override
+ public ParsedService createFromParcel(Parcel source) {
+ return new ParsedService(source);
+ }
+
+ @Override
+ public ParsedService[] newArray(int size) {
+ return new ParsedService[size];
+ }
+ };
+ }
+
+ public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> {
+
+ protected boolean exported;
+ protected int flags;
+ protected int order;
+ private String authority;
+ protected boolean isSyncable;
+ private String readPermission;
+ private String writePermission;
+ protected boolean grantUriPermissions;
+ protected boolean forceUriPermissions;
+ protected boolean multiProcess;
+ protected int initOrder;
+ protected PatternMatcher[] uriPermissionPatterns;
+ protected PathPermission[] pathPermissions;
+
+ protected void setFrom(ParsedProvider other) {
+ super.setFrom(other);
+ this.exported = other.exported;
+
+ this.intents.clear();
+ if (other.intents != null) {
+ this.intents.addAll(other.intents);
+ }
+
+ this.flags = other.flags;
+ this.order = other.order;
+ this.setAuthority(other.getAuthority());
+ this.isSyncable = other.isSyncable;
+ this.setReadPermission(other.getReadPermission());
+ this.setWritePermission(other.getWritePermission());
+ this.grantUriPermissions = other.grantUriPermissions;
+ this.forceUriPermissions = other.forceUriPermissions;
+ this.multiProcess = other.multiProcess;
+ this.initOrder = other.initOrder;
+ this.uriPermissionPatterns = other.uriPermissionPatterns;
+ this.pathPermissions = other.pathPermissions;
+ }
+
+ @Override
+ public void setPackageName(String packageName) {
+ super.setPackageName(packageName);
+ for (ParsedIntentInfo intent : this.intents) {
+ intent.packageName = packageName;
+ }
+ }
+
+ public boolean isExported() {
+ return exported;
+ }
+
+ public List<ParsedProviderIntentInfo> getIntents() {
+ return intents;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public int getOrder() {
+ return order;
+ }
+
+ public void setAuthority(String authority) {
+ this.authority = TextUtils.safeIntern(authority);
+ }
+
+ public String getAuthority() {
+ return authority;
+ }
+
+ public boolean isSyncable() {
+ return isSyncable;
+ }
+
+ public void setReadPermission(String readPermission) {
+ this.readPermission = TextUtils.safeIntern(readPermission);
+ }
+
+ public String getReadPermission() {
+ return readPermission;
+ }
+
+ public void setWritePermission(String writePermission) {
+ this.writePermission = TextUtils.safeIntern(writePermission);
+ }
+
+ public String getWritePermission() {
+ return writePermission;
+ }
+
+ public boolean isGrantUriPermissions() {
+ return grantUriPermissions;
+ }
+
+ public boolean isForceUriPermissions() {
+ return forceUriPermissions;
+ }
+
+ public boolean isMultiProcess() {
+ return multiProcess;
+ }
+
+ public int getInitOrder() {
+ return initOrder;
+ }
+
+ public PatternMatcher[] getUriPermissionPatterns() {
+ return uriPermissionPatterns;
+ }
+
+ public PathPermission[] getPathPermissions() {
+ return pathPermissions;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeBoolean(this.exported);
+ dest.writeInt(this.flags);
+ dest.writeInt(this.order);
+ dest.writeString(this.authority);
+ dest.writeBoolean(this.isSyncable);
+ dest.writeString(this.readPermission);
+ dest.writeString(this.writePermission);
+ dest.writeBoolean(this.grantUriPermissions);
+ dest.writeBoolean(this.forceUriPermissions);
+ dest.writeBoolean(this.multiProcess);
+ dest.writeInt(this.initOrder);
+ dest.writeTypedArray(this.uriPermissionPatterns, flags);
+ dest.writeTypedArray(this.pathPermissions, flags);
+ }
+
+ public ParsedProvider() {
+ }
+
+ protected ParsedProvider(Parcel in) {
+ super(in);
+ this.exported = in.readByte() != 0;
+ this.flags = in.readInt();
+ this.order = in.readInt();
+ this.authority = TextUtils.safeIntern(in.readString());
+ this.isSyncable = in.readByte() != 0;
+ this.readPermission = TextUtils.safeIntern(in.readString());
+ this.writePermission = TextUtils.safeIntern(in.readString());
+ this.grantUriPermissions = in.readByte() != 0;
+ this.forceUriPermissions = in.readByte() != 0;
+ this.multiProcess = in.readByte() != 0;
+ this.initOrder = in.readInt();
+ this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
+ this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
+ }
+
+ public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
+ @Override
+ public ParsedProvider createFromParcel(Parcel source) {
+ return new ParsedProvider(source);
+ }
+
+ @Override
+ public ParsedProvider[] newArray(int size) {
+ return new ParsedProvider[size];
+ }
+ };
+ }
+
+ public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
+
+ public String backgroundPermission;
+ private String group;
+ public int requestRes;
+ public int protectionLevel;
+ public boolean tree;
+
+ public ParsedPermissionGroup parsedPermissionGroup;
+
+ public void setName(String className) {
+ this.className = className;
+ }
+
+ public void setGroup(String group) {
+ this.group = TextUtils.safeIntern(group);
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public boolean isRuntime() {
+ return getProtection() == PermissionInfo.PROTECTION_DANGEROUS;
+ }
+
+ public boolean isAppOp() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
+ }
+
+ @PermissionInfo.Protection
+ public int getProtection() {
+ return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+ }
+
+ public int getProtectionFlags() {
+ return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE;
+ }
+
+ public int calculateFootprint() {
+ int size = getName().length();
+ if (nonLocalizedLabel != null) {
+ size += nonLocalizedLabel.length();
+ }
+ return size;
+ }
+
+ public ParsedPermission() {
+ }
+
+ public ParsedPermission(ParsedPermission other) {
+ // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy
+ // isn't needed.
+ this.className = other.className;
+ this.icon = other.icon;
+ this.labelRes = other.labelRes;
+ this.nonLocalizedLabel = other.nonLocalizedLabel;
+ this.logo = other.logo;
+ this.banner = other.banner;
+ this.descriptionRes = other.descriptionRes;
+ this.enabled = other.enabled;
+ this.directBootAware = other.directBootAware;
+ this.flags = other.flags;
+ this.setSplitName(other.getSplitName());
+ this.setPackageName(other.getPackageName());
+
+ this.intents.addAll(other.intents);
+
+ if (other.metaData != null) {
+ this.metaData = new Bundle();
+ this.metaData.putAll(other.metaData);
+ }
+
+ this.backgroundPermission = other.backgroundPermission;
+ this.setGroup(other.group);
+ this.requestRes = other.requestRes;
+ this.protectionLevel = other.protectionLevel;
+ this.tree = other.tree;
+
+ this.parsedPermissionGroup = other.parsedPermissionGroup;
+ }
+
+ @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(this.parsedPermissionGroup, flags);
+ }
+
+ protected ParsedPermission(Parcel in) {
+ super(in);
+ // We use the boot classloader for all classes that we load.
+ final ClassLoader boot = Object.class.getClassLoader();
+ 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(boot);
+ }
+
+ public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() {
+ @Override
+ public ParsedPermission createFromParcel(Parcel source) {
+ return new ParsedPermission(source);
+ }
+
+ @Override
+ public ParsedPermission[] newArray(int size) {
+ return new ParsedPermission[size];
+ }
+ };
+ }
+
+ public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> {
+
+ public int requestDetailResourceId;
+ public int backgroundRequestResourceId;
+ public int backgroundRequestDetailResourceId;
+
+ public int requestRes;
+ public int priority;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(this.requestDetailResourceId);
+ dest.writeInt(this.backgroundRequestResourceId);
+ dest.writeInt(this.backgroundRequestDetailResourceId);
+ dest.writeInt(this.requestRes);
+ dest.writeInt(this.priority);
+ }
+
+ public ParsedPermissionGroup() {
+ }
+
+ protected ParsedPermissionGroup(Parcel in) {
+ super(in);
+ this.requestDetailResourceId = in.readInt();
+ this.backgroundRequestResourceId = in.readInt();
+ this.backgroundRequestDetailResourceId = in.readInt();
+ this.requestRes = in.readInt();
+ this.priority = in.readInt();
+ }
+
+ public static final Creator<ParsedPermissionGroup> CREATOR =
+ new Creator<ParsedPermissionGroup>() {
+ @Override
+ public ParsedPermissionGroup createFromParcel(Parcel source) {
+ return new ParsedPermissionGroup(source);
+ }
+
+ @Override
+ public ParsedPermissionGroup[] newArray(int size) {
+ return new ParsedPermissionGroup[size];
+ }
+ };
+ }
+
+ public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> {
+
+ private String targetPackage;
+ private String targetProcesses;
+ public boolean handleProfiling;
+ public boolean functionalTest;
+
+ public ParsedInstrumentation() {
+ }
+
+ public void setTargetPackage(String targetPackage) {
+ this.targetPackage = TextUtils.safeIntern(targetPackage);
+ }
+
+ public String getTargetPackage() {
+ return targetPackage;
+ }
+
+ public void setTargetProcesses(String targetProcesses) {
+ this.targetProcesses = TextUtils.safeIntern(targetProcesses);
+ }
+
+ public String getTargetProcesses() {
+ return targetProcesses;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeString(this.targetPackage);
+ dest.writeString(this.targetProcesses);
+ dest.writeBoolean(this.handleProfiling);
+ dest.writeBoolean(this.functionalTest);
+ }
+
+ protected ParsedInstrumentation(Parcel in) {
+ super(in);
+ this.targetPackage = TextUtils.safeIntern(in.readString());
+ this.targetProcesses = TextUtils.safeIntern(in.readString());
+ this.handleProfiling = in.readByte() != 0;
+ this.functionalTest = in.readByte() != 0;
+ }
+
+ public static final Creator<ParsedInstrumentation> CREATOR =
+ new Creator<ParsedInstrumentation>() {
+ @Override
+ public ParsedInstrumentation createFromParcel(Parcel source) {
+ return new ParsedInstrumentation(source);
+ }
+
+ @Override
+ public ParsedInstrumentation[] newArray(int size) {
+ return new ParsedInstrumentation[size];
+ }
+ };
+ }
+
+ public static ParsedActivity parseActivity(
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser, int flags, String[] outError,
+ boolean receiver, boolean hardwareAccelerated)
+ throws XmlPullParserException, IOException {
+
+ TypedArray sa = null;
+ boolean visibleToEphemeral;
+ boolean setExported;
+
+ int targetSdkVersion = parsingPackage.getTargetSdkVersion();
+ String packageName = parsingPackage.getPackageName();
+ String packageProcessName = parsingPackage.getProcessName();
+ ParsedActivity result = new ParsedActivity();
+
+ try {
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
+
+ String tag = receiver ? "<receiver>" : "<activity>";
+
+ String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0);
+ if (name == null) {
+ outError[0] = tag + " does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = tag + " invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestActivity_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+
+ CharSequence pname;
+ if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+ pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_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.AndroidManifestActivity_process);
+ }
+
+ result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+ packageProcessName, pname,
+ flags, separateProcesses, outError));
+
+ result.descriptionRes = sa.getResourceId(
+ R.styleable.AndroidManifestActivity_description, 0);
+
+ result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true);
+
+ setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
+ if (setExported) {
+ result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported,
+ false);
+ }
+
+ result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
+
+ result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
+ parsingPackage.getUiOptions());
+
+ String parentName = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestActivity_parentActivityName,
+ Configuration.NATIVE_CONFIG_VERSION);
+ if (parentName != null) {
+ String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
+ if (parentClassName == null) {
+ Log.e(TAG,
+ "Activity " + result.className
+ + " specified invalid parentActivityName " +
+ parentName);
+ } else {
+ result.parentActivityName = parentClassName;
+ }
+ }
+
+ String str;
+ str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
+ if (str == null) {
+ result.setPermission(parsingPackage.getPermission());
+ } else {
+ result.setPermission(str);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestActivity_taskAffinity,
+ Configuration.NATIVE_CONFIG_VERSION);
+ result.taskAffinity = PackageParser.buildTaskAffinityName(
+ packageName,
+ parsingPackage.getTaskAffinity(), str, outError);
+
+ result.setSplitName(
+ sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0));
+
+ result.flags = 0;
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestActivity_multiprocess, false)) {
+ result.flags |= ActivityInfo.FLAG_MULTIPROCESS;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
+ result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
+ result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
+ result.flags |= ActivityInfo.FLAG_NO_HISTORY;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
+ result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
+ result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
+ result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
+ (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+ != 0)) {
+ result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
+ false)) {
+ result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
+ || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
+ result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
+ result.flags |= ActivityInfo.FLAG_IMMERSIVE;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
+ result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
+ }
+
+ boolean directBootAware;
+
+ if (!receiver) {
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
+ hardwareAccelerated)) {
+ result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
+ }
+
+ result.launchMode = sa.getInt(
+ R.styleable.AndroidManifestActivity_launchMode,
+ ActivityInfo.LAUNCH_MULTIPLE);
+ result.documentLaunchMode = sa.getInt(
+ R.styleable.AndroidManifestActivity_documentLaunchMode,
+ ActivityInfo.DOCUMENT_LAUNCH_NONE);
+ result.maxRecents = sa.getInt(
+ R.styleable.AndroidManifestActivity_maxRecents,
+ ActivityTaskManager.getDefaultAppRecentsLimitStatic());
+ result.configChanges = PackageParser.getActivityConfigChanges(
+ sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
+ sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
+ result.softInputMode = sa.getInt(
+ R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
+
+ result.persistableMode = sa.getInteger(
+ R.styleable.AndroidManifestActivity_persistableMode,
+ ActivityInfo.PERSIST_ROOT_ONLY);
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
+ result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
+ false)) {
+ result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
+ false)) {
+ result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
+ result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
+ }
+
+ int screenOrientation = sa.getInt(
+ R.styleable.AndroidManifestActivity_screenOrientation,
+ SCREEN_ORIENTATION_UNSPECIFIED);
+ result.screenOrientation = screenOrientation;
+
+ int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation);
+ result.resizeMode = resizeMode;
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+ false)) {
+ result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+ result.flags |= FLAG_ALWAYS_FOCUSABLE;
+ }
+
+ if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
+ && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
+ == TypedValue.TYPE_FLOAT) {
+ result.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) {
+ result.setMinAspectRatio(resizeMode,
+ sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio,
+ 0 /*default*/));
+ }
+
+ result.lockTaskLaunchMode =
+ sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
+
+ directBootAware = sa.getBoolean(
+ R.styleable.AndroidManifestActivity_directBootAware,
+ false);
+
+ result.requestedVrComponent =
+ sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
+
+ result.rotationAnimation =
+ sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation,
+ ROTATION_ANIMATION_UNSPECIFIED);
+
+ result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
+ ActivityInfo.COLOR_MODE_DEFAULT);
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
+ result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
+ result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked,
+ false)) {
+ result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
+ }
+ } else {
+ result.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ result.configChanges = 0;
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
+ result.flags |= ActivityInfo.FLAG_SINGLE_USER;
+ }
+ directBootAware = sa.getBoolean(
+ R.styleable.AndroidManifestActivity_directBootAware,
+ false);
+ }
+
+ result.directBootAware = directBootAware;
+
+ if (directBootAware) {
+ parsingPackage.setPartiallyDirectBootAware(true);
+ }
+
+ // can't make this final; we may set it later via meta-data
+ visibleToEphemeral = sa.getBoolean(
+ R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
+ if (visibleToEphemeral) {
+ result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ parsingPackage.setVisibleToInstantApps(true);
+ }
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+
+ if (receiver && (parsingPackage.getPrivateFlags()
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+ // A heavy-weight application can not have receives in its main process
+ if (result.getProcessName().equals(packageName)) {
+ outError[0] = "Heavy-weight applications can not have receivers in main process";
+ return null;
+ }
+ }
+
+ if (outError[0] != null) {
+ return null;
+ }
+
+ 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;
+ }
+
+ if (parser.getName().equals("intent-filter")) {
+ ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
+ result.className);
+ if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
+ true /*allowGlobs*/,
+ true /*allowAutoVerify*/, outError)) {
+ return null;
+ }
+ if (intentInfo.countActions() == 0) {
+ Slog.w(TAG, "No actions in intent filter at "
+ + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ } else {
+ result.order = Math.max(intentInfo.getOrder(), result.order);
+ result.addIntent(intentInfo);
+ }
+ // adjust activity flags when we implicitly expose it via a browsable filter
+ final int visibility = visibleToEphemeral
+ ? IntentFilter.VISIBILITY_EXPLICIT
+ : !receiver && isImplicitlyExposedIntent(intentInfo)
+ ? IntentFilter.VISIBILITY_IMPLICIT
+ : IntentFilter.VISIBILITY_NONE;
+ intentInfo.setVisibilityToInstantApp(visibility);
+ if (intentInfo.isVisibleToInstantApp()) {
+ result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ if (intentInfo.isImplicitlyVisibleToInstantApp()) {
+ result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+ }
+ if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver
+ && (targetSdkVersion >= Build.VERSION_CODES.O)) {
+ for (int i = 0; i < intentInfo.countActions(); i++) {
+ final String action = intentInfo.getAction(i);
+ if (action == null || !action.startsWith("android.")) continue;
+ if (!PackageParser.SAFE_BROADCASTS.contains(action)) {
+ Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
+ + packageName + " as requested at: "
+ + parser.getPositionDescription());
+ }
+ }
+ }
+ } else if (!receiver && parser.getName().equals("preferred")) {
+ ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
+ result.className);
+ if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
+ false /*allowGlobs*/,
+ false /*allowAutoVerify*/, outError)) {
+ return null;
+ }
+ // adjust activity flags when we implicitly expose it via a browsable filter
+ final int visibility = visibleToEphemeral
+ ? IntentFilter.VISIBILITY_EXPLICIT
+ : !receiver && isImplicitlyExposedIntent(intentInfo)
+ ? IntentFilter.VISIBILITY_IMPLICIT
+ : IntentFilter.VISIBILITY_NONE;
+ intentInfo.setVisibilityToInstantApp(visibility);
+ if (intentInfo.isVisibleToInstantApp()) {
+ result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ if (intentInfo.isImplicitlyVisibleToInstantApp()) {
+ result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+ }
+
+ if (intentInfo.countActions() == 0) {
+ Slog.w(TAG, "No actions in preferred at "
+ + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ } else {
+ parsingPackage.addPreferredActivityFilter(intentInfo);
+ }
+ } else if (parser.getName().equals("meta-data")) {
+ if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+ result.metaData,
+ outError)) == null) {
+ return null;
+ }
+ } else if (!receiver && parser.getName().equals("layout")) {
+ result.windowLayout = parseLayout(res, parser);
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":");
+ if (receiver) {
+ Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ } else {
+ Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ if (receiver) {
+ outError[0] = "Bad element under <receiver>: " + parser.getName();
+ } else {
+ outError[0] = "Bad element under <activity>: " + parser.getName();
+ }
+ return null;
+ }
+ }
+ }
+
+ if (!setExported) {
+ result.exported = result.intents.size() > 0;
+ }
+
+ return result;
+ }
+
+ public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) {
+ return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE)
+ || intentInfo.hasAction(Intent.ACTION_SEND)
+ || intentInfo.hasAction(Intent.ACTION_SENDTO)
+ || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE);
+ }
+
+ public static int getActivityResizeMode(
+ ParsingPackage parsingPackage,
+ TypedArray sa,
+ int screenOrientation
+ ) {
+ int privateFlags = parsingPackage.getPrivateFlags();
+ final boolean appExplicitDefault = (privateFlags
+ & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
+ | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
+
+ if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
+ || appExplicitDefault) {
+ // Activity or app explicitly set if it is resizeable or not;
+ final boolean appResizeable = (privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+ appResizeable)) {
+ return ActivityInfo.RESIZE_MODE_RESIZEABLE;
+ } else {
+ return ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ }
+ }
+
+ if ((privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
+ != 0) {
+ // 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;
+ }
+ }
+
+ public static ParsedService parseService(
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser, int flags, String[] outError
+ ) throws XmlPullParserException, IOException {
+ TypedArray sa = null;
+ boolean visibleToEphemeral;
+ boolean setExported;
+
+ String packageName = parsingPackage.getPackageName();
+ String packageProcessName = parsingPackage.getProcessName();
+ ParsedService result = new ParsedService();
+
+ try {
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestService);
+
+ String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0);
+ if (name == null) {
+ outError[0] = "<service> does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = "<service> invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestService_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+
+ CharSequence pname;
+ if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+ pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_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.AndroidManifestService_process);
+ }
+
+ result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+ packageProcessName, pname,
+ flags, separateProcesses, outError));
+
+ result.descriptionRes = sa.getResourceId(
+ R.styleable.AndroidManifestService_description, 0);
+
+ result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true);
+
+ setExported = sa.hasValue(
+ R.styleable.AndroidManifestService_exported);
+ if (setExported) {
+ result.exported = sa.getBoolean(
+ R.styleable.AndroidManifestService_exported, false);
+ }
+
+ String str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestService_permission, 0);
+ if (str == null) {
+ result.setPermission(parsingPackage.getPermission());
+ } else {
+ result.setPermission(str);
+ }
+
+ result.setSplitName(
+ sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0));
+
+ result.foregroundServiceType = sa.getInt(
+ R.styleable.AndroidManifestService_foregroundServiceType,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
+
+ result.flags = 0;
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestService_stopWithTask,
+ false)) {
+ result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
+ }
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestService_isolatedProcess,
+ false)) {
+ result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
+ }
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestService_externalService,
+ false)) {
+ result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
+ }
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestService_useAppZygote,
+ false)) {
+ result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE;
+ }
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestService_singleUser,
+ false)) {
+ result.flags |= ServiceInfo.FLAG_SINGLE_USER;
+ }
+
+ result.directBootAware = sa.getBoolean(
+ R.styleable.AndroidManifestService_directBootAware,
+ false);
+ if (result.directBootAware) {
+ parsingPackage.setPartiallyDirectBootAware(true);
+ }
+
+ visibleToEphemeral = sa.getBoolean(
+ R.styleable.AndroidManifestService_visibleToInstantApps, false);
+ if (visibleToEphemeral) {
+ result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ parsingPackage.setVisibleToInstantApps(true);
+ }
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+ if (parsingPackage.cantSaveState()) {
+ // 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(result.getProcessName(), parsingPackage.getPackageName())) {
+ outError[0] = "Heavy-weight applications can not have services in main process";
+ return null;
+ }
+ }
+
+ 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;
+ }
+
+ if (parser.getName().equals("intent-filter")) {
+ ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName,
+ result.className);
+ if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+ false /*allowAutoVerify*/,
+ outError)) {
+ return null;
+ }
+ if (visibleToEphemeral) {
+ intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+ result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ result.order = Math.max(intent.getOrder(), result.order);
+ result.intents.add(intent);
+ } else if (parser.getName().equals("meta-data")) {
+ if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+ result.metaData,
+ outError)) == null) {
+ return null;
+ }
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under <service>: "
+ + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ outError[0] = "Bad element under <service>: " + parser.getName();
+ return null;
+ }
+ }
+ }
+
+ if (!setExported) {
+ result.exported = result.intents.size() > 0;
+ }
+
+ return result;
+ }
+
+ public static ParsedProvider parseProvider(
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser, int flags, String[] outError)
+ throws XmlPullParserException, IOException {
+ TypedArray sa = null;
+ String cpname;
+ boolean visibleToEphemeral;
+
+ int targetSdkVersion = parsingPackage.getTargetSdkVersion();
+ String packageName = parsingPackage.getPackageName();
+ String packageProcessName = parsingPackage.getProcessName();
+ ParsedProvider result = new ParsedProvider();
+
+ try {
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestProvider);
+
+ String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0);
+ if (name == null) {
+ outError[0] = "<provider> does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = "<provider> invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestProvider_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+
+ CharSequence pname;
+ if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+ pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_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.AndroidManifestProvider_process);
+ }
+
+ result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+ packageProcessName, pname,
+ flags, separateProcesses, outError));
+
+ result.descriptionRes = sa.getResourceId(
+ R.styleable.AndroidManifestProvider_description, 0);
+
+ result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true);
+
+ boolean providerExportedDefault = false;
+
+ if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ // For compatibility, applications targeting API level 16 or lower
+ // should have their content providers exported by default, unless they
+ // specify otherwise.
+ providerExportedDefault = true;
+ }
+
+ result.exported = sa.getBoolean(
+ R.styleable.AndroidManifestProvider_exported,
+ providerExportedDefault);
+
+ cpname = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestProvider_authorities, 0);
+
+ result.isSyncable = sa.getBoolean(
+ R.styleable.AndroidManifestProvider_syncable,
+ false);
+
+ String permission = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestProvider_permission, 0);
+ String str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestProvider_readPermission, 0);
+ if (str == null) {
+ str = permission;
+ }
+ if (str == null) {
+ result.setReadPermission(parsingPackage.getPermission());
+ } else {
+ result.setReadPermission(str);
+ }
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestProvider_writePermission, 0);
+ if (str == null) {
+ str = permission;
+ }
+ if (str == null) {
+ result.setWritePermission(parsingPackage.getPermission());
+ } else {
+ result.setWritePermission(str);
+ }
+
+ result.grantUriPermissions = sa.getBoolean(
+ R.styleable.AndroidManifestProvider_grantUriPermissions,
+ false);
+
+ result.forceUriPermissions = sa.getBoolean(
+ R.styleable.AndroidManifestProvider_forceUriPermissions,
+ false);
+
+ result.multiProcess = sa.getBoolean(
+ R.styleable.AndroidManifestProvider_multiprocess,
+ false);
+
+ result.initOrder = sa.getInt(
+ R.styleable.AndroidManifestProvider_initOrder,
+ 0);
+
+ result.setSplitName(
+ sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0));
+
+ result.flags = 0;
+
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestProvider_singleUser,
+ false)) {
+ result.flags |= ProviderInfo.FLAG_SINGLE_USER;
+ }
+
+ result.directBootAware = sa.getBoolean(
+ R.styleable.AndroidManifestProvider_directBootAware,
+ false);
+ if (result.directBootAware) {
+ parsingPackage.setPartiallyDirectBootAware(true);
+ }
+
+ visibleToEphemeral =
+ sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
+ if (visibleToEphemeral) {
+ result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ parsingPackage.setVisibleToInstantApps(true);
+ }
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+ if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ != 0) {
+ // A heavy-weight application can not have providers in its main process
+ if (result.getProcessName().equals(packageName)) {
+ outError[0] = "Heavy-weight applications can not have providers in main process";
+ return null;
+ }
+ }
+
+ if (cpname == null) {
+ outError[0] = "<provider> does not include authorities attribute";
+ return null;
+ }
+ if (cpname.length() <= 0) {
+ outError[0] = "<provider> has empty authorities attribute";
+ return null;
+ }
+ result.setAuthority(cpname);
+
+ if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) {
+ return null;
+ }
+
+ return result;
+ }
+
+ public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo(
+ parsingPackage.getPackageName(),
+ null
+ );
+ if (!parseIntentInfo(
+ intentInfo,
+ parsingPackage,
+ res,
+ parser,
+ true /*allowGlobs*/,
+ true /*allowAutoVerify*/,
+ outError
+ )) {
+ return null;
+ }
+ return intentInfo;
+ }
+
+ private static boolean parseProviderTags(
+ ParsingPackage parsingPackage,
+ Resources res, XmlResourceParser parser,
+ boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError)
+ throws XmlPullParserException, IOException {
+ 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;
+ }
+
+ if (parser.getName().equals("intent-filter")) {
+ ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo(
+ parsingPackage.getPackageName(), outInfo.className);
+ if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+ false /*allowAutoVerify*/,
+ outError)) {
+ return false;
+ }
+ if (visibleToEphemeral) {
+ intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+ outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ outInfo.order = Math.max(intent.getOrder(), outInfo.order);
+ outInfo.intents.add(intent);
+
+ } else if (parser.getName().equals("meta-data")) {
+ Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+ outInfo.metaData, outError);
+ if (metaData == null) {
+ return false;
+ } else {
+ outInfo.metaData = metaData;
+ }
+
+ } else if (parser.getName().equals("grant-uri-permission")) {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestGrantUriPermission);
+
+ PatternMatcher pa = null;
+
+ String str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestGrantUriPermission_path, 0);
+ if (str != null) {
+ pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
+ if (str != null) {
+ pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
+ if (str != null) {
+ pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
+
+ sa.recycle();
+
+ if (pa != null) {
+ if (outInfo.uriPermissionPatterns == null) {
+ outInfo.uriPermissionPatterns = new PatternMatcher[1];
+ outInfo.uriPermissionPatterns[0] = pa;
+ } else {
+ final int N = outInfo.uriPermissionPatterns.length;
+ PatternMatcher[] newp = new PatternMatcher[N + 1];
+ System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N);
+ newp[N] = pa;
+ outInfo.uriPermissionPatterns = newp;
+ }
+ outInfo.grantUriPermissions = true;
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under <path-permission>: "
+ + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+ + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+ return false;
+ }
+ }
+ XmlUtils.skipCurrentTag(parser);
+
+ } else if (parser.getName().equals("path-permission")) {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestPathPermission);
+
+ PathPermission pa = null;
+
+ 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 (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
+ + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+ + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ outError[0] = "No readPermission or writePermssion for <path-permission>";
+ return false;
+ }
+ }
+
+ String path = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestPathPermission_path, 0);
+ if (path != null) {
+ pa = new PathPermission(path,
+ PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
+ }
+
+ path = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
+ if (path != null) {
+ pa = new PathPermission(path,
+ PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
+ }
+
+ path = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestPathPermission_pathPattern, 0);
+ if (path != null) {
+ pa = new PathPermission(path,
+ PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
+ }
+
+ path = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
+ if (path != null) {
+ pa = new PathPermission(path,
+ PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
+ }
+
+ sa.recycle();
+
+ if (pa != null) {
+ if (outInfo.pathPermissions == null) {
+ outInfo.pathPermissions = new PathPermission[1];
+ outInfo.pathPermissions[0] = pa;
+ } else {
+ final int N = outInfo.pathPermissions.length;
+ PathPermission[] newp = new PathPermission[N + 1];
+ System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N);
+ newp[N] = pa;
+ outInfo.pathPermissions = newp;
+ }
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
+ + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+ + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+ return false;
+ }
+ XmlUtils.skipCurrentTag(parser);
+
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under <provider>: "
+ + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ outError[0] = "Bad element under <provider>: " + parser.getName();
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static ParsedActivity parseActivityAlias(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError)
+ throws XmlPullParserException, IOException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestActivityAlias);
+
+ String targetActivity = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestActivityAlias_targetActivity,
+ Configuration.NATIVE_CONFIG_VERSION);
+ if (targetActivity == null) {
+ outError[0] = "<activity-alias> does not specify android:targetActivity";
+ sa.recycle();
+ return null;
+ }
+
+ String packageName = parsingPackage.getPackageName();
+ targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
+ if (targetActivity == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ sa.recycle();
+ return null;
+ }
+
+ ParsedActivity target = null;
+
+ List<ParsedActivity> activities = parsingPackage.getActivities();
+ final int NA = activities.size();
+ for (int i = 0; i < NA; i++) {
+ ParsedActivity t = activities.get(i);
+ if (targetActivity.equals(t.className)) {
+ target = t;
+ break;
+ }
+ }
+
+ if (target == null) {
+ outError[0] = "<activity-alias> target activity " + targetActivity
+ + " not found in manifest with activities = " + parsingPackage.getActivities()
+ + ", parsedActivities = " + activities;
+ sa.recycle();
+ return null;
+ }
+
+ ParsedActivity result = new ParsedActivity();
+ result.setPackageNameInternal(target.getPackageName());
+ result.targetActivity = targetActivity;
+ result.configChanges = target.configChanges;
+ result.flags = target.flags;
+ result.privateFlags = target.privateFlags;
+ result.icon = target.icon;
+ result.logo = target.logo;
+ result.banner = target.banner;
+ result.labelRes = target.labelRes;
+ result.nonLocalizedLabel = target.nonLocalizedLabel;
+ result.launchMode = target.launchMode;
+ result.lockTaskLaunchMode = target.lockTaskLaunchMode;
+ result.descriptionRes = target.descriptionRes;
+ result.screenOrientation = target.screenOrientation;
+ result.taskAffinity = target.taskAffinity;
+ result.theme = target.theme;
+ result.softInputMode = target.softInputMode;
+ result.uiOptions = target.uiOptions;
+ result.parentActivityName = target.parentActivityName;
+ result.maxRecents = target.maxRecents;
+ result.windowLayout = target.windowLayout;
+ result.resizeMode = target.resizeMode;
+ result.maxAspectRatio = target.maxAspectRatio;
+ result.hasMaxAspectRatio = target.hasMaxAspectRatio;
+ result.minAspectRatio = target.minAspectRatio;
+ result.hasMinAspectRatio = target.hasMinAspectRatio;
+ result.requestedVrComponent = target.requestedVrComponent;
+ result.directBootAware = target.directBootAware;
+
+ result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
+
+ // 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.
+// result.enabled = target.enabled;
+// result.exported = target.exported;
+// result.permission = target.permission;
+// result.splitName = target.splitName;
+// result.documentLaunchMode = target.documentLaunchMode;
+// result.persistableMode = target.persistableMode;
+// result.rotationAnimation = target.rotationAnimation;
+// result.colorMode = target.colorMode;
+// result.intents.addAll(target.intents);
+// result.order = target.order;
+// result.metaData = target.metaData;
+
+ String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name,
+ 0);
+ if (name == null) {
+ outError[0] = "<activity-alias> does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = "<activity-alias> invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+
+ result.descriptionRes = sa.getResourceId(
+ R.styleable.AndroidManifestActivityAlias_description, 0);
+
+ result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true);
+
+ final boolean setExported = sa.hasValue(
+ R.styleable.AndroidManifestActivityAlias_exported);
+ if (setExported) {
+ result.exported = sa.getBoolean(
+ R.styleable.AndroidManifestActivityAlias_exported, false);
+ }
+
+ String str;
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestActivityAlias_permission, 0);
+ if (str != null) {
+ result.setPermission(str);
+ }
+
+ String parentName = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestActivityAlias_parentActivityName,
+ Configuration.NATIVE_CONFIG_VERSION);
+ if (parentName != null) {
+ String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
+ parentName);
+ if (parentClassName == null) {
+ Log.e(TAG, "Activity alias " + result.className +
+ " specified invalid parentActivityName " + parentName);
+ outError[0] = null;
+ } else {
+ result.parentActivityName = parentClassName;
+ }
+ }
+
+ // TODO add visibleToInstantApps attribute to activity alias
+ final boolean visibleToEphemeral =
+ ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
+
+ sa.recycle();
+
+ if (outError[0] != null) {
+ return null;
+ }
+
+ 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;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("intent-filter")) {
+ ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName,
+ result.className);
+ if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+ true /*allowAutoVerify*/, outError)) {
+ return null;
+ }
+ if (intent.countActions() == 0) {
+ Slog.w(TAG, "No actions in intent filter at "
+ + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ } else {
+ result.order = Math.max(intent.getOrder(), result.order);
+ result.addIntent(intent);
+ }
+ // adjust activity flags when we implicitly expose it via a browsable filter
+ final int visibility = visibleToEphemeral
+ ? IntentFilter.VISIBILITY_EXPLICIT
+ : isImplicitlyExposedIntent(intent)
+ ? IntentFilter.VISIBILITY_IMPLICIT
+ : IntentFilter.VISIBILITY_NONE;
+ intent.setVisibilityToInstantApp(visibility);
+ if (intent.isVisibleToInstantApp()) {
+ result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ if (intent.isImplicitlyVisibleToInstantApp()) {
+ result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+ }
+ } else if (tagName.equals("meta-data")) {
+ if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+ result.metaData,
+ outError)) == null) {
+ return null;
+ }
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ outError[0] = "Bad element under <activity-alias>: " + tagName;
+ return null;
+ }
+ }
+ }
+
+ if (!setExported) {
+ result.exported = result.intents.size() > 0;
+ }
+
+ return result;
+ }
+
+ public static ParsedPermission parsePermission(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = null;
+ String packageName = parsingPackage.getPackageName();
+ ParsedPermission result = new ParsedPermission();
+
+ try {
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission);
+
+ String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name,
+ 0);
+ if (name == null) {
+ outError[0] = "<permission> does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = "<permission> invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestPermission_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+
+ result.descriptionRes = sa.getResourceId(
+ R.styleable.AndroidManifestPermission_description, 0);
+
+ if (sa.hasValue(
+ R.styleable.AndroidManifestPermission_backgroundPermission)) {
+ if ("android".equals(packageName)) {
+ result.backgroundPermission = 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.
+ result.setGroup(sa.getNonResourceString(
+ R.styleable.AndroidManifestPermission_permissionGroup));
+
+ result.requestRes = sa.getResourceId(
+ R.styleable.AndroidManifestPermission_request, 0);
+
+ result.protectionLevel = sa.getInt(
+ R.styleable.AndroidManifestPermission_protectionLevel,
+ PermissionInfo.PROTECTION_NORMAL);
+
+ result.flags = sa.getInt(
+ R.styleable.AndroidManifestPermission_permissionFlags, 0);
+
+ // For now only platform runtime permissions can be restricted
+ if (!result.isRuntime() || !"android".equals(result.getPackageName())) {
+ result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;
+ result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;
+ } else {
+ // The platform does not get to specify conflicting permissions
+ if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
+ && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
+ throw new IllegalStateException("Permission cannot be both soft and hard"
+ + " restricted: " + result.getName());
+ }
+ }
+
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+ if (result.protectionLevel == -1) {
+ outError[0] = "<permission> does not specify protectionLevel";
+ return null;
+ }
+
+ result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel);
+
+ if (result.getProtectionFlags() != 0) {
+ if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
+ && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
+ == 0
+ && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) !=
+ PermissionInfo.PROTECTION_SIGNATURE) {
+ outError[0] = "<permission> protectionLevel specifies a non-instant flag but is "
+ + "not based on signature type";
+ return null;
+ }
+ }
+
+ boolean success = parseAllMetaData(parsingPackage, res, parser,
+ "<permission>", result, outError);
+ if (!success || outError[0] != null) {
+ return null;
+ }
+
+ return result;
+ }
+
+ public static ParsedPermission parsePermissionTree(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = null;
+ String packageName = parsingPackage.getPackageName();
+ ParsedPermission result = new ParsedPermission();
+
+ try {
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree);
+
+ String name = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestPermissionTree_name, 0);
+ if (name == null) {
+ outError[0] = "<permission-tree> does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = "<permission-tree> invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+ int index = result.getName().indexOf('.');
+ if (index > 0) {
+ index = result.getName().indexOf('.', index + 1);
+ }
+ if (index < 0) {
+ outError[0] =
+ "<permission-tree> name has less than three segments: " + result.getName();
+ return null;
+ }
+
+ result.descriptionRes = 0;
+ result.requestRes = 0;
+ result.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
+ result.tree = true;
+
+ boolean success = parseAllMetaData(parsingPackage, res, parser,
+ "<permission-tree>", result, outError);
+ if (!success || outError[0] != null) {
+ return null;
+ }
+
+ return result;
+ }
+
+ public static ParsedPermissionGroup parsePermissionGroup(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = null;
+ String packageName = parsingPackage.getPackageName();
+ ParsedPermissionGroup result = new ParsedPermissionGroup();
+
+ try {
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup);
+
+ String name = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestPermissionGroup_name, 0);
+ if (name == null) {
+ outError[0] = "<permission> does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = "<permission> invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+
+ result.descriptionRes = sa.getResourceId(
+ R.styleable.AndroidManifestPermissionGroup_description, 0);
+
+ result.requestDetailResourceId = sa.getResourceId(
+ R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
+ result.backgroundRequestResourceId = sa.getResourceId(
+ R.styleable.AndroidManifestPermissionGroup_backgroundRequest,
+ 0);
+ result.backgroundRequestDetailResourceId = sa.getResourceId(
+ R.styleable
+ .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
+
+ result.requestRes = sa.getResourceId(
+ R.styleable.AndroidManifestPermissionGroup_request, 0);
+ result.flags = sa.getInt(
+ R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,
+ 0);
+ result.priority = sa.getInt(
+ R.styleable.AndroidManifestPermissionGroup_priority, 0);
+
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+ boolean success = parseAllMetaData(parsingPackage, res, parser,
+ "<permission-group>", result, outError);
+ if (!success || outError[0] != null) {
+ return null;
+ }
+
+ return result;
+ }
+
+ public static ParsedInstrumentation parseInstrumentation(
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = null;
+ String packageName = parsingPackage.getPackageName();
+ ParsedInstrumentation result = new ParsedInstrumentation();
+
+ try {
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation);
+
+ // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was
+ // un-used for this, but can be adjusted and re-added to share all the initial result
+ // parsing for icon/logo/name/etc in all of these parse methods.
+ String name = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestInstrumentation_name, 0);
+ if (name == null) {
+ outError[0] = "<instrumentation> does not specify android:name";
+ return null;
+ } else {
+ String className = ApkParseUtils.buildClassName(packageName, name);
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+ outError[0] = "<instrumentation> invalid android:name";
+ return null;
+ } else if (className == null) {
+ outError[0] = "Empty class name in package " + packageName;
+ return null;
+ }
+
+ result.className = className;
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ result.icon = roundIconVal;
+ result.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0);
+ if (iconVal != 0) {
+ result.icon = iconVal;
+ result.nonLocalizedLabel = null;
+ }
+ }
+
+ int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0);
+ if (logoVal != 0) {
+ result.logo = logoVal;
+ }
+
+ int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0);
+ if (bannerVal != 0) {
+ result.banner = bannerVal;
+ }
+
+ TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label);
+ if (v != null && (result.labelRes = v.resourceId) == 0) {
+ result.nonLocalizedLabel = v.coerceToString();
+ }
+
+ result.setPackageNameInternal(packageName);
+
+ String str;
+ // Note: don't allow this value to be a reference to a resource
+ // that may change.
+ str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage);
+ result.setTargetPackage(str);
+
+ str = sa.getNonResourceString(
+ R.styleable.AndroidManifestInstrumentation_targetProcesses);
+ result.setTargetProcesses(str);
+ result.handleProfiling = sa.getBoolean(
+ R.styleable.AndroidManifestInstrumentation_handleProfiling, false);
+ result.functionalTest = sa.getBoolean(
+ R.styleable.AndroidManifestInstrumentation_functionalTest, false);
+
+ } finally {
+ if (sa != null) {
+ sa.recycle();
+ }
+ }
+
+ boolean success = parseAllMetaData(parsingPackage, res, parser,
+ "<instrumentation>", result, outError);
+ if (!success || outError[0] != null) {
+ return null;
+ }
+
+ return result;
+ }
+
+ public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) {
+ TypedArray sw = res.obtainAttributes(attrs,
+ R.styleable.AndroidManifestLayout);
+ 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);
+ sw.recycle();
+ return new ActivityInfo.WindowLayout(width, widthFraction,
+ height, heightFraction, gravity, minWidth, minHeight);
+ }
+
+ public static boolean parseIntentInfo(
+ ParsedIntentInfo intentInfo,
+ ParsingPackage parsingPackage,
+ Resources res, XmlResourceParser parser, boolean allowGlobs,
+ boolean allowAutoVerify, String[] outError
+ ) throws XmlPullParserException, IOException {
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestIntentFilter);
+
+ int priority = sa.getInt(
+ R.styleable.AndroidManifestIntentFilter_priority, 0);
+ intentInfo.setPriority(priority);
+
+ int order = sa.getInt(
+ R.styleable.AndroidManifestIntentFilter_order, 0);
+ intentInfo.setOrder(order);
+
+ TypedValue v = sa.peekValue(
+ R.styleable.AndroidManifestIntentFilter_label);
+ if (v != null && (intentInfo.labelRes = v.resourceId) == 0) {
+ intentInfo.nonLocalizedLabel = v.coerceToString();
+ }
+
+ int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+ R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ intentInfo.icon = roundIconVal;
+ } else {
+ intentInfo.icon = sa.getResourceId(
+ R.styleable.AndroidManifestIntentFilter_icon, 0);
+ }
+
+ if (allowAutoVerify) {
+ intentInfo.setAutoVerify(sa.getBoolean(
+ R.styleable.AndroidManifestIntentFilter_autoVerify,
+ false));
+ }
+
+ sa.recycle();
+
+ 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;
+ }
+
+ String nodeName = parser.getName();
+ if (nodeName.equals("action")) {
+ String value = parser.getAttributeValue(
+ PackageParser.ANDROID_RESOURCES, "name");
+ if (TextUtils.isEmpty(value)) {
+ outError[0] = "No value supplied for <android:name>";
+ return false;
+ }
+ XmlUtils.skipCurrentTag(parser);
+
+ intentInfo.addAction(value);
+ } else if (nodeName.equals("category")) {
+ String value = parser.getAttributeValue(
+ PackageParser.ANDROID_RESOURCES, "name");
+ if (TextUtils.isEmpty(value)) {
+ outError[0] = "No value supplied for <android:name>";
+ return false;
+ }
+ XmlUtils.skipCurrentTag(parser);
+
+ intentInfo.addCategory(value);
+
+ } else if (nodeName.equals("data")) {
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestData);
+
+ String str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_mimeType, 0);
+ if (str != null) {
+ try {
+ intentInfo.addRawDataType(str);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ outError[0] = e.toString();
+ sa.recycle();
+ return false;
+ }
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_scheme, 0);
+ if (str != null) {
+ intentInfo.addDataScheme(str);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_ssp, 0);
+ if (str != null) {
+ intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_sspPrefix, 0);
+ if (str != null) {
+ intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_sspPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ outError[0] = "sspPattern not allowed here; ssp must be literal";
+ return false;
+ }
+ intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
+
+ String host = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_host, 0);
+ String port = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_port, 0);
+ if (host != null) {
+ intentInfo.addDataAuthority(host, port);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_path, 0);
+ if (str != null) {
+ intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_pathPrefix, 0);
+ if (str != null) {
+ intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_pathPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ outError[0] = "pathPattern not allowed here; path must be literal";
+ return false;
+ }
+ intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
+ return false;
+ }
+ intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
+ }
+
+ sa.recycle();
+ XmlUtils.skipCurrentTag(parser);
+ } else if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under <intent-filter>: "
+ + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ outError[0] = "Bad element under <intent-filter>: " + parser.getName();
+ return false;
+ }
+ }
+
+ intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
+
+ if (PackageParser.DEBUG_PARSER) {
+ final StringBuilder cats = new StringBuilder("Intent d=");
+ cats.append(intentInfo.hasDefault);
+ cats.append(", cat=");
+
+ final Iterator<String> it = intentInfo.categoriesIterator();
+ if (it != null) {
+ while (it.hasNext()) {
+ cats.append(' ');
+ cats.append(it.next());
+ }
+ }
+ Slog.d(TAG, cats.toString());
+ }
+
+ return true;
+ }
+
+ private static boolean parseAllMetaData(
+ ParsingPackage parsingPackage,
+ Resources res, XmlResourceParser parser, String tag,
+ ParsedComponent outInfo,
+ String[] outError
+ ) throws XmlPullParserException, IOException {
+ 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;
+ }
+
+ if (parser.getName().equals("meta-data")) {
+ if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+ outInfo.metaData, outError)) == null) {
+ return false;
+ }
+ } else {
+ if (!PackageParser.RIGID_PARSER) {
+ Slog.w(TAG, "Unknown element under " + tag + ": "
+ + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else {
+ outError[0] = "Bad element under " + tag + ": " + parser.getName();
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean isImplicitlyExposedIntent(IntentFilter intent) {
+ return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+ || intent.hasAction(Intent.ACTION_SEND)
+ || intent.hasAction(Intent.ACTION_SENDTO)
+ || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
+ }
+}
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
new file mode 100644
index 000000000000..377279e750c6
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -0,0 +1,3234 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm.parsing;
+
+import static android.os.Build.VERSION_CODES.DONUT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+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.PackageParser;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Parcel;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
+
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * The backing data for a package that was parsed from disk.
+ *
+ * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case
+ * TODO(b/135203078): Field nullability annotations
+ * TODO(b/135203078): Convert = 1 fields into Booleans
+ * TODO(b/135203078): Make all lists nullable and Collections.unmodifiable immutable when returned.
+ * Prefer add/set methods if adding is necessary.
+ * TODO(b/135203078): Consider comments to disable auto-format and single-line, single-space all the
+ * get/set methods to make this class far more compact. Maybe even separate some logic into parent
+ * classes, assuming there is no overhead.
+ * TODO(b/135203078): Copy documentation from PackageParser#Package for the relevant fields included
+ * here. Should clarify and clean up any differences. Also consider renames if it helps make
+ * things clearer.
+ * TODO(b/135203078): Intern all possibl e String values? Initial refactor just mirrored old
+ * behavior.
+ *
+ * @hide
+ */
+public final class PackageImpl implements ParsingPackage, ParsedPackage, AndroidPackage,
+ AndroidPackageWrite {
+
+ private static final String TAG = "PackageImpl";
+
+ // Resource boolean are -1, so 1 means we don't know the value.
+ private int supportsSmallScreens = 1;
+ private int supportsNormalScreens = 1;
+ private int supportsLargeScreens = 1;
+ private int supportsXLargeScreens = 1;
+ private int resizeable = 1;
+ private int anyDensity = 1;
+
+ private long[] lastPackageUsageTimeInMills =
+ new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
+
+ private int versionCode;
+ private int versionCodeMajor;
+ private int baseRevisionCode;
+ private String versionName;
+
+ private boolean coreApp;
+ private int compileSdkVersion;
+ private String compileSdkVersionCodename;
+
+ private String packageName;
+ private String realPackage;
+ private String manifestPackageName;
+ private String baseCodePath;
+
+ private boolean requiredForAllUsers;
+ private String restrictedAccountType;
+ private String requiredAccountType;
+
+ private boolean baseHardwareAccelerated;
+
+ private String overlayTarget;
+ private String overlayTargetName;
+ private String overlayCategory;
+ private int overlayPriority;
+ private boolean overlayIsStatic;
+
+ private String staticSharedLibName;
+ private long staticSharedLibVersion;
+ private ArrayList<String> libraryNames;
+ private ArrayList<String> usesLibraries;
+ private ArrayList<String> usesOptionalLibraries;
+
+ private ArrayList<String> usesStaticLibraries;
+ private long[] usesStaticLibrariesVersions;
+ private String[][] usesStaticLibrariesCertDigests;
+
+ private String sharedUserId;
+
+ private int sharedUserLabel;
+ private ArrayList<ConfigurationInfo> configPreferences;
+ private ArrayList<FeatureInfo> reqFeatures;
+ private ArrayList<FeatureGroupInfo> featureGroups;
+
+ private byte[] restrictUpdateHash;
+
+ private ArrayList<String> originalPackages;
+ private ArrayList<String> adoptPermissions;
+
+ private ArrayList<String> requestedPermissions;
+ private ArrayList<String> implicitPermissions;
+
+ private ArraySet<String> upgradeKeySets;
+ private Map<String, ArraySet<PublicKey>> keySetMapping;
+
+ private ArrayList<String> protectedBroadcasts;
+
+ @Nullable
+ private ArrayList<ComponentParseUtils.ParsedActivity> activities;
+
+ @Nullable
+ private ArrayList<ComponentParseUtils.ParsedActivity> receivers;
+
+ @Nullable
+ private ArrayList<ComponentParseUtils.ParsedService> services;
+
+ @Nullable
+ private ArrayList<ComponentParseUtils.ParsedProvider> providers;
+
+ @Nullable
+ private ArrayList<ComponentParseUtils.ParsedPermission> permissions;
+
+ @Nullable
+ private ArrayList<ComponentParseUtils.ParsedPermissionGroup> permissionGroups;
+
+ @Nullable
+ private ArrayList<ComponentParseUtils.ParsedInstrumentation> instrumentations;
+
+ private ArrayList<ParsedActivityIntentInfo> preferredActivityFilters;
+
+ private Bundle appMetaData;
+
+ private String volumeUuid;
+ private String applicationVolumeUuid;
+ private PackageParser.SigningDetails signingDetails;
+
+ private String codePath;
+
+ private boolean use32BitAbi;
+ private boolean visibleToInstantApps;
+
+ private String cpuAbiOverride;
+
+ private boolean isStub;
+
+ // TODO(b/135203078): Remove, should be unused
+ private int preferredOrder;
+
+ private boolean forceQueryable;
+
+ @Nullable
+ private ArrayList<Intent> queriesIntents;
+
+ @Nullable
+ private ArrayList<String> queriesPackages;
+
+ private String[] splitClassLoaderNames;
+ private String[] splitCodePaths;
+ private SparseArray<int[]> splitDependencies;
+ private int[] splitFlags;
+ private String[] splitNames;
+ private int[] splitRevisionCodes;
+
+ // TODO(b/135203078): Audit applicationInfo.something usages, which may be different from
+ // package.something usages. There were differing cases of package.field = versus
+ // package.appInfo.field =. This class assumes some obvious ones, like packageName,
+ // were collapsible, but kept the following separate.
+
+ private String applicationInfoBaseResourcePath;
+ private String applicationInfoCodePath;
+ private String applicationInfoResourcePath;
+ private String[] applicationInfoSplitResourcePaths;
+
+ private String appComponentFactory;
+ private String backupAgentName;
+ private int banner;
+ private int category;
+ private String classLoaderName;
+ private String className;
+ private int compatibleWidthLimitDp;
+ private String credentialProtectedDataDir;
+ private String dataDir;
+ private int descriptionRes;
+ private String deviceProtectedDataDir;
+ private boolean enabled;
+ private int flags;
+ private int fullBackupContent;
+ private boolean hiddenUntilInstalled;
+ private int icon;
+ private int iconRes;
+ private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION;
+ private int labelRes;
+ private int largestWidthLimitDp;
+ private int logo;
+ private String manageSpaceActivityName;
+ private float maxAspectRatio;
+ private float minAspectRatio;
+ private int minSdkVersion;
+ private String name;
+ private String nativeLibraryDir;
+ private String nativeLibraryRootDir;
+ private boolean nativeLibraryRootRequiresIsa;
+ private int networkSecurityConfigRes;
+ private CharSequence nonLocalizedLabel;
+ private String permission;
+ private String primaryCpuAbi;
+ private int privateFlags;
+ private String processName;
+ private int requiresSmallestWidthDp;
+ private int roundIconRes;
+ private String secondaryCpuAbi;
+ private String secondaryNativeLibraryDir;
+ private String seInfo;
+ private String seInfoUser;
+ private int targetSandboxVersion;
+ private int targetSdkVersion;
+ private String taskAffinity;
+ private int theme;
+ private int uid = -1;
+ private int uiOptions;
+ private String[] usesLibraryFiles;
+ private List<SharedLibraryInfo> usesLibraryInfos;
+ private String zygotePreloadName;
+
+ @VisibleForTesting
+ public PackageImpl(
+ String packageName,
+ String baseCodePath,
+ TypedArray manifestArray,
+ boolean isCoreApp
+ ) {
+ this.packageName = TextUtils.safeIntern(packageName);
+ this.manifestPackageName = this.packageName;
+ this.baseCodePath = baseCodePath;
+
+ this.versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
+ this.versionCodeMajor = manifestArray.getInteger(
+ R.styleable.AndroidManifest_versionCodeMajor, 0);
+ this.baseRevisionCode = manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode,
+ 0);
+ setVersionName(manifestArray.getNonConfigurationString(
+ R.styleable.AndroidManifest_versionName, 0));
+ this.coreApp = isCoreApp;
+
+ this.compileSdkVersion = manifestArray.getInteger(
+ R.styleable.AndroidManifest_compileSdkVersion, 0);
+ setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
+ R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
+ }
+
+ private PackageImpl(String packageName) {
+ this.packageName = TextUtils.safeIntern(packageName);
+ this.manifestPackageName = this.packageName;
+ }
+
+ @VisibleForTesting
+ public static ParsingPackage forParsing(String packageName) {
+ return new PackageImpl(packageName);
+ }
+
+ @VisibleForTesting
+ public static ParsingPackage forParsing(
+ String packageName,
+ String baseCodePath,
+ TypedArray manifestArray,
+ boolean isCoreApp) {
+ return new PackageImpl(packageName, baseCodePath, 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.
+ */
+ public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) {
+ return new PackageImpl(packageName)
+ .setVolumeUuid(volumeUuid)
+ .hideAsParsed()
+ .hideAsFinal();
+ }
+
+ @Override
+ public ParsedPackage hideAsParsed() {
+ return this;
+ }
+
+ @Override
+ public AndroidPackage hideAsFinal() {
+ updateFlags();
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public AndroidPackageWrite mutate() {
+ return this;
+ }
+
+ private void updateFlags() {
+ if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ this.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+ }
+ if (supportsNormalScreens != 0) {
+ this.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+ }
+ if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ this.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+ }
+ if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.GINGERBREAD)) {
+ this.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
+ }
+ if (resizeable < 0 || (resizeable > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ this.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
+ }
+ if (anyDensity < 0 || (anyDensity > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ this.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+ }
+ }
+
+ @Override
+ public boolean usesCompatibilityMode() {
+ int flags = 0;
+
+ if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+ }
+ if (supportsNormalScreens != 0) {
+ flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+ }
+ if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+ }
+ if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.GINGERBREAD)) {
+ flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
+ }
+ if (resizeable < 0 || (resizeable > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
+ }
+ if (anyDensity < 0 || (anyDensity > 0
+ && targetSdkVersion
+ >= Build.VERSION_CODES.DONUT)) {
+ flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+ }
+
+ return targetSdkVersion < DONUT
+ || (flags & (ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+ | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+ | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)) == 0;
+ }
+
+ @Override
+ public String getBaseCodePath() {
+ return baseCodePath;
+ }
+
+ @Override
+ public int getTargetSdkVersion() {
+ return targetSdkVersion;
+ }
+
+ @Override
+ public String getPackageName() {
+ return packageName;
+ }
+
+ @Override
+ public String getProcessName() {
+ return processName;
+ }
+
+ @Override
+ public String getPermission() {
+ return permission;
+ }
+
+ @Override
+ public String getStaticSharedLibName() {
+ return staticSharedLibName;
+ }
+
+ @Override
+ public long getStaticSharedLibVersion() {
+ return staticSharedLibVersion;
+ }
+
+ @Override
+ public String getSharedUserId() {
+ return sharedUserId;
+ }
+
+ @Override
+ public List<String> getRequestedPermissions() {
+ return requestedPermissions == null ? Collections.emptyList() : requestedPermissions;
+ }
+
+ @Nullable
+ @Override
+ public List<ParsedInstrumentation> getInstrumentations() {
+ return instrumentations;
+ }
+
+ @Override
+ public Map<String, ArraySet<PublicKey>> getKeySetMapping() {
+ return keySetMapping == null ? Collections.emptyMap() : keySetMapping;
+ }
+
+ @Override
+ public float getMaxAspectRatio() {
+ return maxAspectRatio;
+ }
+
+ @Override
+ public float getMinAspectRatio() {
+ return minAspectRatio;
+ }
+
+ @NonNull
+ @Override
+ public List<String> getLibraryNames() {
+ return libraryNames == null ? Collections.emptyList() : libraryNames;
+ }
+
+ @Override
+ public List<ParsedActivity> getActivities() {
+ return activities == null ? Collections.emptyList()
+ : activities;
+ }
+
+ @Override
+ public Bundle getAppMetaData() {
+ return appMetaData;
+ }
+
+ @Nullable
+ @Override
+ public List<String> getUsesLibraries() {
+ return usesLibraries;
+ }
+
+ @Nullable
+ @Override
+ public List<String> getUsesStaticLibraries() {
+ return usesStaticLibraries;
+ }
+
+ @Override
+ public boolean isBaseHardwareAccelerated() {
+ return baseHardwareAccelerated;
+ }
+
+ @Override
+ public int getUiOptions() {
+ return uiOptions;
+ }
+
+ // TODO(b/135203078): Checking flags directly can be error prone,
+ // consider separate interface methods?
+ @Override
+ public int getFlags() {
+ return flags;
+ }
+
+ // TODO(b/135203078): Checking flags directly can be error prone,
+ // consider separate interface methods?
+ @Override
+ public int getPrivateFlags() {
+ return privateFlags;
+ }
+
+ @Override
+ public String getTaskAffinity() {
+ return taskAffinity;
+ }
+
+ @Nullable
+ @Override
+ public List<String> getOriginalPackages() {
+ return originalPackages;
+ }
+
+ @Override
+ public PackageParser.SigningDetails getSigningDetails() {
+ return signingDetails;
+ }
+
+ @Override
+ public String getVolumeUuid() {
+ return volumeUuid;
+ }
+
+ @Nullable
+ @Override
+ public List<ParsedPermissionGroup> getPermissionGroups() {
+ return permissionGroups;
+ }
+
+ @Nullable
+ @Override
+ public List<ParsedPermission> getPermissions() {
+ return permissions;
+ }
+
+ @Override
+ public String getCpuAbiOverride() {
+ return cpuAbiOverride;
+ }
+
+ @Override
+ public String getPrimaryCpuAbi() {
+ return primaryCpuAbi;
+ }
+
+ @Override
+ public String getSecondaryCpuAbi() {
+ return secondaryCpuAbi;
+ }
+
+ @Override
+ public boolean isUse32BitAbi() {
+ return use32BitAbi;
+ }
+
+ @Override
+ public boolean isForceQueryable() {
+ return forceQueryable;
+ }
+
+ @Override
+ public String getCodePath() {
+ return codePath;
+ }
+
+ @Override
+ public String getNativeLibraryDir() {
+ return nativeLibraryDir;
+ }
+
+ @Override
+ public String getNativeLibraryRootDir() {
+ return nativeLibraryRootDir;
+ }
+
+ @Override
+ public boolean isNativeLibraryRootRequiresIsa() {
+ return nativeLibraryRootRequiresIsa;
+ }
+
+ // TODO(b/135203078): Does nothing, remove?
+ @Override
+ public int getPreferredOrder() {
+ return preferredOrder;
+ }
+
+ @Override
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+ }
+
+ @Override
+ public PackageImpl setIsOverlay(boolean isOverlay) {
+ this.privateFlags = isOverlay
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setExternalStorage(boolean externalStorage) {
+ this.flags = externalStorage
+ ? this.flags | ApplicationInfo.FLAG_EXTERNAL_STORAGE
+ : this.flags & ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setIsolatedSplitLoading(boolean isolatedSplitLoading) {
+ this.privateFlags = isolatedSplitLoading
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
+ return this;
+ }
+
+ @Override
+ public PackageImpl sortActivities() {
+ Collections.sort(this.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
+ return this;
+ }
+
+ @Override
+ public PackageImpl sortReceivers() {
+ Collections.sort(this.receivers, (a1, a2) -> Integer.compare(a2.order, a1.order));
+ return this;
+ }
+
+ @Override
+ public PackageImpl sortServices() {
+ Collections.sort(this.services, (a1, a2) -> Integer.compare(a2.order, a1.order));
+ return this;
+ }
+
+ @Override
+ public PackageImpl setBaseRevisionCode(int baseRevisionCode) {
+ this.baseRevisionCode = baseRevisionCode;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setPreferredOrder(int preferredOrder) {
+ this.preferredOrder = preferredOrder;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setVersionName(String versionName) {
+ this.versionName = TextUtils.safeIntern(versionName);
+ return this;
+ }
+
+ @Override
+ public ParsingPackage setCompileSdkVersion(int compileSdkVersion) {
+ this.compileSdkVersion = compileSdkVersion;
+ return this;
+ }
+
+ @Override
+ public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
+ this.compileSdkVersionCodename = TextUtils.safeIntern(compileSdkVersionCodename);
+ return this;
+ }
+
+ @Override
+ public PackageImpl setMaxAspectRatio(float maxAspectRatio) {
+ this.maxAspectRatio = maxAspectRatio;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setMinAspectRatio(float minAspectRatio) {
+ this.minAspectRatio = minAspectRatio;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setMinSdkVersion(int minSdkVersion) {
+ this.minSdkVersion = minSdkVersion;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setTargetSdkVersion(int targetSdkVersion) {
+ this.targetSdkVersion = targetSdkVersion;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRealPackage(String realPackage) {
+ this.realPackage = realPackage;
+ return this;
+ }
+
+ @Override
+ public PackageImpl addConfigPreference(ConfigurationInfo configPreference) {
+ this.configPreferences = ArrayUtils.add(this.configPreferences, configPreference);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addReqFeature(FeatureInfo reqFeature) {
+ this.reqFeatures = ArrayUtils.add(this.reqFeatures, reqFeature);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) {
+ this.featureGroups = ArrayUtils.add(this.featureGroups, featureGroup);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addProtectedBroadcast(String protectedBroadcast) {
+ if (this.protectedBroadcasts == null
+ || !this.protectedBroadcasts.contains(protectedBroadcast)) {
+ this.protectedBroadcasts = ArrayUtils.add(this.protectedBroadcasts,
+ TextUtils.safeIntern(protectedBroadcast));
+ }
+ return this;
+ }
+
+ @Override
+ public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) {
+ this.instrumentations = ArrayUtils.add(this.instrumentations, instrumentation);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addOriginalPackage(String originalPackage) {
+ this.originalPackages = ArrayUtils.add(this.originalPackages, originalPackage);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addAdoptPermission(String adoptPermission) {
+ this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addPermission(ParsedPermission permission) {
+ this.permissions = ArrayUtils.add(this.permissions, permission);
+ return this;
+ }
+
+ @Override
+ public PackageImpl removePermission(int index) {
+ this.permissions.remove(index);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) {
+ this.permissionGroups = ArrayUtils.add(this.permissionGroups, permissionGroup);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addRequestedPermission(String permission) {
+ this.requestedPermissions = ArrayUtils.add(this.requestedPermissions,
+ TextUtils.safeIntern(permission));
+ return this;
+ }
+
+ @Override
+ public PackageImpl addImplicitPermission(String permission) {
+ this.implicitPermissions = ArrayUtils.add(this.implicitPermissions,
+ TextUtils.safeIntern(permission));
+ return this;
+ }
+
+ @Override
+ public PackageImpl addKeySet(String keySetName, PublicKey publicKey) {
+ if (keySetMapping == null) {
+ keySetMapping = new ArrayMap<>();
+ }
+
+ ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName);
+ if (publicKeys == null) {
+ publicKeys = new ArraySet<>();
+ keySetMapping.put(keySetName, publicKeys);
+ }
+
+ publicKeys.add(publicKey);
+
+ return this;
+ }
+
+ @Override
+ public ParsingPackage addActivity(ParsedActivity parsedActivity) {
+ this.activities = ArrayUtils.add(this.activities, parsedActivity);
+ return this;
+ }
+
+ @Override
+ public ParsingPackage addReceiver(ParsedActivity parsedReceiver) {
+ this.receivers = ArrayUtils.add(this.receivers, parsedReceiver);
+ return this;
+ }
+
+ @Override
+ public ParsingPackage addService(ParsedService parsedService) {
+ this.services = ArrayUtils.add(this.services, parsedService);
+ return this;
+ }
+
+ @Override
+ public ParsingPackage addProvider(ParsedProvider parsedProvider) {
+ this.providers = ArrayUtils.add(this.providers, parsedProvider);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addLibraryName(String libraryName) {
+ this.libraryNames = ArrayUtils.add(this.libraryNames, TextUtils.safeIntern(libraryName));
+ return this;
+ }
+
+ @Override
+ public PackageImpl addUsesLibrary(String libraryName) {
+ this.usesLibraries = ArrayUtils.add(this.usesLibraries, TextUtils.safeIntern(libraryName));
+ return this;
+ }
+
+ @Override
+ public PackageImpl addUsesOptionalLibrary(String libraryName) {
+ this.usesOptionalLibraries = ArrayUtils.add(this.usesOptionalLibraries,
+ TextUtils.safeIntern(libraryName));
+ return this;
+ }
+
+ @Override
+ public PackageImpl removeUsesOptionalLibrary(String libraryName) {
+ this.usesOptionalLibraries = ArrayUtils.remove(this.usesOptionalLibraries, libraryName);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addUsesStaticLibrary(String libraryName) {
+ this.usesStaticLibraries = ArrayUtils.add(this.usesStaticLibraries,
+ TextUtils.safeIntern(libraryName));
+ return this;
+ }
+
+ @Override
+ public PackageImpl addUsesStaticLibraryVersion(long version) {
+ this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions,
+ version, true);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) {
+ this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
+ this.usesStaticLibrariesCertDigests, certSha256Digests, true);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addPreferredActivityFilter(
+ ParsedActivityIntentInfo parsedActivityIntentInfo) {
+ this.preferredActivityFilters = ArrayUtils.add(this.preferredActivityFilters,
+ parsedActivityIntentInfo);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addQueriesIntent(Intent intent) {
+ this.queriesIntents = ArrayUtils.add(this.queriesIntents, intent);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addQueriesPackage(String packageName) {
+ this.queriesPackages = ArrayUtils.add(this.queriesPackages,
+ TextUtils.safeIntern(packageName));
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
+ if (supportsSmallScreens == 1) {
+ return this;
+ }
+
+ this.supportsSmallScreens = supportsSmallScreens;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
+ if (supportsNormalScreens == 1) {
+ return this;
+ }
+
+ this.supportsNormalScreens = supportsNormalScreens;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
+ if (supportsLargeScreens == 1) {
+ return this;
+ }
+
+ this.supportsLargeScreens = supportsLargeScreens;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSupportsXLargeScreens(int supportsXLargeScreens) {
+ if (supportsXLargeScreens == 1) {
+ return this;
+ }
+
+ this.supportsXLargeScreens = supportsXLargeScreens;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setResizeable(int resizeable) {
+ if (resizeable == 1) {
+ return this;
+ }
+
+ this.resizeable = resizeable;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAnyDensity(int anyDensity) {
+ if (anyDensity == 1) {
+ return this;
+ }
+
+ this.anyDensity = anyDensity;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRequiresSmallestWidthDp(int requiresSmallestWidthDp) {
+ this.requiresSmallestWidthDp = requiresSmallestWidthDp;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setCompatibleWidthLimitDp(int compatibleWidthLimitDp) {
+ this.compatibleWidthLimitDp = compatibleWidthLimitDp;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setLargestWidthLimitDp(int largestWidthLimitDp) {
+ this.largestWidthLimitDp = largestWidthLimitDp;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setInstallLocation(int installLocation) {
+ this.installLocation = installLocation;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setTargetSandboxVersion(int targetSandboxVersion) {
+ this.targetSandboxVersion = targetSandboxVersion;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRequiredForAllUsers(boolean requiredForAllUsers) {
+ this.requiredForAllUsers = requiredForAllUsers;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRestrictedAccountType(String restrictedAccountType) {
+ this.restrictedAccountType = restrictedAccountType;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRequiredAccountType(String requiredAccountType) {
+ this.requiredAccountType = requiredAccountType;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setBaseHardwareAccelerated(boolean baseHardwareAccelerated) {
+ this.baseHardwareAccelerated = baseHardwareAccelerated;
+
+ this.flags = baseHardwareAccelerated
+ ? this.flags | ApplicationInfo.FLAG_HARDWARE_ACCELERATED
+ : this.flags & ~ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
+
+ return this;
+ }
+
+ @Override
+ public PackageImpl setHasDomainUrls(boolean hasDomainUrls) {
+ this.privateFlags = hasDomainUrls
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAppMetaData(Bundle appMetaData) {
+ this.appMetaData = appMetaData;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setOverlayTarget(String overlayTarget) {
+ this.overlayTarget = overlayTarget;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setOverlayTargetName(String overlayTargetName) {
+ this.overlayTargetName = overlayTargetName;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setOverlayCategory(String overlayCategory) {
+ this.overlayCategory = overlayCategory;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setOverlayPriority(int overlayPriority) {
+ this.overlayPriority = overlayPriority;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setOverlayIsStatic(boolean overlayIsStatic) {
+ this.overlayIsStatic = overlayIsStatic;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setStaticSharedLibName(String staticSharedLibName) {
+ this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName);
+ return this;
+ }
+
+ @Override
+ public PackageImpl setStaticSharedLibVersion(long staticSharedLibVersion) {
+ this.staticSharedLibVersion = staticSharedLibVersion;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSharedUserId(String sharedUserId) {
+ this.sharedUserId = TextUtils.safeIntern(sharedUserId);
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSharedUserLabel(int sharedUserLabel) {
+ this.sharedUserLabel = sharedUserLabel;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRestrictUpdateHash(byte[] restrictUpdateHash) {
+ this.restrictUpdateHash = restrictUpdateHash;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUpgradeKeySets(ArraySet<String> upgradeKeySets) {
+ this.upgradeKeySets = upgradeKeySets;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setVolumeUuid(String volumeUuid) {
+ this.volumeUuid = volumeUuid;
+ return this;
+ }
+
+ @Deprecated
+ @Override
+ public PackageImpl setApplicationVolumeUuid(String applicationVolumeUuid) {
+ this.applicationVolumeUuid = applicationVolumeUuid;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSigningDetails(PackageParser.SigningDetails signingDetails) {
+ this.signingDetails = signingDetails;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setCodePath(String codePath) {
+ this.codePath = codePath;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUse32BitAbi(boolean use32BitAbi) {
+ this.use32BitAbi = use32BitAbi;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setCpuAbiOverride(String cpuAbiOverride) {
+ this.cpuAbiOverride = cpuAbiOverride;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setForceQueryable(boolean forceQueryable) {
+ this.forceQueryable = forceQueryable;
+ return this;
+ }
+
+ // TODO(b/135203078): Remove and move PackageManagerService#renameStaticSharedLibraryPackage
+ // into initial package parsing
+ @Override
+ public PackageImpl setPackageName(String packageName) {
+ this.packageName = packageName.intern();
+
+ if (permissions != null) {
+ for (ParsedPermission permission : permissions) {
+ permission.setPackageName(this.packageName);
+ }
+ }
+
+ if (permissionGroups != null) {
+ for (ParsedPermissionGroup permissionGroup : permissionGroups) {
+ permissionGroup.setPackageName(this.packageName);
+ }
+ }
+
+ if (activities != null) {
+ for (ParsedActivity parsedActivity : activities) {
+ parsedActivity.setPackageName(this.packageName);
+ }
+ }
+
+ if (receivers != null) {
+ for (ParsedActivity receiver : receivers) {
+ receiver.setPackageName(this.packageName);
+ }
+ }
+
+ if (providers != null) {
+ for (ParsedProvider provider : providers) {
+ provider.setPackageName(this.packageName);
+ }
+ }
+
+ if (services != null) {
+ for (ParsedService service : services) {
+ service.setPackageName(this.packageName);
+ }
+ }
+
+ if (instrumentations != null) {
+ for (ParsedInstrumentation instrumentation : instrumentations) {
+ instrumentation.setPackageName(this.packageName);
+ }
+ }
+
+ return this;
+ }
+
+ // Under this is parseBaseApplication
+
+ @Override
+ public PackageImpl setAllowBackup(boolean allowBackup) {
+ this.flags = allowBackup
+ ? this.flags | ApplicationInfo.FLAG_ALLOW_BACKUP
+ : this.flags & ~ApplicationInfo.FLAG_ALLOW_BACKUP;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setKillAfterRestore(boolean killAfterRestore) {
+ this.flags = killAfterRestore
+ ? this.flags | ApplicationInfo.FLAG_KILL_AFTER_RESTORE
+ : this.flags & ~ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRestoreAnyVersion(boolean restoreAnyVersion) {
+ this.flags = restoreAnyVersion
+ ? this.flags | ApplicationInfo.FLAG_RESTORE_ANY_VERSION
+ : this.flags & ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setFullBackupOnly(boolean fullBackupOnly) {
+ this.flags = fullBackupOnly
+ ? this.flags | ApplicationInfo.FLAG_FULL_BACKUP_ONLY
+ : this.flags & ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setPersistent(boolean persistent) {
+ this.flags = persistent
+ ? this.flags | ApplicationInfo.FLAG_PERSISTENT
+ : this.flags & ~ApplicationInfo.FLAG_PERSISTENT;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setDebuggable(boolean debuggable) {
+ this.flags = debuggable
+ ? this.flags | ApplicationInfo.FLAG_DEBUGGABLE
+ : this.flags & ~ApplicationInfo.FLAG_DEBUGGABLE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setProfileableByShell(boolean profileableByShell) {
+ this.privateFlags = profileableByShell
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setVmSafeMode(boolean vmSafeMode) {
+ this.flags = vmSafeMode
+ ? this.flags | ApplicationInfo.FLAG_VM_SAFE_MODE
+ : this.flags & ~ApplicationInfo.FLAG_VM_SAFE_MODE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setHasCode(boolean hasCode) {
+ this.flags = hasCode
+ ? this.flags | ApplicationInfo.FLAG_HAS_CODE
+ : this.flags & ~ApplicationInfo.FLAG_HAS_CODE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAllowTaskReparenting(boolean allowTaskReparenting) {
+ this.flags = allowTaskReparenting
+ ? this.flags | ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING
+ : this.flags & ~ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAllowClearUserData(boolean allowClearUserData) {
+ this.flags = allowClearUserData
+ ? this.flags | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA
+ : this.flags & ~ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setLargeHeap(boolean largeHeap) {
+ this.flags = largeHeap
+ ? this.flags | ApplicationInfo.FLAG_LARGE_HEAP
+ : this.flags & ~ApplicationInfo.FLAG_LARGE_HEAP;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUsesCleartextTraffic(boolean usesCleartextTraffic) {
+ this.flags = usesCleartextTraffic
+ ? this.flags | ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC
+ : this.flags & ~ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSupportsRtl(boolean supportsRtl) {
+ this.flags = supportsRtl
+ ? this.flags | ApplicationInfo.FLAG_SUPPORTS_RTL
+ : this.flags & ~ApplicationInfo.FLAG_SUPPORTS_RTL;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setTestOnly(boolean testOnly) {
+ this.flags = testOnly
+ ? this.flags | ApplicationInfo.FLAG_TEST_ONLY
+ : this.flags & ~ApplicationInfo.FLAG_TEST_ONLY;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setMultiArch(boolean multiArch) {
+ this.flags = multiArch
+ ? this.flags | ApplicationInfo.FLAG_MULTIARCH
+ : this.flags & ~ApplicationInfo.FLAG_MULTIARCH;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setExtractNativeLibs(boolean extractNativeLibs) {
+ this.flags = extractNativeLibs
+ ? this.flags | ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS
+ : this.flags & ~ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setIsGame(boolean isGame) {
+ this.flags = isGame
+ ? this.flags | ApplicationInfo.FLAG_IS_GAME
+ : this.flags & ~ApplicationInfo.FLAG_IS_GAME;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setBackupInForeground(boolean backupInForeground) {
+ this.privateFlags = backupInForeground
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUseEmbeddedDex(boolean useEmbeddedDex) {
+ this.privateFlags = useEmbeddedDex
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage) {
+ this.privateFlags = defaultToDeviceProtectedStorage
+ ? this.privateFlags | ApplicationInfo
+ .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE
+ : this.privateFlags & ~ApplicationInfo
+ .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setDirectBootAware(boolean directBootAware) {
+ this.privateFlags = directBootAware
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setPartiallyDirectBootAware(boolean partiallyDirectBootAware) {
+ this.privateFlags = partiallyDirectBootAware
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setActivitiesResizeModeResizeableViaSdkVersion(
+ boolean resizeableViaSdkVersion
+ ) {
+ this.privateFlags = resizeableViaSdkVersion
+ ? this.privateFlags | ApplicationInfo
+ .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
+ : this.privateFlags & ~ApplicationInfo
+ .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setActivitiesResizeModeResizeable(boolean resizeable) {
+ this.privateFlags = resizeable
+ ? this.privateFlags | ApplicationInfo
+ .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
+ : this.privateFlags & ~ApplicationInfo
+ .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+
+ this.privateFlags = !resizeable
+ ? this.privateFlags | ApplicationInfo
+ .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE
+ : this.privateFlags & ~ApplicationInfo
+ .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAllowClearUserDataOnFailedRestore(
+ boolean allowClearUserDataOnFailedRestore
+ ) {
+ this.privateFlags = allowClearUserDataOnFailedRestore
+ ? this.privateFlags | ApplicationInfo
+ .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
+ : this.privateFlags & ~ApplicationInfo
+ .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture) {
+ this.privateFlags = allowAudioPlaybackCapture
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage) {
+ this.privateFlags = requestLegacyExternalStorage
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) {
+ this.privateFlags = usesNonSdkApi
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setHasFragileUserData(boolean hasFragileUserData) {
+ this.privateFlags = hasFragileUserData
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setCantSaveState(boolean cantSaveState) {
+ this.privateFlags = cantSaveState
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+ return this;
+ }
+
+ @Override
+ public boolean cantSaveState() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0;
+ }
+
+ @Override
+ public boolean isLibrary() {
+ return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
+ }
+
+ // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+ // part of PackageParser
+ @Override
+ public boolean isSystemApp() {
+ return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+ // part of PackageParser
+ @Override
+ public boolean isSystemExt() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
+ }
+
+ // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+ // part of PackageParser
+ @Override
+ public boolean isUpdatedSystemApp() {
+ return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+ }
+
+ @Override
+ public PackageImpl setStaticSharedLibrary(boolean staticSharedLibrary) {
+ this.privateFlags = staticSharedLibrary
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
+ return this;
+ }
+
+ @Override
+ public boolean isStaticSharedLibrary() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0;
+ }
+
+ @Override
+ public PackageImpl setVisibleToInstantApps(boolean visibleToInstantApps) {
+ this.visibleToInstantApps = visibleToInstantApps;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setIconRes(int iconRes) {
+ this.iconRes = iconRes;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setRoundIconRes(int roundIconRes) {
+ this.roundIconRes = roundIconRes;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setClassName(String className) {
+ this.className = className;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setManageSpaceActivityName(String manageSpaceActivityName) {
+ this.manageSpaceActivityName = manageSpaceActivityName;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setBackupAgentName(String backupAgentName) {
+ this.backupAgentName = backupAgentName;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setFullBackupContent(int fullBackupContent) {
+ this.fullBackupContent = fullBackupContent;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setTheme(int theme) {
+ this.theme = theme;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setDescriptionRes(int descriptionRes) {
+ this.descriptionRes = descriptionRes;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setNetworkSecurityConfigRes(int networkSecurityConfigRes) {
+ this.networkSecurityConfigRes = networkSecurityConfigRes;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setCategory(int category) {
+ this.category = category;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setPermission(String permission) {
+ this.permission = permission;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setTaskAffinity(String taskAffinity) {
+ this.taskAffinity = taskAffinity;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setAppComponentFactory(String appComponentFactory) {
+ this.appComponentFactory = appComponentFactory;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setProcessName(String processName) {
+ if (processName == null) {
+ this.processName = packageName;
+ } else {
+ this.processName = processName;
+ }
+ return this;
+ }
+
+ @Override
+ public PackageImpl setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUiOptions(int uiOptions) {
+ this.uiOptions = uiOptions;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setClassLoaderName(String classLoaderName) {
+ this.classLoaderName = classLoaderName;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setZygotePreloadName(String zygotePreloadName) {
+ this.zygotePreloadName = zygotePreloadName;
+ return this;
+ }
+
+ // parsePackageItemInfo
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public PackageImpl setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setIcon(int icon) {
+ this.icon = icon;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setNonLocalizedLabel(CharSequence nonLocalizedLabel) {
+ this.nonLocalizedLabel = nonLocalizedLabel;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setLogo(int logo) {
+ this.logo = logo;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setBanner(int banner) {
+ this.banner = banner;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setLabelRes(int labelRes) {
+ this.labelRes = labelRes;
+ return this;
+ }
+
+ @Override
+ public PackageImpl asSplit(
+ String[] splitNames,
+ String[] splitCodePaths,
+ int[] splitRevisionCodes,
+ SparseArray<int[]> splitDependencies
+ ) {
+ this.splitNames = splitNames;
+
+ if (this.splitNames != null) {
+ for (int index = 0; index < this.splitNames.length; index++) {
+ splitNames[index] = TextUtils.safeIntern(splitNames[index]);
+ }
+ }
+
+ 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;
+ }
+
+ @Override
+ public String[] getSplitNames() {
+ return splitNames;
+ }
+
+ @Override
+ public String[] getSplitCodePaths() {
+ return splitCodePaths;
+ }
+
+ @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 setSplitClassLoaderName(int splitIndex, String classLoaderName) {
+ this.splitClassLoaderNames[splitIndex] = classLoaderName;
+ return this;
+ }
+
+ @Override
+ public List<String> makeListAllCodePaths() {
+ ArrayList<String> paths = new ArrayList<>();
+ paths.add(baseCodePath);
+
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ Collections.addAll(paths, splitCodePaths);
+ }
+ return paths;
+ }
+
+ @Override
+ public PackageImpl setBaseCodePath(String baseCodePath) {
+ this.baseCodePath = baseCodePath;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSplitCodePaths(String[] splitCodePaths) {
+ this.splitCodePaths = splitCodePaths;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "Package{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + packageName + "}";
+ }
+
+ @Override
+ public PackageImpl setPrimaryCpuAbi(String primaryCpuAbi) {
+ this.primaryCpuAbi = primaryCpuAbi;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSecondaryCpuAbi(String secondaryCpuAbi) {
+ this.secondaryCpuAbi = secondaryCpuAbi;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setNativeLibraryRootDir(String nativeLibraryRootDir) {
+ this.nativeLibraryRootDir = nativeLibraryRootDir;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa) {
+ this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setNativeLibraryDir(String nativeLibraryDir) {
+ this.nativeLibraryDir = nativeLibraryDir;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir) {
+ this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+ return this;
+ }
+
+ @Deprecated
+ @Override
+ public PackageImpl setApplicationInfoCodePath(String applicationInfoCodePath) {
+ this.applicationInfoCodePath = applicationInfoCodePath;
+ return this;
+ }
+
+ @Deprecated
+ @Override
+ public PackageImpl setApplicationInfoResourcePath(String applicationInfoResourcePath) {
+ this.applicationInfoResourcePath = applicationInfoResourcePath;
+ return this;
+ }
+
+ @Deprecated
+ @Override
+ public PackageImpl setApplicationInfoBaseResourcePath(
+ String applicationInfoBaseResourcePath) {
+ this.applicationInfoBaseResourcePath = applicationInfoBaseResourcePath;
+ return this;
+ }
+
+ @Deprecated
+ @Override
+ public PackageImpl setApplicationInfoSplitResourcePaths(
+ String[] applicationInfoSplitResourcePaths) {
+ this.applicationInfoSplitResourcePaths = applicationInfoSplitResourcePaths;
+ return this;
+ }
+
+ @Override
+ public boolean isDirectBootAware() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
+ }
+
+ @Override
+ public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) {
+ if (activities != null) {
+ for (ParsedActivity parsedActivity : activities) {
+ parsedActivity.directBootAware = allComponentsDirectBootAware;
+ }
+ }
+
+ if (receivers != null) {
+ for (ParsedActivity parsedReceiver : receivers) {
+ parsedReceiver.directBootAware = allComponentsDirectBootAware;
+ }
+ }
+
+ if (providers != null) {
+ for (ParsedProvider parsedProvider : providers) {
+ parsedProvider.directBootAware = allComponentsDirectBootAware;
+ }
+ }
+
+ if (services != null) {
+ for (ParsedService parsedService : services) {
+ parsedService.directBootAware = allComponentsDirectBootAware;
+ }
+ }
+
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSystem(boolean system) {
+ this.flags = system
+ ? this.flags | ApplicationInfo.FLAG_SYSTEM
+ : this.flags & ~ApplicationInfo.FLAG_SYSTEM;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSystemExt(boolean systemExt) {
+ this.privateFlags = systemExt
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setIsStub(boolean isStub) {
+ this.isStub = isStub;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setCoreApp(boolean coreApp) {
+ this.coreApp = coreApp;
+ return this;
+ }
+
+ @Override
+ public ParsedPackage capPermissionPriorities() {
+ if (permissionGroups != null && !permissionGroups.isEmpty()) {
+ for (int i = permissionGroups.size() - 1; i >= 0; --i) {
+ // TODO(b/135203078): Builder/immutability
+ permissionGroups.get(i).priority = 0;
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public ParsedPackage clearProtectedBroadcasts() {
+ if (protectedBroadcasts != null) {
+ protectedBroadcasts.clear();
+ }
+ return this;
+ }
+
+ @Override
+ public ParsedPackage markNotActivitiesAsNotExportedIfSingleUser() {
+ // ignore export request for single user receivers
+ if (receivers != null) {
+ for (ParsedActivity receiver : receivers) {
+ if ((receiver.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+ receiver.exported = false;
+ }
+ }
+ }
+ // ignore export request for single user services
+ if (services != null) {
+ for (ParsedService service : services) {
+ if ((service.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
+ service.exported = false;
+ }
+ }
+ }
+ // ignore export request for single user providers
+ if (providers != null) {
+ for (ParsedProvider provider : providers) {
+ if ((provider.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
+ provider.exported = false;
+ }
+ }
+ }
+
+ return this;
+ }
+
+ @Override
+ public ParsedPackage setPrivileged(boolean privileged) {
+ this.privateFlags = privileged
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ return this;
+ }
+
+ @Override
+ public ParsedPackage setOem(boolean oem) {
+ this.privateFlags = oem
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_OEM
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_OEM;
+ return this;
+ }
+
+ @Override
+ public ParsedPackage setVendor(boolean vendor) {
+ this.privateFlags = vendor
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_VENDOR
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
+ return this;
+ }
+
+ @Override
+ public ParsedPackage setProduct(boolean product) {
+ this.privateFlags = product
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRODUCT
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRODUCT;
+ return this;
+ }
+
+ @Override
+ public ParsedPackage setOdm(boolean odm) {
+ this.privateFlags = odm
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ODM
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ODM;
+ return this;
+ }
+
+ @Override
+ public ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey) {
+ this.privateFlags = signedWithPlatformKey
+ ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY
+ : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
+ return this;
+ }
+
+ @Override
+ public ParsedPackage clearOriginalPackages() {
+ if (originalPackages != null) {
+ originalPackages.clear();
+ }
+ return this;
+ }
+
+ @Override
+ public ParsedPackage clearAdoptPermissions() {
+ if (adoptPermissions != null) {
+ adoptPermissions.clear();
+ }
+ return this;
+ }
+
+ @Override
+ public PackageImpl addUsesLibrary(int index, String libraryName) {
+ this.usesLibraries = ArrayUtils.add(usesLibraries, index, libraryName);
+ return this;
+ }
+
+ @Override
+ public ParsedPackage removeUsesLibrary(String libraryName) {
+ this.usesLibraries = ArrayUtils.remove(this.usesLibraries, libraryName);
+ return this;
+ }
+
+ @Override
+ public PackageImpl addUsesOptionalLibrary(int index, String libraryName) {
+ this.usesOptionalLibraries = ArrayUtils.add(usesOptionalLibraries, index, libraryName);
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public List<String> getUsesOptionalLibraries() {
+ return usesOptionalLibraries;
+ }
+
+ @Override
+ public int getVersionCode() {
+ return versionCode;
+ }
+
+ @Nullable
+ @Override
+ public long[] getUsesStaticLibrariesVersions() {
+ return usesStaticLibrariesVersions;
+ }
+
+ @Override
+ public PackageImpl setPackageSettingCallback(PackageSettingCallback packageSettingCallback) {
+ packageSettingCallback.setAndroidPackage(this);
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUpdatedSystemApp(boolean updatedSystemApp) {
+ this.flags = updatedSystemApp
+ ? this.flags | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
+ : this.flags & ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ return this;
+ }
+
+ @Override
+ public boolean isPrivileged() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ }
+
+ @Override
+ public PackageImpl setSeInfo(String seInfo) {
+ this.seInfo = seInfo;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setSeInfoUser(String seInfoUser) {
+ this.seInfoUser = seInfoUser;
+ return this;
+ }
+
+ @Override
+ public PackageImpl initForUser(int userId) {
+ // TODO(b/135203078): Move this user state to some other data structure
+ this.uid = UserHandle.getUid(userId, UserHandle.getAppId(this.uid));
+
+ if ("android".equals(packageName)) {
+ dataDir = Environment.getDataSystemDirectory().getAbsolutePath();
+ return this;
+ }
+
+ deviceProtectedDataDir = Environment
+ .getDataUserDePackageDirectory(applicationVolumeUuid, userId, packageName)
+ .getAbsolutePath();
+ credentialProtectedDataDir = Environment
+ .getDataUserCePackageDirectory(applicationVolumeUuid, userId, packageName)
+ .getAbsolutePath();
+
+ if ((privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0
+ && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+ dataDir = deviceProtectedDataDir;
+ } else {
+ dataDir = credentialProtectedDataDir;
+ }
+ return this;
+ }
+
+ @Override
+ public ParsedPackage setFactoryTest(boolean factoryTest) {
+ this.flags = factoryTest
+ ? this.flags | ApplicationInfo.FLAG_FACTORY_TEST
+ : this.flags & ~ApplicationInfo.FLAG_FACTORY_TEST;
+ return this;
+ }
+
+ @Override
+ public String getManifestPackageName() {
+ return manifestPackageName;
+ }
+
+ @Override
+ public String getRealPackage() {
+ return realPackage;
+ }
+
+ @Override
+ public String getOverlayTarget() {
+ return overlayTarget;
+ }
+
+ @Override
+ public String getOverlayTargetName() {
+ return overlayTargetName;
+ }
+
+ @Override
+ public boolean isOverlayIsStatic() {
+ return overlayIsStatic;
+ }
+
+ @Override
+ public int[] getSplitFlags() {
+ return splitFlags;
+ }
+
+ @Deprecated
+ @Override
+ public String getApplicationInfoVolumeUuid() {
+ return applicationVolumeUuid;
+ }
+
+ @Nullable
+ @Override
+ public List<String> getProtectedBroadcasts() {
+ return protectedBroadcasts;
+ }
+
+ @Nullable
+ @Override
+ public Set<String> getUpgradeKeySets() {
+ return upgradeKeySets;
+ }
+
+ @Nullable
+ @Override
+ public String[][] getUsesStaticLibrariesCertDigests() {
+ return usesStaticLibrariesCertDigests;
+ }
+
+ @Override
+ public int getOverlayPriority() {
+ return overlayPriority;
+ }
+
+ @Deprecated
+ @Override
+ public String getAppInfoPackageName() {
+ return packageName;
+ }
+
+ @Override
+ public UUID getStorageUuid() {
+ return StorageManager.convert(applicationVolumeUuid);
+ }
+
+ @Override
+ public int getUid() {
+ return uid;
+ }
+
+ @Override
+ public boolean isStub() {
+ return isStub;
+ }
+
+ @Deprecated
+ @Override
+ public String getAppInfoCodePath() {
+ return applicationInfoCodePath;
+ }
+
+ @Override
+ public boolean isSystem() {
+ return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ @Override
+ public boolean isMatch(int flags) {
+ if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+ return isSystem();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean isVisibleToInstantApps() {
+ return visibleToInstantApps;
+ }
+
+ @Override
+ public PackageImpl setLastPackageUsageTimeInMills(int reason, long time) {
+ lastPackageUsageTimeInMills[reason] = time;
+ return this;
+ }
+
+ @Override
+ public List<SharedLibraryInfo> getUsesLibraryInfos() {
+ return usesLibraryInfos;
+ }
+
+ @NonNull
+ @Override
+ public List<String> getAllCodePaths() {
+ return makeListAllCodePaths();
+ }
+
+ @Nullable
+ @Override
+ public String[] getUsesLibraryFiles() {
+ return usesLibraryFiles;
+ }
+
+ @Override
+ public PackageImpl setUsesLibraryInfos(
+ @Nullable List<SharedLibraryInfo> usesLibraryInfos) {
+ this.usesLibraryInfos = usesLibraryInfos;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUsesLibraryFiles(@Nullable String[] usesLibraryFiles) {
+ this.usesLibraryFiles = usesLibraryFiles;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setUid(int uid) {
+ this.uid = uid;
+ return this;
+ }
+
+ @Override
+ public List<String> getAdoptPermissions() {
+ return adoptPermissions;
+ }
+
+ @Override
+ public ApplicationInfo toAppInfoWithoutState() {
+ updateFlags();
+
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ appInfo.flags = flags;
+ appInfo.privateFlags = privateFlags;
+
+ 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 = credentialProtectedDataDir;
+ appInfo.dataDir = dataDir;
+ appInfo.descriptionRes = descriptionRes;
+ appInfo.deviceProtectedDataDir = deviceProtectedDataDir;
+ appInfo.enabled = enabled;
+ appInfo.fullBackupContent = fullBackupContent;
+ appInfo.hiddenUntilInstalled = hiddenUntilInstalled;
+ appInfo.icon = icon;
+ appInfo.iconRes = iconRes;
+ appInfo.installLocation = installLocation;
+ appInfo.labelRes = labelRes;
+ appInfo.largestWidthLimitDp = largestWidthLimitDp;
+ appInfo.logo = logo;
+ appInfo.manageSpaceActivityName = manageSpaceActivityName;
+ appInfo.maxAspectRatio = maxAspectRatio;
+ appInfo.metaData = appMetaData;
+ appInfo.minAspectRatio = minAspectRatio;
+ appInfo.minSdkVersion = minSdkVersion;
+ appInfo.name = name;
+ if (appInfo.name != null) {
+ appInfo.name = appInfo.name.trim();
+ }
+ appInfo.nativeLibraryDir = nativeLibraryDir;
+ appInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+ appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+ appInfo.networkSecurityConfigRes = networkSecurityConfigRes;
+ appInfo.nonLocalizedLabel = nonLocalizedLabel;
+ if (appInfo.nonLocalizedLabel != null) {
+ appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim();
+ }
+ appInfo.packageName = packageName;
+ appInfo.permission = permission;
+ appInfo.primaryCpuAbi = primaryCpuAbi;
+ appInfo.processName = getProcessName();
+ appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp;
+ appInfo.roundIconRes = roundIconRes;
+ appInfo.secondaryCpuAbi = secondaryCpuAbi;
+ appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+ appInfo.seInfo = seInfo;
+ appInfo.seInfoUser = seInfoUser;
+ appInfo.sharedLibraryFiles = usesLibraryFiles;
+ appInfo.sharedLibraryInfos = ArrayUtils.isEmpty(usesLibraryInfos) ? null : usesLibraryInfos;
+ appInfo.splitClassLoaderNames = splitClassLoaderNames;
+ appInfo.splitDependencies = splitDependencies;
+ appInfo.splitNames = splitNames;
+ appInfo.storageUuid = StorageManager.convert(volumeUuid);
+ appInfo.targetSandboxVersion = targetSandboxVersion;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ appInfo.taskAffinity = taskAffinity;
+ appInfo.theme = theme;
+ appInfo.uid = uid;
+ appInfo.uiOptions = uiOptions;
+ appInfo.volumeUuid = volumeUuid;
+ appInfo.zygotePreloadName = zygotePreloadName;
+
+ appInfo.setBaseCodePath(baseCodePath);
+ appInfo.setBaseResourcePath(baseCodePath);
+ appInfo.setCodePath(codePath);
+ appInfo.setResourcePath(codePath);
+ appInfo.setSplitCodePaths(splitCodePaths);
+ appInfo.setSplitResourcePaths(splitCodePaths);
+ appInfo.setVersionCode(getLongVersionCode());
+
+ // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo.
+// appInfo.showUserIcon = pkg.getShowUserIcon();
+ // TODO(b/135203078): Unused?
+// appInfo.resourceDirs = pkg.getResourceDirs();
+ // TODO(b/135203078): Unused?
+// appInfo.enabledSetting = pkg.getEnabledSetting();
+ // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy
+// appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy();
+
+ return appInfo;
+ }
+
+ @Override
+ public PackageImpl setVersionCode(int versionCode) {
+ this.versionCode = versionCode;
+ return this;
+ }
+
+ @Override
+ public PackageImpl setHiddenUntilInstalled(boolean hidden) {
+ this.hiddenUntilInstalled = hidden;
+ return this;
+ }
+
+ @Override
+ public String getSeInfo() {
+ return seInfo;
+ }
+
+ @Deprecated
+ @Override
+ public String getAppInfoResourcePath() {
+ return applicationInfoResourcePath;
+ }
+
+ @Override
+ public boolean isForwardLocked() {
+ // TODO(b/135203078): Unused? Move to debug flag?
+ return false;
+ }
+
+ @Override
+ public byte[] getRestrictUpdateHash() {
+ return restrictUpdateHash;
+ }
+
+ @Override
+ public boolean hasComponentClassName(String className) {
+ if (activities != null) {
+ for (ParsedActivity parsedActivity : activities) {
+ if (Objects.equals(className, parsedActivity.className)) {
+ return true;
+ }
+ }
+ }
+
+ if (receivers != null) {
+ for (ParsedActivity receiver : receivers) {
+ if (Objects.equals(className, receiver.className)) {
+ return true;
+ }
+ }
+ }
+
+ if (providers != null) {
+ for (ParsedProvider provider : providers) {
+ if (Objects.equals(className, provider.className)) {
+ return true;
+ }
+ }
+ }
+
+ if (services != null) {
+ for (ParsedService service : services) {
+ if (Objects.equals(className, service.className)) {
+ return true;
+ }
+ }
+ }
+
+ if (instrumentations != null) {
+ for (ParsedInstrumentation instrumentation : instrumentations) {
+ if (Objects.equals(className, instrumentation.className)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isDefaultToDeviceProtectedStorage() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
+ != 0;
+ }
+
+ @Override
+ public boolean isInternal() {
+ return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0;
+ }
+
+ @Override
+ public int getBaseRevisionCode() {
+ return baseRevisionCode;
+ }
+
+ @Override
+ public int[] getSplitRevisionCodes() {
+ return splitRevisionCodes;
+ }
+
+ @Override
+ public boolean canHaveOatDir() {
+ // The following app types CANNOT have oat directory
+ // - non-updated system apps
+ return !isSystem() || isUpdatedSystemApp();
+ }
+
+ @Override
+ public long getLatestPackageUseTimeInMills() {
+ long latestUse = 0L;
+ for (long use : lastPackageUsageTimeInMills) {
+ latestUse = Math.max(latestUse, use);
+ }
+ return latestUse;
+ }
+
+ @Override
+ public long getLatestForegroundPackageUseTimeInMills() {
+ int[] foregroundReasons = {
+ PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
+ PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
+ };
+
+ long latestUse = 0L;
+ for (int reason : foregroundReasons) {
+ latestUse = Math.max(latestUse, lastPackageUsageTimeInMills[reason]);
+ }
+ return latestUse;
+ }
+
+ @Override
+ public boolean isCoreApp() {
+ return coreApp;
+ }
+
+ @Override
+ public String getVersionName() {
+ return versionName;
+ }
+
+ @Override
+ public PackageImpl setVersionCodeMajor(int versionCodeMajor) {
+ this.versionCodeMajor = versionCodeMajor;
+ return this;
+ }
+
+ @Override
+ public long[] getLastPackageUsageTimeInMills() {
+ return lastPackageUsageTimeInMills;
+ }
+
+ @Override
+ public String getDataDir() {
+ return dataDir;
+ }
+
+ @Override
+ public boolean isExternal() {
+ return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
+ }
+
+ @Override
+ public List<String> getImplicitPermissions() {
+ return implicitPermissions == null ? Collections.emptyList() : implicitPermissions;
+ }
+
+ /**
+ * TODO(b/135203078): Remove, ensure b/140256621 is fixed or irrelevant
+ * TODO(b/140256621): Remove after fixing instant app check
+ * @deprecated This method always returns false because there's no paired set method
+ */
+ @Deprecated
+ @Override
+ public boolean isInstantApp() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
+ }
+
+ @Override
+ public boolean hasRequestedLegacyExternalStorage() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
+ }
+
+ @Override
+ public boolean isVendor() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+ }
+
+ @Override
+ public boolean isProduct() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+ }
+
+ @Override
+ public boolean isOem() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+ }
+
+ @Override
+ public boolean isEncryptionAware() {
+ boolean isPartiallyDirectBootAware =
+ (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
+ return isDirectBootAware() || isPartiallyDirectBootAware;
+ }
+
+ @Override
+ public boolean isEmbeddedDexUsed() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) != 0;
+ }
+
+ @Deprecated
+ @Override
+ public String getAppInfoProcessName() {
+ return processName;
+ }
+
+ @Override
+ public List<String> getAllCodePathsExcludingResourceOnly() {
+ ArrayList<String> paths = new ArrayList<>();
+ if ((flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ paths.add(baseCodePath);
+ }
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ for (int i = 0; i < splitCodePaths.length; i++) {
+ if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ paths.add(splitCodePaths[i]);
+ }
+ }
+ }
+ return paths;
+ }
+
+ @Deprecated
+ @Override
+ public String getAppInfoName() {
+ return name;
+ }
+
+ private boolean isSignedWithPlatformKey() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0;
+ }
+
+ private boolean usesNonSdkApi() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) != 0;
+ }
+
+ private boolean isPackageWhitelistedForHiddenApis() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+ }
+
+ private boolean isAllowedToUseHiddenApis() {
+ if (isSignedWithPlatformKey()) {
+ return true;
+ } else if (isSystemApp() || isUpdatedSystemApp()) {
+ return usesNonSdkApi() || isPackageWhitelistedForHiddenApis();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int getHiddenApiEnforcementPolicy() {
+ if (isAllowedToUseHiddenApis()) {
+ return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
+ }
+
+ // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done
+ // entirely through ApplicationInfo and shouldn't touch this specific class, but that
+ // may not always hold true.
+// if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) {
+// return mHiddenApiPolicy;
+// }
+ return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED;
+ }
+
+ @Nullable
+ @Override
+ public SparseArray<int[]> getSplitDependencies() {
+ return splitDependencies;
+ }
+
+ @Override
+ public boolean requestsIsolatedSplitLoading() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0;
+ }
+
+ @Deprecated
+ @Override
+ public String getAppInfoClassLoaderName() {
+ return classLoaderName;
+ }
+
+ @Override
+ public String getClassLoaderName() {
+ return classLoaderName;
+ }
+
+ @Override
+ public String[] getSplitClassLoaderNames() {
+ return splitClassLoaderNames;
+ }
+
+ @Override
+ public String getOverlayCategory() {
+ return overlayCategory;
+ }
+
+ @Override
+ public boolean isProfileableByShell() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0;
+ }
+
+ @Nullable
+ @Override
+ public List<ParsedActivityIntentInfo> getPreferredActivityFilters() {
+ return preferredActivityFilters;
+ }
+
+ @Override
+ public boolean isHiddenUntilInstalled() {
+ return hiddenUntilInstalled;
+ }
+
+ @Override
+ public int getMinSdkVersion() {
+ return minSdkVersion;
+ }
+
+ @Override
+ public String getRestrictedAccountType() {
+ return restrictedAccountType;
+ }
+
+ @Override
+ public String getRequiredAccountType() {
+ return requiredAccountType;
+ }
+
+ @Override
+ public int getInstallLocation() {
+ return installLocation;
+ }
+
+ @Override
+ public List<ParsedActivity> getReceivers() {
+ return receivers;
+ }
+
+ @Override
+ public List<ParsedService> getServices() {
+ return services;
+ }
+
+ @Override
+ public List<ParsedProvider> getProviders() {
+ return providers;
+ }
+
+ @Override
+ public int getSharedUserLabel() {
+ return sharedUserLabel;
+ }
+
+ @Override
+ public int getVersionCodeMajor() {
+ return versionCodeMajor;
+ }
+
+ @Override
+ public boolean isRequiredForAllUsers() {
+ return requiredForAllUsers;
+ }
+
+ @Override
+ public int getCompileSdkVersion() {
+ return compileSdkVersion;
+ }
+
+ @Override
+ public String getCompileSdkVersionCodeName() {
+ return compileSdkVersionCodename;
+ }
+
+ @Nullable
+ @Override
+ public List<ConfigurationInfo> getConfigPreferences() {
+ return configPreferences;
+ }
+
+ @Nullable
+ @Override
+ public List<FeatureInfo> getReqFeatures() {
+ return reqFeatures;
+ }
+
+ @Override
+ public List<FeatureGroupInfo> getFeatureGroups() {
+ return featureGroups;
+ }
+
+ @Override
+ public String getDeviceProtectedDataDir() {
+ return deviceProtectedDataDir;
+ }
+
+ @Override
+ public String getCredentialProtectedDataDir() {
+ return credentialProtectedDataDir;
+ }
+
+ @Override
+ public String getSeInfoUser() {
+ return seInfoUser;
+ }
+
+ @Override
+ public String getClassName() {
+ return className;
+ }
+
+ @Override
+ public int getTheme() {
+ return theme;
+ }
+
+ @Override
+ public int getRequiresSmallestWidthDp() {
+ return requiresSmallestWidthDp;
+ }
+
+ @Override
+ public int getCompatibleWidthLimitDp() {
+ return compatibleWidthLimitDp;
+ }
+
+ @Override
+ public int getLargestWidthLimitDp() {
+ return largestWidthLimitDp;
+ }
+
+ @Override
+ public String getScanSourceDir() {
+ return applicationInfoCodePath;
+ }
+
+ @Override
+ public String getScanPublicSourceDir() {
+ return applicationInfoResourcePath;
+ }
+
+ @Override
+ public String getPublicSourceDir() {
+ return applicationInfoBaseResourcePath;
+ }
+
+ @Override
+ public String[] getSplitPublicSourceDirs() {
+ return applicationInfoSplitResourcePaths;
+ }
+
+ @Override
+ public String getSecondaryNativeLibraryDir() {
+ return secondaryNativeLibraryDir;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public String getManageSpaceActivityName() {
+ return manageSpaceActivityName;
+ }
+
+ @Override
+ public int getDescriptionRes() {
+ return descriptionRes;
+ }
+
+ @Override
+ public String getBackupAgentName() {
+ return backupAgentName;
+ }
+
+ @Override
+ public int getFullBackupContent() {
+ return fullBackupContent;
+ }
+
+ @Override
+ public int getNetworkSecurityConfigRes() {
+ return networkSecurityConfigRes;
+ }
+
+ @Override
+ public int getCategory() {
+ return category;
+ }
+
+ @Override
+ public int getTargetSandboxVersion() {
+ return targetSandboxVersion;
+ }
+
+ @Override
+ public String getAppComponentFactory() {
+ return appComponentFactory;
+ }
+
+ @Override
+ public int getIconRes() {
+ return iconRes;
+ }
+
+ @Override
+ public int getRoundIconRes() {
+ return roundIconRes;
+ }
+
+ @Override
+ public String getZygotePreloadName() {
+ return zygotePreloadName;
+ }
+
+ @Override
+ public int getLabelRes() {
+ return labelRes;
+ }
+
+ @Override
+ public CharSequence getNonLocalizedLabel() {
+ return nonLocalizedLabel;
+ }
+
+ @Override
+ public int getIcon() {
+ return icon;
+ }
+
+ @Override
+ public int getBanner() {
+ return banner;
+ }
+
+ @Override
+ public int getLogo() {
+ return logo;
+ }
+
+ @Override
+ public Bundle getMetaData() {
+ return appMetaData;
+ }
+
+ @Override
+ @Nullable
+ public List<Intent> getQueriesIntents() {
+ return queriesIntents;
+ }
+
+ @Override
+ @Nullable
+ public List<String> getQueriesPackages() {
+ return queriesPackages;
+ }
+
+ private static void internStringArrayList(List<String> list) {
+ if (list != null) {
+ final int N = list.size();
+ for (int i = 0; i < N; ++i) {
+ list.set(i, list.get(i).intern());
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(this.supportsSmallScreens);
+ dest.writeInt(this.supportsNormalScreens);
+ dest.writeInt(this.supportsLargeScreens);
+ dest.writeInt(this.supportsXLargeScreens);
+ dest.writeInt(this.resizeable);
+ dest.writeInt(this.anyDensity);
+ dest.writeLongArray(this.lastPackageUsageTimeInMills);
+ dest.writeInt(this.versionCode);
+ dest.writeInt(this.versionCodeMajor);
+ dest.writeInt(this.baseRevisionCode);
+ dest.writeString(this.versionName);
+ dest.writeBoolean(this.coreApp);
+ dest.writeInt(this.compileSdkVersion);
+ dest.writeString(this.compileSdkVersionCodename);
+ dest.writeString(this.packageName);
+ dest.writeString(this.realPackage);
+ dest.writeString(this.manifestPackageName);
+ dest.writeString(this.baseCodePath);
+ dest.writeBoolean(this.requiredForAllUsers);
+ dest.writeString(this.restrictedAccountType);
+ dest.writeString(this.requiredAccountType);
+ dest.writeBoolean(this.baseHardwareAccelerated);
+ dest.writeString(this.overlayTarget);
+ dest.writeString(this.overlayTargetName);
+ dest.writeString(this.overlayCategory);
+ dest.writeInt(this.overlayPriority);
+ dest.writeBoolean(this.overlayIsStatic);
+ dest.writeString(this.staticSharedLibName);
+ dest.writeLong(this.staticSharedLibVersion);
+ dest.writeStringList(this.libraryNames);
+ dest.writeStringList(this.usesLibraries);
+ dest.writeStringList(this.usesOptionalLibraries);
+ dest.writeStringList(this.usesStaticLibraries);
+ 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]);
+ }
+ }
+
+ dest.writeString(this.sharedUserId);
+ dest.writeInt(this.sharedUserLabel);
+ dest.writeTypedList(this.configPreferences);
+ dest.writeTypedList(this.reqFeatures);
+ dest.writeTypedList(this.featureGroups);
+ dest.writeByteArray(this.restrictUpdateHash);
+ dest.writeStringList(this.originalPackages);
+ dest.writeStringList(this.adoptPermissions);
+ dest.writeStringList(this.requestedPermissions);
+ dest.writeStringList(this.implicitPermissions);
+ dest.writeArraySet(this.upgradeKeySets);
+ dest.writeMap(this.keySetMapping);
+ dest.writeStringList(this.protectedBroadcasts);
+ dest.writeTypedList(this.activities);
+ dest.writeTypedList(this.receivers);
+ dest.writeTypedList(this.services);
+ dest.writeTypedList(this.providers);
+ dest.writeTypedList(this.permissions);
+ dest.writeTypedList(this.permissionGroups);
+ dest.writeTypedList(this.instrumentations);
+ ParsedIntentInfo.writeIntentsList(this.preferredActivityFilters, dest, flags);
+ dest.writeBundle(this.appMetaData);
+ dest.writeString(this.volumeUuid);
+ dest.writeString(this.applicationVolumeUuid);
+ dest.writeParcelable(this.signingDetails, flags);
+ dest.writeString(this.codePath);
+ dest.writeBoolean(this.use32BitAbi);
+ dest.writeBoolean(this.visibleToInstantApps);
+ dest.writeString(this.cpuAbiOverride);
+ dest.writeBoolean(this.isStub);
+ dest.writeInt(this.preferredOrder);
+ dest.writeBoolean(this.forceQueryable);
+ dest.writeParcelableList(this.queriesIntents, flags);
+ dest.writeStringList(this.queriesPackages);
+ dest.writeString(this.applicationInfoBaseResourcePath);
+ dest.writeString(this.applicationInfoCodePath);
+ dest.writeString(this.applicationInfoResourcePath);
+ dest.writeStringArray(this.applicationInfoSplitResourcePaths);
+ 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.writeString(this.credentialProtectedDataDir);
+ dest.writeString(this.dataDir);
+ dest.writeInt(this.descriptionRes);
+ dest.writeString(this.deviceProtectedDataDir);
+ dest.writeBoolean(this.enabled);
+ dest.writeInt(this.flags);
+ dest.writeInt(this.fullBackupContent);
+ dest.writeBoolean(this.hiddenUntilInstalled);
+ dest.writeInt(this.icon);
+ 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.writeString(this.name);
+ dest.writeString(this.nativeLibraryDir);
+ dest.writeString(this.nativeLibraryRootDir);
+ dest.writeBoolean(this.nativeLibraryRootRequiresIsa);
+ dest.writeInt(this.networkSecurityConfigRes);
+ dest.writeCharSequence(this.nonLocalizedLabel);
+ dest.writeString(this.permission);
+ dest.writeString(this.primaryCpuAbi);
+ dest.writeInt(this.privateFlags);
+ dest.writeString(this.processName);
+ dest.writeInt(this.requiresSmallestWidthDp);
+ dest.writeInt(this.roundIconRes);
+ dest.writeString(this.secondaryCpuAbi);
+ dest.writeString(this.secondaryNativeLibraryDir);
+ dest.writeString(this.seInfo);
+ dest.writeString(this.seInfoUser);
+ dest.writeInt(this.targetSandboxVersion);
+ dest.writeInt(this.targetSdkVersion);
+ dest.writeString(this.taskAffinity);
+ dest.writeInt(this.theme);
+ dest.writeInt(this.uid);
+ dest.writeInt(this.uiOptions);
+ dest.writeStringArray(this.usesLibraryFiles);
+ dest.writeTypedList(this.usesLibraryInfos);
+ 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);
+ }
+
+ public PackageImpl(Parcel in) {
+ // We use the boot classloader for all classes that we load.
+ final ClassLoader boot = Object.class.getClassLoader();
+ this.supportsSmallScreens = in.readInt();
+ this.supportsNormalScreens = in.readInt();
+ this.supportsLargeScreens = in.readInt();
+ this.supportsXLargeScreens = in.readInt();
+ this.resizeable = in.readInt();
+ this.anyDensity = in.readInt();
+ this.lastPackageUsageTimeInMills = in.createLongArray();
+ this.versionCode = in.readInt();
+ this.versionCodeMajor = in.readInt();
+ this.baseRevisionCode = in.readInt();
+ this.versionName = TextUtils.safeIntern(in.readString());
+ this.coreApp = in.readBoolean();
+ this.compileSdkVersion = in.readInt();
+ this.compileSdkVersionCodename = TextUtils.safeIntern(in.readString());
+ this.packageName = TextUtils.safeIntern(in.readString());
+ this.realPackage = in.readString();
+ this.manifestPackageName = in.readString();
+ this.baseCodePath = in.readString();
+ this.requiredForAllUsers = in.readBoolean();
+ this.restrictedAccountType = in.readString();
+ this.requiredAccountType = in.readString();
+ this.baseHardwareAccelerated = in.readBoolean();
+ this.overlayTarget = in.readString();
+ this.overlayTargetName = in.readString();
+ this.overlayCategory = in.readString();
+ this.overlayPriority = in.readInt();
+ this.overlayIsStatic = in.readBoolean();
+ this.staticSharedLibName = TextUtils.safeIntern(in.readString());
+ this.staticSharedLibVersion = in.readLong();
+ this.libraryNames = in.createStringArrayList();
+ internStringArrayList(this.libraryNames);
+ this.usesLibraries = in.createStringArrayList();
+ internStringArrayList(this.usesLibraries);
+ this.usesOptionalLibraries = in.createStringArrayList();
+ internStringArrayList(this.usesOptionalLibraries);
+ this.usesStaticLibraries = in.createStringArrayList();
+ internStringArrayList(usesStaticLibraries);
+ 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] = in.readStringArray();
+ }
+ }
+
+ this.sharedUserId = TextUtils.safeIntern(in.readString());
+ 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 = in.createStringArrayList();
+ this.requestedPermissions = in.createStringArrayList();
+ internStringArrayList(this.requestedPermissions);
+ this.implicitPermissions = in.createStringArrayList();
+ internStringArrayList(this.implicitPermissions);
+ this.upgradeKeySets = (ArraySet<String>) in.readArraySet(boot);
+ this.keySetMapping = in.readHashMap(boot);
+ this.protectedBroadcasts = in.createStringArrayList();
+ internStringArrayList(this.protectedBroadcasts);
+ this.activities = in.createTypedArrayList(ParsedActivity.CREATOR);
+ this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
+ this.services = in.createTypedArrayList(ParsedService.CREATOR);
+ this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
+ this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
+ this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
+ this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
+ this.preferredActivityFilters = ParsedIntentInfo.createIntentsList(in);
+ this.appMetaData = in.readBundle(boot);
+ this.volumeUuid = in.readString();
+ this.applicationVolumeUuid = in.readString();
+ this.signingDetails = in.readParcelable(boot);
+ this.codePath = in.readString();
+ this.use32BitAbi = in.readBoolean();
+ this.visibleToInstantApps = in.readBoolean();
+ this.cpuAbiOverride = in.readString();
+ this.isStub = in.readBoolean();
+ this.preferredOrder = in.readInt();
+ this.forceQueryable = in.readBoolean();
+ this.queriesIntents = in.createTypedArrayList(Intent.CREATOR);
+ this.queriesPackages = in.createStringArrayList();
+ internStringArrayList(this.queriesPackages);
+ this.applicationInfoBaseResourcePath = in.readString();
+ this.applicationInfoCodePath = in.readString();
+ this.applicationInfoResourcePath = in.readString();
+ this.applicationInfoSplitResourcePaths = in.createStringArray();
+ 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.credentialProtectedDataDir = in.readString();
+ this.dataDir = in.readString();
+ this.descriptionRes = in.readInt();
+ this.deviceProtectedDataDir = in.readString();
+ this.enabled = in.readBoolean();
+ this.flags = in.readInt();
+ this.fullBackupContent = in.readInt();
+ this.hiddenUntilInstalled = in.readBoolean();
+ this.icon = 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.name = in.readString();
+ this.nativeLibraryDir = in.readString();
+ this.nativeLibraryRootDir = in.readString();
+ this.nativeLibraryRootRequiresIsa = in.readBoolean();
+ this.networkSecurityConfigRes = in.readInt();
+ this.nonLocalizedLabel = in.readCharSequence();
+ this.permission = TextUtils.safeIntern(in.readString());
+ this.primaryCpuAbi = in.readString();
+ this.privateFlags = in.readInt();
+ this.processName = in.readString();
+ this.requiresSmallestWidthDp = in.readInt();
+ this.roundIconRes = in.readInt();
+ this.secondaryCpuAbi = in.readString();
+ this.secondaryNativeLibraryDir = in.readString();
+ this.seInfo = in.readString();
+ this.seInfoUser = in.readString();
+ this.targetSandboxVersion = in.readInt();
+ this.targetSdkVersion = in.readInt();
+ this.taskAffinity = in.readString();
+ this.theme = in.readInt();
+ this.uid = in.readInt();
+ this.uiOptions = in.readInt();
+ this.usesLibraryFiles = in.createStringArray();
+ this.usesLibraryInfos = in.createTypedArrayList(SharedLibraryInfo.CREATOR);
+ 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();
+ }
+
+ public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
+ @Override
+ public PackageImpl createFromParcel(Parcel source) {
+ return new PackageImpl(source);
+ }
+
+ @Override
+ public PackageImpl[] newArray(int size) {
+ return new PackageImpl[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
new file mode 100644
index 000000000000..af9ba8d1ed90
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FallbackCategoryProvider;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.SELinuxUtil;
+import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Set;
+
+/** @hide */
+public class PackageInfoUtils {
+
+ private static final String TAG = ApkParseUtils.TAG;
+
+ /**
+ * Returns true if the package is installed and not hidden, or if the caller
+ * explicitly wanted all uninstalled and hidden packages as well.
+ */
+ private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state,
+ @PackageManager.PackageInfoFlags int flags) {
+ // Returns false if the package is hidden system app until installed.
+ if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
+ && !state.installed
+ && pkg.isHiddenUntilInstalled()) {
+ return false;
+ }
+
+ // If available for the target user, or trying to match uninstalled packages and it's
+ // a system app.
+ return state.isAvailable(flags)
+ || (pkg.isSystemApp()
+ && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+ || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
+ }
+
+ public static PackageInfo generate(AndroidPackage pkg, int[] gids,
+ @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+ Set<String> grantedPermissions, PackageUserState state, int userId) {
+ if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
+ return null;
+ }
+ ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = pkg.getPackageName();
+ pi.splitNames = pkg.getSplitNames();
+ pi.versionCode = pkg.getVersionCode();
+ pi.versionCodeMajor = pkg.getVersionCodeMajor();
+ pi.baseRevisionCode = pkg.getBaseRevisionCode();
+ pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
+ pi.versionName = pkg.getVersionName();
+ pi.sharedUserId = pkg.getSharedUserId();
+ pi.sharedUserLabel = pkg.getSharedUserLabel();
+ pi.applicationInfo = applicationInfo;
+ pi.installLocation = pkg.getInstallLocation();
+ pi.isStub = pkg.isStub();
+ pi.coreApp = pkg.isCoreApp();
+ if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+ || (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+ pi.requiredForAllUsers = pkg.isRequiredForAllUsers();
+ }
+ pi.restrictedAccountType = pkg.getRestrictedAccountType();
+ pi.requiredAccountType = pkg.getRequiredAccountType();
+ pi.overlayTarget = pkg.getOverlayTarget();
+ pi.targetOverlayableName = pkg.getOverlayTargetName();
+ pi.overlayCategory = pkg.getOverlayCategory();
+ pi.overlayPriority = pkg.getOverlayPriority();
+ pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
+ pi.compileSdkVersion = pkg.getCompileSdkVersion();
+ pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
+ pi.firstInstallTime = firstInstallTime;
+ pi.lastUpdateTime = lastUpdateTime;
+ if ((flags & PackageManager.GET_GIDS) != 0) {
+ pi.gids = gids;
+ }
+ if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
+ int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0;
+ if (size > 0) {
+ pi.configPreferences = new ConfigurationInfo[size];
+ pkg.getConfigPreferences().toArray(pi.configPreferences);
+ }
+ size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0;
+ if (size > 0) {
+ pi.reqFeatures = new FeatureInfo[size];
+ pkg.getReqFeatures().toArray(pi.reqFeatures);
+ }
+ size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0;
+ if (size > 0) {
+ pi.featureGroups = new FeatureGroupInfo[size];
+ pkg.getFeatureGroups().toArray(pi.featureGroups);
+ }
+ }
+ if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+ if (pkg.getActivities() != null) {
+ final int N = pkg.getActivities().size();
+ if (N > 0) {
+ int num = 0;
+ final ActivityInfo[] res = new ActivityInfo[N];
+ for (int i = 0; i < N; i++) {
+ final ParsedActivity a = pkg.getActivities().get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
+ a.className)) {
+ continue;
+ }
+ res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
+ userId);
+ }
+ }
+ pi.activities = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ }
+ if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+ if (pkg.getReceivers() != null) {
+ final int size = pkg.getReceivers().size();
+ if (size > 0) {
+ int num = 0;
+ final ActivityInfo[] res = new ActivityInfo[size];
+ for (int i = 0; i < size; i++) {
+ final ParsedActivity a = pkg.getReceivers().get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+ res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
+ userId);
+ }
+ }
+ pi.receivers = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ }
+ if ((flags & PackageManager.GET_SERVICES) != 0) {
+ if (pkg.getServices() != null) {
+ final int size = pkg.getServices().size();
+ if (size > 0) {
+ int num = 0;
+ final ServiceInfo[] res = new ServiceInfo[size];
+ for (int i = 0; i < size; i++) {
+ final ComponentParseUtils.ParsedService s = pkg.getServices().get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
+ res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
+ userId);
+ }
+ }
+ pi.services = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ }
+ if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+ if (pkg.getProviders() != null) {
+ final int size = pkg.getProviders().size();
+ if (size > 0) {
+ int num = 0;
+ final ProviderInfo[] res = new ProviderInfo[size];
+ for (int i = 0; i < size; i++) {
+ final ComponentParseUtils.ParsedProvider pr = pkg.getProviders()
+ .get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
+ res[num++] = generateProviderInfo(pkg, pr, flags, state,
+ applicationInfo, userId);
+ }
+ }
+ pi.providers = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ }
+ if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
+ if (pkg.getInstrumentations() != null) {
+ int N = pkg.getInstrumentations().size();
+ if (N > 0) {
+ pi.instrumentation = new InstrumentationInfo[N];
+ for (int i = 0; i < N; i++) {
+ pi.instrumentation[i] = generateInstrumentationInfo(
+ pkg.getInstrumentations().get(i), pkg, flags);
+ }
+ }
+ }
+ }
+ if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
+ if (pkg.getPermissions() != null) {
+ int N = ArrayUtils.size(pkg.getPermissions());
+ if (N > 0) {
+ pi.permissions = new PermissionInfo[N];
+ for (int i = 0; i < N; i++) {
+ pi.permissions[i] = generatePermissionInfo(
+ pkg.getPermissions().get(i),
+ flags
+ );
+ }
+ }
+ }
+ if (pkg.getRequestedPermissions() != null) {
+ int N = pkg.getRequestedPermissions().size();
+ if (N > 0) {
+ pi.requestedPermissions = new String[N];
+ pi.requestedPermissionsFlags = new int[N];
+ for (int i = 0; i < N; i++) {
+ final String perm = pkg.getRequestedPermissions().get(i);
+ pi.requestedPermissions[i] = perm;
+ // The notion of required permissions is deprecated but for compatibility.
+ pi.requestedPermissionsFlags[i] |=
+ PackageInfo.REQUESTED_PERMISSION_REQUIRED;
+ if (grantedPermissions != null && grantedPermissions.contains(perm)) {
+ pi.requestedPermissionsFlags[i] |=
+ PackageInfo.REQUESTED_PERMISSION_GRANTED;
+ }
+ }
+ }
+ }
+ }
+
+ PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
+ // deprecated method of getting signing certificates
+ if ((flags & PackageManager.GET_SIGNATURES) != 0) {
+ if (signingDetails.hasPastSigningCertificates()) {
+ // Package has included signing certificate rotation information. Return the oldest
+ // cert so that programmatic checks keep working even if unaware of key rotation.
+ pi.signatures = new Signature[1];
+ pi.signatures[0] = signingDetails.pastSigningCertificates[0];
+ } else if (signingDetails.hasSignatures()) {
+ // otherwise keep old behavior
+ int numberOfSigs = signingDetails.signatures.length;
+ pi.signatures = new Signature[numberOfSigs];
+ System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
+ numberOfSigs);
+ }
+ }
+
+ // replacement for GET_SIGNATURES
+ if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
+ if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
+ // only return a valid SigningInfo if there is signing information to report
+ pi.signingInfo = new SigningInfo(signingDetails);
+ } else {
+ pi.signingInfo = null;
+ }
+ }
+
+ return pi;
+ }
+
+ @Nullable
+ public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
+ @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
+
+ if (pkg == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
+ return null;
+ }
+
+ // Make shallow copy so we can store the metadata/libraries safely
+ ApplicationInfo ai = pkg.toAppInfoWithoutState();
+ ai.initForUser(userId);
+ if ((flags & PackageManager.GET_META_DATA) == 0) {
+ ai.metaData = null;
+ }
+ if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
+ ai.sharedLibraryFiles = null;
+ ai.sharedLibraryInfos = null;
+ }
+ if (state.stopped) {
+ ai.flags |= ApplicationInfo.FLAG_STOPPED;
+ } else {
+ ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
+ }
+ updateApplicationInfo(ai, flags, state);
+
+ return ai;
+ }
+
+ private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+ @Nullable ApplicationInfo applicationInfo, int userId) {
+ if (a == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+ return null;
+ }
+ if (applicationInfo == null) {
+ applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+ }
+ // Make shallow copies so we can store the metadata safely
+ ActivityInfo ai = new ActivityInfo();
+ assignSharedFieldsForComponentInfo(ai, a);
+ ai.targetActivity = a.targetActivity;
+ ai.processName = a.getProcessName();
+ ai.exported = a.exported;
+ ai.theme = a.theme;
+ ai.uiOptions = a.uiOptions;
+ ai.parentActivityName = a.parentActivityName;
+ ai.permission = a.getPermission();
+ ai.taskAffinity = a.taskAffinity;
+ ai.flags = a.flags;
+ ai.privateFlags = a.privateFlags;
+ ai.launchMode = a.launchMode;
+ ai.documentLaunchMode = a.documentLaunchMode;
+ ai.maxRecents = a.maxRecents;
+ ai.configChanges = a.configChanges;
+ ai.softInputMode = a.softInputMode;
+ ai.persistableMode = a.persistableMode;
+ ai.lockTaskLaunchMode = a.lockTaskLaunchMode;
+ ai.screenOrientation = a.screenOrientation;
+ ai.resizeMode = a.resizeMode;
+ ai.maxAspectRatio = a.maxAspectRatio;
+ ai.minAspectRatio = a.minAspectRatio;
+ ai.requestedVrComponent = a.requestedVrComponent;
+ ai.rotationAnimation = a.rotationAnimation;
+ ai.colorMode = a.colorMode;
+ ai.windowLayout = a.windowLayout;
+ ai.metaData = a.metaData;
+ ai.applicationInfo = applicationInfo;
+ return ai;
+ }
+
+ public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+ return generateActivityInfo(pkg, a, flags, state, null, userId);
+ }
+
+ private static ServiceInfo generateServiceInfo(AndroidPackage pkg,
+ ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
+ PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
+ if (s == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+ return null;
+ }
+ if (applicationInfo == null) {
+ applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+ }
+ // Make shallow copies so we can store the metadata safely
+ ServiceInfo si = new ServiceInfo();
+ assignSharedFieldsForComponentInfo(si, s);
+ si.exported = s.exported;
+ si.flags = s.flags;
+ si.metaData = s.metaData;
+ si.permission = s.getPermission();
+ si.processName = s.getProcessName();
+ si.mForegroundServiceType = s.foregroundServiceType;
+ si.metaData = s.metaData;
+ si.applicationInfo = applicationInfo;
+ return si;
+ }
+
+ public static ServiceInfo generateServiceInfo(AndroidPackage pkg,
+ ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
+ PackageUserState state, int userId) {
+ return generateServiceInfo(pkg, s, flags, state, null, userId);
+ }
+
+ private static ProviderInfo generateProviderInfo(AndroidPackage pkg,
+ ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
+ PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
+ if (p == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+ return null;
+ }
+ if (applicationInfo == null) {
+ applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+ }
+ // Make shallow copies so we can store the metadata safely
+ ProviderInfo pi = new ProviderInfo();
+ assignSharedFieldsForComponentInfo(pi, p);
+ pi.exported = p.exported;
+ pi.flags = p.flags;
+ pi.processName = p.getProcessName();
+ pi.authority = p.getAuthority();
+ pi.isSyncable = p.isSyncable;
+ pi.readPermission = p.getReadPermission();
+ pi.writePermission = p.getWritePermission();
+ pi.grantUriPermissions = p.grantUriPermissions;
+ pi.forceUriPermissions = p.forceUriPermissions;
+ pi.multiprocess = p.multiProcess;
+ pi.initOrder = p.initOrder;
+ pi.uriPermissionPatterns = p.uriPermissionPatterns;
+ pi.pathPermissions = p.pathPermissions;
+ pi.metaData = p.metaData;
+ if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
+ pi.uriPermissionPatterns = null;
+ }
+ pi.applicationInfo = applicationInfo;
+ return pi;
+ }
+
+ public static ProviderInfo generateProviderInfo(AndroidPackage pkg,
+ ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
+ PackageUserState state, int userId) {
+ return generateProviderInfo(pkg, p, flags, state, null, userId);
+ }
+
+ public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+ AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags) {
+ if (i == null) return null;
+
+ InstrumentationInfo ii = new InstrumentationInfo();
+ assignSharedFieldsForPackageItemInfo(ii, i);
+ ii.targetPackage = i.getTargetPackage();
+ ii.targetProcesses = i.getTargetProcesses();
+ ii.handleProfiling = i.handleProfiling;
+ ii.functionalTest = i.functionalTest;
+
+ ii.sourceDir = pkg.getBaseCodePath();
+ ii.publicSourceDir = pkg.getBaseCodePath();
+ ii.splitNames = pkg.getSplitNames();
+ ii.splitSourceDirs = pkg.getSplitCodePaths();
+ ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
+ ii.splitDependencies = pkg.getSplitDependencies();
+ ii.dataDir = pkg.getDataDir();
+ ii.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir();
+ ii.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir();
+ ii.primaryCpuAbi = pkg.getPrimaryCpuAbi();
+ ii.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
+ ii.nativeLibraryDir = pkg.getNativeLibraryDir();
+ ii.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
+
+ if ((flags & PackageManager.GET_META_DATA) == 0) {
+ return ii;
+ }
+ ii.metaData = i.metaData;
+ return ii;
+ }
+
+ public static PermissionInfo generatePermissionInfo(ParsedPermission p,
+ @PackageManager.ComponentInfoFlags int flags) {
+ if (p == null) return null;
+
+ PermissionInfo pi = new PermissionInfo(p.backgroundPermission);
+ assignSharedFieldsForPackageItemInfo(pi, p);
+ pi.group = p.getGroup();
+ pi.requestRes = p.requestRes;
+ pi.protectionLevel = p.protectionLevel;
+ pi.descriptionRes = p.descriptionRes;
+ pi.flags = p.flags;
+
+ if ((flags & PackageManager.GET_META_DATA) == 0) {
+ return pi;
+ }
+ pi.metaData = p.metaData;
+ return pi;
+ }
+
+ public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
+ @PackageManager.ComponentInfoFlags int flags) {
+ if (pg == null) return null;
+
+ PermissionGroupInfo pgi = new PermissionGroupInfo(
+ pg.requestDetailResourceId,
+ pg.backgroundRequestResourceId,
+ pg.backgroundRequestDetailResourceId
+ );
+ assignSharedFieldsForPackageItemInfo(pgi, pg);
+ pgi.priority = pg.priority;
+ pgi.requestRes = pg.requestRes;
+ pgi.flags = pg.flags;
+
+ if ((flags & PackageManager.GET_META_DATA) == 0) {
+ return pgi;
+ }
+ pgi.metaData = pg.metaData;
+ return pgi;
+ }
+
+ private static void updateApplicationInfo(ApplicationInfo ai,
+ @PackageManager.ApplicationInfoFlags int flags,
+ PackageUserState state) {
+ // CompatibilityMode is global state.
+ if (!PackageParser.sCompatibilityModeEnabled) {
+ ai.disableCompatibilityMode();
+ }
+ if (state.installed) {
+ ai.flags |= ApplicationInfo.FLAG_INSTALLED;
+ } else {
+ ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+ }
+ if (state.suspended) {
+ ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
+ } else {
+ ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
+ }
+ if (state.instantApp) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
+ } else {
+ ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
+ }
+ if (state.virtualPreload) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
+ } else {
+ ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
+ }
+ if (state.hidden) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+ } else {
+ ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+ }
+ if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ ai.enabled = true;
+ } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
+ } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+ ai.enabled = false;
+ }
+ ai.enabledSetting = state.enabled;
+ if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+ ai.category = state.categoryHint;
+ }
+ if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+ ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
+ }
+ ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
+ ai.resourceDirs = state.overlayPaths;
+ ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0)
+ ? ai.roundIconRes : ai.iconRes;
+ }
+
+ private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo,
+ ComponentParseUtils.ParsedComponent parsedComponent) {
+ packageItemInfo.banner = parsedComponent.banner;
+ packageItemInfo.icon = parsedComponent.icon;
+ packageItemInfo.labelRes = parsedComponent.labelRes;
+ packageItemInfo.logo = parsedComponent.logo;
+ packageItemInfo.name = parsedComponent.className;
+ packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel;
+ packageItemInfo.packageName = parsedComponent.getPackageName();
+ }
+
+ private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo,
+ ComponentParseUtils.ParsedComponent parsedComponent) {
+ assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent);
+ componentInfo.descriptionRes = parsedComponent.descriptionRes;
+ componentInfo.directBootAware = parsedComponent.directBootAware;
+ componentInfo.enabled = parsedComponent.enabled;
+ componentInfo.splitName = parsedComponent.getSplitName();
+ }
+
+}
diff --git a/core/java/android/content/pm/parsing/ParsedPackage.java b/core/java/android/content/pm/parsing/ParsedPackage.java
new file mode 100644
index 000000000000..05cf586522f2
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsedPackage.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.content.pm.PackageParser;
+
+/**
+ * Methods used for mutation after direct package parsing, mostly done inside
+ * {@link com.android.server.pm.PackageManagerService}.
+ *
+ * Java disallows defining this as an inner interface, so this must be a separate file.
+ *
+ * @hide
+ */
+public interface ParsedPackage extends AndroidPackage {
+
+ AndroidPackage hideAsFinal();
+
+ ParsedPackage addUsesLibrary(int index, String libraryName);
+
+ ParsedPackage addUsesOptionalLibrary(int index, String libraryName);
+
+ ParsedPackage capPermissionPriorities();
+
+ ParsedPackage clearAdoptPermissions();
+
+ ParsedPackage clearOriginalPackages();
+
+ ParsedPackage clearProtectedBroadcasts();
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #setCodePath(String)}
+ */
+ @Deprecated
+ ParsedPackage setApplicationInfoCodePath(String applicationInfoCodePath);
+
+ /**
+ * TODO(b/135203078): Use non-AppInfo method
+ * @deprecated use {@link #setCodePath(String)}
+ */
+ @Deprecated
+ ParsedPackage setApplicationInfoResourcePath(String applicationInfoResourcePath);
+
+ ParsedPackage setBaseCodePath(String baseCodePath);
+
+ ParsedPackage setCodePath(String codePath);
+
+ ParsedPackage setCpuAbiOverride(String cpuAbiOverride);
+
+ ParsedPackage setNativeLibraryDir(String nativeLibraryDir);
+
+ ParsedPackage setNativeLibraryRootDir(String nativeLibraryRootDir);
+
+ ParsedPackage setPackageName(String packageName);
+
+ ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi);
+
+ ParsedPackage setProcessName(String processName);
+
+ ParsedPackage setRealPackage(String realPackage);
+
+ ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi);
+
+ ParsedPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+
+ ParsedPackage setSplitCodePaths(String[] splitCodePaths);
+
+ ParsedPackage initForUser(int userId);
+
+ ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa);
+
+ ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware);
+
+ ParsedPackage setFactoryTest(boolean factoryTest);
+
+ ParsedPackage markNotActivitiesAsNotExportedIfSingleUser();
+
+ ParsedPackage setOdm(boolean odm);
+
+ ParsedPackage setOem(boolean oem);
+
+ ParsedPackage setPrivileged(boolean privileged);
+
+ ParsedPackage setProduct(boolean product);
+
+ ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey);
+
+ ParsedPackage setSystem(boolean system);
+
+ ParsedPackage setSystemExt(boolean systemExt);
+
+ ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp);
+
+ ParsedPackage setVendor(boolean vendor);
+
+ ParsedPackage removePermission(int index);
+
+ ParsedPackage removeUsesLibrary(String libraryName);
+
+ ParsedPackage removeUsesOptionalLibrary(String libraryName);
+
+ ParsedPackage setApplicationInfoBaseResourcePath(String applicationInfoBaseResourcePath);
+
+ ParsedPackage setApplicationInfoSplitResourcePaths(
+ String[] applicationInfoSplitResourcePaths);
+
+ ParsedPackage setApplicationVolumeUuid(String applicationVolumeUuid);
+
+ ParsedPackage setCoreApp(boolean coreApp);
+
+ ParsedPackage setIsStub(boolean isStub);
+
+ // TODO(b/135203078): Remove entirely
+ ParsedPackage setPackageSettingCallback(PackageSettingCallback packageSettingCallback);
+
+ ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
+
+ ParsedPackage setSeInfo(String seInfo);
+
+ ParsedPackage setSeInfoUser(String seInfoUser);
+
+ ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir);
+
+ ParsedPackage setUid(int uid);
+
+ ParsedPackage setVersionCode(int versionCode);
+
+ ParsedPackage setVersionCodeMajor(int versionCodeMajor);
+
+ // TODO(b/135203078): Move logic earlier in parse chain so nothing needs to be reverted
+ ParsedPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage);
+
+ ParsedPackage setDirectBootAware(boolean directBootAware);
+
+ ParsedPackage setPersistent(boolean persistent);
+
+ interface PackageSettingCallback {
+ default void setAndroidPackage(AndroidPackage pkg){}
+ }
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
new file mode 100644
index 000000000000..43c1f6e335b0
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import java.security.PublicKey;
+
+/**
+ * Methods used for mutation during direct package parsing.
+ *
+ * Java disallows defining this as an inner interface, so this must be a separate file.
+ *
+ * @hide
+ */
+public interface ParsingPackage extends AndroidPackage {
+
+ ParsingPackage addActivity(ParsedActivity parsedActivity);
+
+ ParsingPackage addAdoptPermission(String adoptPermission);
+
+ ParsingPackage addConfigPreference(ConfigurationInfo configPreference);
+
+ ParsingPackage addFeatureGroup(FeatureGroupInfo featureGroup);
+
+ ParsingPackage addImplicitPermission(String permission);
+
+ ParsingPackage addInstrumentation(ParsedInstrumentation instrumentation);
+
+ ParsingPackage addKeySet(String keySetName, PublicKey publicKey);
+
+ ParsingPackage addLibraryName(String libraryName);
+
+ ParsingPackage addOriginalPackage(String originalPackage);
+
+ ParsingPackage addPermission(ParsedPermission permission);
+
+ ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);
+
+ ParsingPackage addPreferredActivityFilter(ParsedActivityIntentInfo activityIntentInfo);
+
+ ParsingPackage addProtectedBroadcast(String protectedBroadcast);
+
+ ParsingPackage addProvider(ParsedProvider parsedProvider);
+
+ ParsingPackage addReceiver(ParsedActivity parsedReceiver);
+
+ ParsingPackage addReqFeature(FeatureInfo reqFeature);
+
+ ParsingPackage addRequestedPermission(String permission);
+
+ ParsingPackage addService(ParsedService parsedService);
+
+ ParsingPackage addUsesLibrary(String libraryName);
+
+ ParsingPackage addUsesOptionalLibrary(String libraryName);
+
+ ParsingPackage addUsesStaticLibrary(String libraryName);
+
+ ParsingPackage addUsesStaticLibraryCertDigests(String[] certSha256Digests);
+
+ ParsingPackage addUsesStaticLibraryVersion(long version);
+
+ ParsingPackage addQueriesIntent(Intent intent);
+
+ ParsingPackage addQueriesPackage(String packageName);
+
+ ParsingPackage asSplit(
+ String[] splitNames,
+ String[] splitCodePaths,
+ int[] splitRevisionCodes,
+ @Nullable SparseArray<int[]> splitDependencies
+ );
+
+ ParsingPackage setAppMetaData(Bundle appMetaData);
+
+ ParsingPackage setForceQueryable(boolean forceQueryable);
+
+ ParsingPackage setMaxAspectRatio(float maxAspectRatio);
+
+ ParsingPackage setMinAspectRatio(float minAspectRatio);
+
+ ParsingPackage setName(String name);
+
+ ParsingPackage setPermission(String permission);
+
+ ParsingPackage setProcessName(String processName);
+
+ ParsingPackage setSharedUserId(String sharedUserId);
+
+ ParsingPackage setStaticSharedLibName(String staticSharedLibName);
+
+ ParsingPackage setTaskAffinity(String taskAffinity);
+
+ ParsingPackage setTargetSdkVersion(int targetSdkVersion);
+
+ ParsingPackage setUiOptions(int uiOptions);
+
+ ParsingPackage setBaseHardwareAccelerated(boolean baseHardwareAccelerated);
+
+ ParsingPackage setActivitiesResizeModeResizeable(boolean resizeable);
+
+ ParsingPackage setActivitiesResizeModeResizeableViaSdkVersion(boolean resizeableViaSdkVersion);
+
+ ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture);
+
+ ParsingPackage setAllowBackup(boolean allowBackup);
+
+ ParsingPackage setAllowClearUserData(boolean allowClearUserData);
+
+ ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore);
+
+ ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
+
+ ParsingPackage setIsOverlay(boolean isOverlay);
+
+ ParsingPackage setBackupInForeground(boolean backupInForeground);
+
+ ParsingPackage setCantSaveState(boolean cantSaveState);
+
+ ParsingPackage setDebuggable(boolean debuggable);
+
+ ParsingPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage);
+
+ ParsingPackage setDirectBootAware(boolean directBootAware);
+
+ ParsingPackage setExternalStorage(boolean externalStorage);
+
+ ParsingPackage setExtractNativeLibs(boolean extractNativeLibs);
+
+ ParsingPackage setFullBackupOnly(boolean fullBackupOnly);
+
+ ParsingPackage setHasCode(boolean hasCode);
+
+ ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
+
+ ParsingPackage setIsGame(boolean isGame);
+
+ ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
+
+ ParsingPackage setKillAfterRestore(boolean killAfterRestore);
+
+ ParsingPackage setLargeHeap(boolean largeHeap);
+
+ ParsingPackage setMultiArch(boolean multiArch);
+
+ ParsingPackage setPartiallyDirectBootAware(boolean partiallyDirectBootAware);
+
+ ParsingPackage setPersistent(boolean persistent);
+
+ ParsingPackage setProfileableByShell(boolean profileableByShell);
+
+ ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage);
+
+ ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion);
+
+ ParsingPackage setSplitHasCode(int splitIndex, boolean splitHasCode);
+
+ ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary);
+
+ ParsingPackage setSupportsRtl(boolean supportsRtl);
+
+ ParsingPackage setTestOnly(boolean testOnly);
+
+ ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex);
+
+ ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic);
+
+ ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi);
+
+ ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps);
+
+ ParsingPackage setVmSafeMode(boolean vmSafeMode);
+
+ ParsingPackage removeUsesOptionalLibrary(String libraryName);
+
+ ParsingPackage setAnyDensity(int anyDensity);
+
+ ParsingPackage setAppComponentFactory(String appComponentFactory);
+
+ ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid);
+
+ ParsingPackage setBackupAgentName(String backupAgentName);
+
+ ParsingPackage setBanner(int banner);
+
+ ParsingPackage setCategory(int category);
+
+ ParsingPackage setClassLoaderName(String classLoaderName);
+
+ ParsingPackage setClassName(String className);
+
+ ParsingPackage setCodePath(String codePath);
+
+ ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
+
+ ParsingPackage setDescriptionRes(int descriptionRes);
+
+ ParsingPackage setEnabled(boolean enabled);
+
+ ParsingPackage setFullBackupContent(int fullBackupContent);
+
+ ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
+
+ ParsingPackage setIcon(int icon);
+
+ ParsingPackage setIconRes(int iconRes);
+
+ ParsingPackage setInstallLocation(int installLocation);
+
+ ParsingPackage setLabelRes(int labelRes);
+
+ ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
+
+ ParsingPackage setLogo(int logo);
+
+ ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName);
+
+ ParsingPackage setMinSdkVersion(int minSdkVersion);
+
+ ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
+
+ ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
+
+ ParsingPackage setOverlayCategory(String overlayCategory);
+
+ ParsingPackage setOverlayIsStatic(boolean overlayIsStatic);
+
+ ParsingPackage setOverlayPriority(int overlayPriority);
+
+ ParsingPackage setOverlayTarget(String overlayTarget);
+
+ ParsingPackage setOverlayTargetName(String overlayTargetName);
+
+ ParsingPackage setRealPackage(String realPackage);
+
+ ParsingPackage setRequiredAccountType(String requiredAccountType);
+
+ ParsingPackage setRequiredForAllUsers(boolean requiredForAllUsers);
+
+ ParsingPackage setRequiresSmallestWidthDp(int requiresSmallestWidthDp);
+
+ ParsingPackage setResizeable(int resizeable);
+
+ ParsingPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
+
+ ParsingPackage setRestrictedAccountType(String restrictedAccountType);
+
+ ParsingPackage setRoundIconRes(int roundIconRes);
+
+ ParsingPackage setSharedUserLabel(int sharedUserLabel);
+
+ ParsingPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+
+ ParsingPackage setSplitClassLoaderName(int splitIndex, String classLoaderName);
+
+ ParsingPackage setStaticSharedLibVersion(long staticSharedLibVersion);
+
+ ParsingPackage setSupportsLargeScreens(int supportsLargeScreens);
+
+ ParsingPackage setSupportsNormalScreens(int supportsNormalScreens);
+
+ ParsingPackage setSupportsSmallScreens(int supportsSmallScreens);
+
+ ParsingPackage setSupportsXLargeScreens(int supportsXLargeScreens);
+
+ ParsingPackage setTargetSandboxVersion(int targetSandboxVersion);
+
+ ParsingPackage setTheme(int theme);
+
+ ParsingPackage setUpgradeKeySets(ArraySet<String> upgradeKeySets);
+
+ ParsingPackage setUse32BitAbi(boolean use32BitAbi);
+
+ ParsingPackage setVolumeUuid(String volumeUuid);
+
+ ParsingPackage setZygotePreloadName(String zygotePreloadName);
+
+ ParsingPackage sortActivities();
+
+ ParsingPackage sortReceivers();
+
+ ParsingPackage sortServices();
+
+ ParsedPackage hideAsParsed();
+
+ ParsingPackage setBaseRevisionCode(int baseRevisionCode);
+
+ ParsingPackage setPreferredOrder(int preferredOrder);
+
+ ParsingPackage setVersionName(String versionName);
+
+ ParsingPackage setCompileSdkVersion(int compileSdkVersion);
+
+ ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename);
+
+ boolean usesCompatibilityMode();
+}
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
index d0657e5eb8ec..81b4bc574197 100644
--- a/core/java/android/content/pm/AndroidHidlUpdater.java
+++ b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm;
+package android.content.pm.parsing.library;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
-import android.content.pm.PackageParser.Package;
+import android.content.pm.parsing.ParsedPackage;
import android.os.Build;
import com.android.internal.annotations.VisibleForTesting;
@@ -33,20 +33,18 @@ import com.android.internal.annotations.VisibleForTesting;
public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
@Override
- public void updatePackage(Package pkg) {
- ApplicationInfo info = pkg.applicationInfo;
-
+ public void updatePackage(ParsedPackage parsedPackage) {
// This was the default <= P and is maintained for backwards compatibility.
- boolean isLegacy = info.targetSdkVersion <= Build.VERSION_CODES.P;
+ boolean isLegacy = parsedPackage.getTargetSdkVersion() <= Build.VERSION_CODES.P;
// Only system apps use these libraries
- boolean isSystem = info.isSystemApp() || info.isUpdatedSystemApp();
+ boolean isSystem = parsedPackage.isSystemApp() || parsedPackage.isUpdatedSystemApp();
if (isLegacy && isSystem) {
- prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
- prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
+ prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_BASE);
+ prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_MANAGER);
} else {
- removeLibrary(pkg, ANDROID_HIDL_BASE);
- removeLibrary(pkg, ANDROID_HIDL_MANAGER);
+ removeLibrary(parsedPackage, ANDROID_HIDL_BASE);
+ removeLibrary(parsedPackage, ANDROID_HIDL_MANAGER);
}
}
}
diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
index 18d3ba33552e..5fbe5b9c7250 100644
--- a/core/java/android/content/pm/AndroidTestBaseUpdater.java
+++ b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm;
+package android.content.pm.parsing.library;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.Context;
-import android.content.pm.PackageParser.Package;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -54,25 +55,25 @@ public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater {
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
private static final long REMOVE_ANDROID_TEST_BASE = 133396946L;
- private static boolean isChangeEnabled(Package pkg) {
+ private static boolean isChangeEnabled(AndroidPackage pkg) {
// Do not ask platform compat for system apps to prevent a boot time regression in tests.
// b/142558883.
- if (!pkg.applicationInfo.isSystemApp()) {
+ if (!pkg.isSystem()) {
IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
try {
return platformCompat.isChangeEnabled(REMOVE_ANDROID_TEST_BASE,
- pkg.applicationInfo);
+ pkg.toAppInfoWithoutState());
} catch (RemoteException | NullPointerException e) {
Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
}
}
// Fall back to previous behaviour.
- return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q;
+ return pkg.getTargetSdkVersion() > Build.VERSION_CODES.Q;
}
@Override
- public void updatePackage(Package pkg) {
+ public void updatePackage(ParsedPackage pkg) {
// Packages targeted at <= Q expect the classes in the android.test.base library
// to be accessible so this maintains backward compatibility by adding the
// android.test.base library to those packages.
diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
index 707443b19679..613a06b636e9 100644
--- a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
+++ b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm;
+package android.content.pm.parsing.library;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-import android.content.pm.PackageParser.Package;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
import android.os.Build;
import com.android.internal.annotations.VisibleForTesting;
@@ -31,18 +32,17 @@ import com.android.internal.annotations.VisibleForTesting;
@VisibleForTesting
public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater {
- private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) {
- int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
- return targetSdkVersion < Build.VERSION_CODES.P;
+ private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(AndroidPackage pkg) {
+ return pkg.getTargetSdkVersion() < Build.VERSION_CODES.P;
}
@Override
- public void updatePackage(Package pkg) {
+ public void updatePackage(ParsedPackage parsedPackage) {
// Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
// to be accessible so this maintains backward compatibility by adding the
// org.apache.http.legacy library to those packages.
- if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) {
- prefixRequiredLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
+ if (apkTargetsApiLevelLessThanOrEqualToOMR1(parsedPackage)) {
+ prefixRequiredLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
}
}
}
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
index 4331bd4ac4d4..1220fc497b04 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.content.pm;
+package android.content.pm.parsing.library;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-import android.content.pm.PackageParser.Package;
+import android.content.pm.parsing.ParsedPackage;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -31,7 +31,7 @@ import java.util.List;
import java.util.function.Supplier;
/**
- * Modifies {@link Package} in order to maintain backwards compatibility.
+ * Modifies {@link ParsedPackage} in order to maintain backwards compatibility.
*
* @hide
*/
@@ -60,7 +60,7 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
// will remove any references to org.apache.http.library from the package so that it does
// not try and load the library when it is on the bootclasspath.
boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters,
- "android.content.pm.AndroidTestBaseUpdater",
+ "android.content.pm.parsing.library.AndroidTestBaseUpdater",
RemoveUnnecessaryAndroidTestBaseLibrary::new);
PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
@@ -123,20 +123,20 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
}
/**
- * Modify the shared libraries in the supplied {@link Package} to maintain backwards
+ * Modify the shared libraries in the supplied {@link ParsedPackage} to maintain backwards
* compatibility.
*
- * @param pkg the {@link Package} to modify.
+ * @param parsedPackage the {@link ParsedPackage} to modify.
*/
@VisibleForTesting
- public static void modifySharedLibraries(Package pkg) {
- INSTANCE.updatePackage(pkg);
+ public static void modifySharedLibraries(ParsedPackage parsedPackage) {
+ INSTANCE.updatePackage(parsedPackage);
}
@Override
- public void updatePackage(Package pkg) {
+ public void updatePackage(ParsedPackage parsedPackage) {
for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
- packageUpdater.updatePackage(pkg);
+ packageUpdater.updatePackage(parsedPackage);
}
}
@@ -161,10 +161,10 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater {
@Override
- public void updatePackage(Package pkg) {
+ public void updatePackage(ParsedPackage parsedPackage) {
// android.test.runner has a dependency on android.test.mock so if android.test.runner
// is present but android.test.mock is not then add android.test.mock.
- prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
+ prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
}
}
@@ -177,8 +177,8 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
extends PackageSharedLibraryUpdater {
@Override
- public void updatePackage(Package pkg) {
- removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
+ public void updatePackage(ParsedPackage parsedPackage) {
+ removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
}
}
@@ -192,8 +192,8 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
extends PackageSharedLibraryUpdater {
@Override
- public void updatePackage(Package pkg) {
- removeLibrary(pkg, ANDROID_TEST_BASE);
+ public void updatePackage(ParsedPackage parsedPackage) {
+ removeLibrary(parsedPackage, ANDROID_TEST_BASE);
}
}
}
diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
index 1565d9ce77d4..8b27d140a8f4 100644
--- a/core/java/android/content/pm/PackageSharedLibraryUpdater.java
+++ b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,18 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm;
+package android.content.pm.parsing.library;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.parsing.ParsedPackage;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
+import java.util.List;
/**
- * Base for classes that update a {@link PackageParser.Package}'s shared libraries.
+ * Base for classes that update a {@link ParsedPackage}'s shared libraries.
*
* @hide
*/
@@ -34,14 +36,13 @@ public abstract class PackageSharedLibraryUpdater {
/**
* Update the package's shared libraries.
*
- * @param pkg the package to update.
+ * @param parsedPackage the package to update.
*/
- public abstract void updatePackage(PackageParser.Package pkg);
+ public abstract void updatePackage(ParsedPackage parsedPackage);
- static void removeLibrary(PackageParser.Package pkg, String libraryName) {
- pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, libraryName);
- pkg.usesOptionalLibraries =
- ArrayUtils.remove(pkg.usesOptionalLibraries, libraryName);
+ static void removeLibrary(ParsedPackage parsedPackage, String libraryName) {
+ parsedPackage.removeUsesLibrary(libraryName)
+ .removeUsesOptionalLibrary(libraryName);
}
static @NonNull
@@ -53,8 +54,8 @@ public abstract class PackageSharedLibraryUpdater {
return cur;
}
- private static boolean isLibraryPresent(ArrayList<String> usesLibraries,
- ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) {
+ private static boolean isLibraryPresent(List<String> usesLibraries,
+ List<String> usesOptionalLibraries, String apacheHttpLegacy) {
return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
|| ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
}
@@ -65,37 +66,32 @@ public abstract class PackageSharedLibraryUpdater {
* <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with
* the {@code implicitDependency} if it is not already in the list of libraries.
*
- * @param pkg the {@link PackageParser.Package} to update.
+ * @param parsedPackage the {@link ParsedPackage} to update.
* @param existingLibrary the existing library.
* @param implicitDependency the implicit dependency to add
*/
- void prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary,
+ void prefixImplicitDependency(ParsedPackage parsedPackage, String existingLibrary,
String implicitDependency) {
- ArrayList<String> usesLibraries = pkg.usesLibraries;
- ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
+ List<String> usesLibraries = parsedPackage.getUsesLibraries();
+ List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries();
if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) {
if (ArrayUtils.contains(usesLibraries, existingLibrary)) {
- prefix(usesLibraries, implicitDependency);
+ parsedPackage.addUsesLibrary(0, implicitDependency);
} else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) {
- prefix(usesOptionalLibraries, implicitDependency);
+ parsedPackage.addUsesOptionalLibrary(0, implicitDependency);
}
-
- pkg.usesLibraries = usesLibraries;
- pkg.usesOptionalLibraries = usesOptionalLibraries;
}
}
- void prefixRequiredLibrary(PackageParser.Package pkg, String libraryName) {
- ArrayList<String> usesLibraries = pkg.usesLibraries;
- ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
+ void prefixRequiredLibrary(ParsedPackage parsedPackage, String libraryName) {
+ List<String> usesLibraries = parsedPackage.getUsesLibraries();
+ List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries();
boolean alreadyPresent = isLibraryPresent(
usesLibraries, usesOptionalLibraries, libraryName);
if (!alreadyPresent) {
- usesLibraries = prefix(usesLibraries, libraryName);
-
- pkg.usesLibraries = usesLibraries;
+ parsedPackage.addUsesLibrary(0, libraryName);
}
}
}
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java
index a607a9ff682b..7b691c06718e 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm;
+package android.content.pm.parsing.library;
/**
* A set of shared library names
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 090629fe77cb..fa5ad39789dd 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -452,6 +452,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if ((diff & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
list.add("CONFIG_SMALLEST_SCREEN_SIZE");
}
+ if ((diff & ActivityInfo.CONFIG_DENSITY) != 0) {
+ list.add("CONFIG_DENSITY");
+ }
if ((diff & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
list.add("CONFIG_LAYOUT_DIRECTION");
}
@@ -461,6 +464,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if ((diff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
list.add("CONFIG_ASSETS_PATHS");
}
+ if ((diff & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) {
+ list.add("CONFIG_WINDOW_CONFIGURATION");
+ }
StringBuilder builder = new StringBuilder("{");
for (int i = 0, n = list.size(); i < n; i++) {
builder.append(list.get(i));
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 2698c2de4c61..c698267b956b 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1859,6 +1859,7 @@ public class Resources {
mResId = other.mResId == null ? null : other.mResId.clone();
mForce = other.mForce == null ? null : other.mForce.clone();
mCount = other.mCount;
+ mHashCode = other.mHashCode;
}
@Override
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 84489cfb768c..e4a4a1a771b2 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -344,7 +344,7 @@ public class ResourcesImpl {
try {
return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
} catch (Exception e) {
- throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
+ throw new NotFoundException("File " + tempValue.string.toString() + " from "
+ "resource ID #0x" + Integer.toHexString(id), e);
}
}
@@ -359,7 +359,7 @@ public class ResourcesImpl {
// Note: value.string might be null
NotFoundException rnf = new NotFoundException("File "
+ (value.string == null ? "(null)" : value.string.toString())
- + " from drawable resource ID #0x" + Integer.toHexString(id));
+ + " from resource ID #0x" + Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
}
diff --git a/core/java/android/ddm/DdmHandleAppName.java b/core/java/android/ddm/DdmHandleAppName.java
index 956078772ca8..de7acbaf6e55 100644
--- a/core/java/android/ddm/DdmHandleAppName.java
+++ b/core/java/android/ddm/DdmHandleAppName.java
@@ -17,10 +17,12 @@
package android.ddm;
import android.annotation.UnsupportedAppUsage;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
+
import java.nio.ByteBuffer;
@@ -31,7 +33,7 @@ public class DdmHandleAppName extends ChunkHandler {
public static final int CHUNK_APNM = type("APNM");
- private volatile static String mAppName = "";
+ private static volatile Names sNames = new Names("", "");
private static DdmHandleAppName mInstance = new DdmHandleAppName();
@@ -66,45 +68,81 @@ public class DdmHandleAppName extends ChunkHandler {
/**
+ * Sets all names to the same name.
+ */
+ @UnsupportedAppUsage
+ public static void setAppName(String name, int userId) {
+ setAppName(name, name, userId);
+ }
+
+ /**
* Set the application name. Called when we get named, which may be
* before or after DDMS connects. For the latter we need to send up
* an APNM message.
*/
@UnsupportedAppUsage
- public static void setAppName(String name, int userId) {
- if (name == null || name.length() == 0)
- return;
+ public static void setAppName(String appName, String pkgName, int userId) {
+ if (appName == null || appName.isEmpty() || pkgName == null || pkgName.isEmpty()) return;
- mAppName = name;
+ sNames = new Names(appName, pkgName);
// if DDMS is already connected, send the app name up
- sendAPNM(name, userId);
+ sendAPNM(appName, pkgName, userId);
}
@UnsupportedAppUsage
- public static String getAppName() {
- return mAppName;
+ public static Names getNames() {
+ return sNames;
}
- /*
+ /**
* Send an APNM (APplication NaMe) chunk.
*/
- private static void sendAPNM(String appName, int userId) {
+ private static void sendAPNM(String appName, String pkgName, int userId) {
if (false)
Log.v("ddm", "Sending app name");
ByteBuffer out = ByteBuffer.allocate(
4 /* appName's length */
- + appName.length()*2 /* appName */
- + 4 /* userId */);
+ + appName.length() * 2 /* appName */
+ + 4 /* userId */
+ + 4 /* pkgName's length */
+ + pkgName.length() * 2 /* pkgName */);
out.order(ChunkHandler.CHUNK_ORDER);
out.putInt(appName.length());
putString(out, appName);
out.putInt(userId);
+ out.putInt(pkgName.length());
+ putString(out, pkgName);
Chunk chunk = new Chunk(CHUNK_APNM, out);
DdmServer.sendChunk(chunk);
}
+ /**
+ * A class that encapsulates the app and package names into a single
+ * instance, effectively synchronizing the two names.
+ */
+ static final class Names {
+
+ private final String mAppName;
+
+ private final String mPkgName;
+
+ private Names(String appName, String pkgName) {
+ mAppName = appName;
+ mPkgName = pkgName;
+ }
+
+ public String getAppName() {
+ return mAppName;
+ }
+
+ public String getPkgName() {
+ return mPkgName;
+ }
+
+ }
+
}
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 87568e857d6d..60dfc8d7ee7b 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -126,10 +126,9 @@ public class DdmHandleHello extends ChunkHandler {
String vmVersion = System.getProperty("java.vm.version", "?");
String vmIdent = vmName + " v" + vmVersion;
- //String appName = android.app.ActivityThread.currentPackageName();
- //if (appName == null)
- // appName = "unknown";
- String appName = DdmHandleAppName.getAppName();
+ DdmHandleAppName.Names names = DdmHandleAppName.getNames();
+ String appName = names.getAppName();
+ String pkgName = names.getPkgName();
VMRuntime vmRuntime = VMRuntime.getRuntime();
String instructionSetDescription =
@@ -142,12 +141,13 @@ public class DdmHandleHello extends ChunkHandler {
+ (vmRuntime.isCheckJniEnabled() ? "true" : "false");
boolean isNativeDebuggable = vmRuntime.isNativeDebuggable();
- ByteBuffer out = ByteBuffer.allocate(28
+ ByteBuffer out = ByteBuffer.allocate(32
+ vmIdent.length() * 2
+ appName.length() * 2
+ instructionSetDescription.length() * 2
+ vmFlags.length() * 2
- + 1);
+ + 1
+ + pkgName.length() * 2);
out.order(ChunkHandler.CHUNK_ORDER);
out.putInt(CLIENT_PROTOCOL_VERSION);
out.putInt(android.os.Process.myPid());
@@ -161,6 +161,8 @@ public class DdmHandleHello extends ChunkHandler {
out.putInt(vmFlags.length());
putString(out, vmFlags);
out.put((byte)(isNativeDebuggable ? 1 : 0));
+ out.putInt(pkgName.length());
+ putString(out, pkgName);
Chunk reply = new Chunk(CHUNK_HELO, out);
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index c9a999cfdf17..1ae44e169851 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -20,8 +20,6 @@ import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import com.google.android.collect.Sets;
-
import java.util.HashSet;
/**
@@ -32,7 +30,7 @@ import java.util.HashSet;
public class InterfaceConfiguration implements Parcelable {
private String mHwAddr;
private LinkAddress mAddr;
- private HashSet<String> mFlags = Sets.newHashSet();
+ private HashSet<String> mFlags = new HashSet<>();
// Must be kept in sync with constant in INetd.aidl
private static final String FLAG_UP = "up";
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index adc497a6d67d..299212735410 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
@@ -461,6 +462,14 @@ public class NetworkRequest implements Parcelable {
return networkCapabilities.hasTransport(transportType);
}
+ /**
+ * @see Builder#setNetworkSpecifier(NetworkSpecifier)
+ */
+ @Nullable
+ public NetworkSpecifier getNetworkSpecifier() {
+ return networkCapabilities.getNetworkSpecifier();
+ }
+
public String toString() {
return "NetworkRequest [ " + type + " id=" + requestId +
(legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 6408f6170fce..ebb2071ead7e 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -519,11 +519,12 @@ public class Process {
* @param invokeWith null-ok the command to invoke with.
* @param packageName null-ok the name of the package this process belongs to.
* @param isTopApp whether the process starts for high priority application.
- *
+ * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
+ * started.
* @param zygoteArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
- *
+ *
* {@hide}
*/
public static ProcessStartResult start(@NonNull final String processClass,
@@ -539,11 +540,12 @@ public class Process {
@Nullable String invokeWith,
@Nullable String packageName,
boolean isTopApp,
+ @Nullable long[] disabledCompatChanges,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
- /*useUsapPool=*/ true, isTopApp, zygoteArgs);
+ /*useUsapPool=*/ true, isTopApp, disabledCompatChanges, zygoteArgs);
}
/** @hide */
@@ -559,11 +561,12 @@ public class Process {
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
+ @Nullable long[] disabledCompatChanges,
@Nullable String[] zygoteArgs) {
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
- /*useUsapPool=*/ false, /*isTopApp=*/ false, zygoteArgs);
+ /*useUsapPool=*/ false, /*isTopApp=*/ false, disabledCompatChanges, zygoteArgs);
}
/**
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 1456a734394d..e132c11d6c8e 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -21,6 +21,7 @@ import android.annotation.UnsupportedAppUsage;
import com.android.internal.os.Zygote;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
/**
@@ -107,12 +108,15 @@ public final class Trace {
private static final int MAX_SECTION_NAME_LEN = 127;
// Must be volatile to avoid word tearing.
+ // This is only kept in case any apps get this by reflection but do not
+ // check the return value for null.
@UnsupportedAppUsage
private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
private static int sZygoteDebugFlags = 0;
@UnsupportedAppUsage
+ @CriticalNative
private static native long nativeGetEnabledTags();
private static native void nativeSetAppTracingAllowed(boolean allowed);
private static native void nativeSetTracingEnabled(boolean allowed);
@@ -128,47 +132,10 @@ public final class Trace {
@FastNative
private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
- static {
- // We configure two separate change callbacks, one in Trace.cpp and one here. The
- // native callback reads the tags from the system property, and this callback
- // reads the value that the native code retrieved. It's essential that the native
- // callback executes first.
- //
- // The system provides ordering through a priority level. Callbacks made through
- // SystemProperties.addChangeCallback currently have a negative priority, while
- // our native code is using a priority of zero.
- SystemProperties.addChangeCallback(() -> {
- cacheEnabledTags();
- if ((sZygoteDebugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
- traceCounter(TRACE_TAG_ALWAYS, "java_debuggable", 1);
- }
- });
- }
-
private Trace() {
}
/**
- * Caches a copy of the enabled-tag bits. The "master" copy is held by the native code,
- * and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property.
- * <p>
- * If the native code hasn't yet read the property, we will cause it to do one-time
- * initialization. We don't want to do this during class init, because this class is
- * preloaded, so all apps would be stuck with whatever the zygote saw. (The zygote
- * doesn't see the system-property update broadcasts.)
- * <p>
- * We want to defer initialization until the first use by an app, post-zygote.
- * <p>
- * We're okay if multiple threads call here simultaneously -- the native state is
- * synchronized, and sEnabledTags is volatile (prevents word tearing).
- */
- private static long cacheEnabledTags() {
- long tags = nativeGetEnabledTags();
- sEnabledTags = tags;
- return tags;
- }
-
- /**
* Returns true if a trace tag is enabled.
*
* @param traceTag The trace tag to check.
@@ -178,10 +145,7 @@ public final class Trace {
*/
@UnsupportedAppUsage
public static boolean isTagEnabled(long traceTag) {
- long tags = sEnabledTags;
- if (tags == TRACE_TAG_NOT_READY) {
- tags = cacheEnabledTags();
- }
+ long tags = nativeGetEnabledTags();
return (tags & traceTag) != 0;
}
@@ -210,10 +174,6 @@ public final class Trace {
@UnsupportedAppUsage
public static void setAppTracingAllowed(boolean allowed) {
nativeSetAppTracingAllowed(allowed);
-
- // Setting whether app tracing is allowed may change the tags, so we update the cached
- // tags here.
- cacheEnabledTags();
}
/**
@@ -227,10 +187,6 @@ public final class Trace {
public static void setTracingEnabled(boolean enabled, int debugFlags) {
nativeSetTracingEnabled(enabled);
sZygoteDebugFlags = debugFlags;
-
- // Setting whether tracing is enabled may change the tags, so we update the cached tags
- // here.
- cacheEnabledTags();
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 907eae87bcb2..d17a5e026880 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -306,6 +306,8 @@ public class ZygoteProcess {
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
* @param packageName null-ok the name of the package this process belongs to.
+ * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
+ * started.
* @param zygoteArgs Additional arguments to supply to the zygote process.
* @param isTopApp Whether the process starts for high priority application.
*
@@ -325,6 +327,7 @@ public class ZygoteProcess {
@Nullable String packageName,
boolean useUsapPool,
boolean isTopApp,
+ @Nullable long[] disabledCompatChanges,
@Nullable String[] zygoteArgs) {
// TODO (chriswailes): Is there a better place to check this value?
if (fetchUsapPoolEnabledPropWithMinInterval()) {
@@ -335,7 +338,7 @@ public class ZygoteProcess {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
- packageName, useUsapPool, isTopApp, zygoteArgs);
+ packageName, useUsapPool, isTopApp, disabledCompatChanges, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -535,6 +538,7 @@ public class ZygoteProcess {
* that has its state cloned from this zygote process.
* @param packageName null-ok the name of the package this process belongs to.
* @param isTopApp Whether the process starts for high priority application.
+ * @param disabledCompatChanges a list of disabled compat changes for the process being started.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
@@ -554,6 +558,7 @@ public class ZygoteProcess {
@Nullable String packageName,
boolean useUsapPool,
boolean isTopApp,
+ @Nullable long[] disabledCompatChanges,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
@@ -584,10 +589,10 @@ public class ZygoteProcess {
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
- StringBuilder sb = new StringBuilder();
+ final StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
- int sz = gids.length;
+ final int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
@@ -631,6 +636,21 @@ public class ZygoteProcess {
argsForZygote.add(Zygote.START_AS_TOP_APP_ARG);
}
+ if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("--disabled-compat-changes=");
+
+ int sz = disabledCompatChanges.length;
+ for (int i = 0; i < sz; i++) {
+ if (i != 0) {
+ sb.append(',');
+ }
+ sb.append(disabledCompatChanges[i]);
+ }
+
+ argsForZygote.add(sb.toString());
+ }
+
argsForZygote.add(processClass);
if (extraArgs != null) {
@@ -1166,7 +1186,8 @@ public class ZygoteProcess {
gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
true /* startChildZygote */, null /* packageName */,
- false /* useUsapPool */, false /* isTopApp */, extraArgs);
+ false /* useUsapPool */, false /* isTopApp */,
+ null /* disabledCompatChanges */, extraArgs);
} catch (ZygoteStartFailedEx ex) {
throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
}
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 14c299d11a94..5cac5f580af1 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -109,4 +109,13 @@ public abstract class StorageManagerInternal {
*/
public abstract void onAppOpsChanged(int code, int uid,
@Nullable String packageName, int mode);
+
+ /**
+ * Asks the StorageManager to reset all state for the provided user; this will result
+ * in the unmounting for all volumes of the user, and, if the user is still running, the
+ * volumes will be re-mounted as well.
+ *
+ * @param userId the userId for which to reset storage
+ */
+ public abstract void resetUser(int userId);
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index f10e184ccf5a..8bf723fa54ed 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -17,6 +17,8 @@
package android.provider;
import android.accounts.Account;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -2902,6 +2904,40 @@ public final class ContactsContract {
}
/**
+ * The default value used for {@link #ACCOUNT_NAME} of raw contacts when they are inserted
+ * without a value for this column.
+ *
+ * <p>This account is used to identify contacts that are only stored locally in the
+ * contacts database instead of being associated with an {@link Account} managed by an
+ * installed application.
+ *
+ * <p>When this returns null then {@link #getLocalAccountType} will also return null and
+ * when it is non-null {@link #getLocalAccountType} will also return a non-null value.
+ */
+ @Nullable
+ public static String getLocalAccountName(@NonNull Context context) {
+ return TextUtils.nullIfEmpty(context.getString(
+ com.android.internal.R.string.config_rawContactsLocalAccountName));
+ }
+
+ /**
+ * The default value used for {@link #ACCOUNT_TYPE} of raw contacts when they are inserted
+ * without a value for this column.
+ *
+ * <p>This account is used to identify contacts that are only stored locally in the
+ * contacts database instead of being associated with an {@link Account} managed by an
+ * installed application.
+ *
+ * <p>When this returns null then {@link #getLocalAccountName} will also return null and
+ * when it is non-null {@link #getLocalAccountName} will also return a non-null value.
+ */
+ @Nullable
+ public static String getLocalAccountType(@NonNull Context context) {
+ return TextUtils.nullIfEmpty(context.getString(
+ com.android.internal.R.string.config_rawContactsLocalAccountType));
+ }
+
+ /**
* A sub-directory of a single raw contact that contains all of its
* {@link ContactsContract.Data} rows. To access this directory
* append {@link Data#CONTENT_DIRECTORY} to the raw contact URI.
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index abf34ca2d21a..9dc680629260 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -357,6 +357,13 @@ public final class DeviceConfig {
@TestApi
public static final String NAMESPACE_PERMISSIONS = "permissions";
+ /**
+ * Namespace for all widget related features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_WIDGET = "widget";
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ad8d55313795..165c2843301c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -648,6 +648,22 @@ public final class Settings {
"android.settings.NIGHT_DISPLAY_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of Dark theme.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_DARK_THEME_SETTINGS =
+ "android.settings.DARK_THEME_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of locale.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/service/incremental/IncrementalDataLoaderService.java b/core/java/android/service/incremental/IncrementalDataLoaderService.java
new file mode 100644
index 000000000000..c4a06c8f53db
--- /dev/null
+++ b/core/java/android/service/incremental/IncrementalDataLoaderService.java
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.incremental;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.InstallationFile;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.incremental.IncrementalDataLoaderParams;
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.os.incremental.IncrementalFileSystemControlParcel;
+import android.os.incremental.NamedParcelFileDescriptor;
+import android.util.Slog;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * The base class for implementing data loader service to control data loaders. Expecting
+ * Incremental Service to bind to a children class of this.
+ *
+ * @hide
+ *
+ * Hide for now, should be @SystemApi
+ * TODO(b/136132412): update with latest API design
+ */
+public abstract class IncrementalDataLoaderService extends Service {
+ private static final String TAG = "IncrementalDataLoaderService";
+ private final DataLoaderBinderService mBinder = new DataLoaderBinderService();
+
+ public static final int DATA_LOADER_READY =
+ IDataLoaderStatusListener.DATA_LOADER_READY;
+ public static final int DATA_LOADER_NOT_READY =
+ IDataLoaderStatusListener.DATA_LOADER_NOT_READY;
+ public static final int DATA_LOADER_RUNNING =
+ IDataLoaderStatusListener.DATA_LOADER_RUNNING;
+ public static final int DATA_LOADER_STOPPED =
+ IDataLoaderStatusListener.DATA_LOADER_STOPPED;
+ public static final int DATA_LOADER_SLOW_CONNECTION =
+ IDataLoaderStatusListener.DATA_LOADER_SLOW_CONNECTION;
+ public static final int DATA_LOADER_NO_CONNECTION =
+ IDataLoaderStatusListener.DATA_LOADER_NO_CONNECTION;
+ public static final int DATA_LOADER_CONNECTION_OK =
+ IDataLoaderStatusListener.DATA_LOADER_CONNECTION_OK;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"DATA_LOADER_"}, value = {
+ DATA_LOADER_READY,
+ DATA_LOADER_NOT_READY,
+ DATA_LOADER_RUNNING,
+ DATA_LOADER_STOPPED,
+ DATA_LOADER_SLOW_CONNECTION,
+ DATA_LOADER_NO_CONNECTION,
+ DATA_LOADER_CONNECTION_OK
+ })
+ public @interface DataLoaderStatus {
+ }
+
+ /**
+ * Incremental FileSystem block size.
+ **/
+ public static final int BLOCK_SIZE = 4096;
+
+ /**
+ * Data compression types
+ */
+ public static final int COMPRESSION_NONE = 0;
+ public static final int COMPRESSION_LZ4 = 1;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({COMPRESSION_NONE, COMPRESSION_LZ4})
+ public @interface CompressionType {
+ }
+
+ /**
+ * Managed DataLoader interface. Each instance corresponds to a single Incremental File System
+ * instance.
+ */
+ public abstract static class DataLoader {
+ /**
+ * A virtual constructor used to do simple initialization. Not ready to serve any data yet.
+ * All heavy-lifting has to be done in onStart.
+ *
+ * @param params Data loader configuration parameters.
+ * @param connector IncFS API wrapper.
+ * @param listener Used for reporting internal state to IncrementalService.
+ * @return True if initialization of a Data Loader was successful. False will be reported to
+ * IncrementalService and can cause an unmount of an IFS instance.
+ */
+ public abstract boolean onCreate(@NonNull IncrementalDataLoaderParams params,
+ @NonNull FileSystemConnector connector,
+ @NonNull StatusListener listener);
+
+ /**
+ * Start the data loader. After this method returns data loader is considered to be ready to
+ * receive callbacks from IFS, supply data via connector and send status updates via
+ * callbacks.
+ *
+ * @return True if Data Loader was able to start. False will be reported to
+ * IncrementalService and can cause an unmount of an IFS instance.
+ */
+ public abstract boolean onStart();
+
+ /**
+ * Stop the data loader. Use to stop any additional threads and free up resources. Data
+ * loader is not longer responsible for supplying data. Start/Stop pair can be called
+ * multiple times e.g. if IFS detects corruption and data needs to be re-loaded.
+ */
+ public abstract void onStop();
+
+ /**
+ * Virtual destructor. Use to cleanup all internal state. After this method returns, the
+ * data loader can no longer use connector or callbacks. For any additional operations with
+ * this instance of IFS a new DataLoader will be created using createDataLoader method.
+ */
+ public abstract void onDestroy();
+
+ /**
+ * IFS reports a pending read each time the page needs to be loaded, e.g. missing.
+ *
+ * @param pendingReads array of blocks to load.
+ *
+ * TODO(b/136132412): avoid using collections
+ */
+ public abstract void onPendingReads(
+ @NonNull Collection<FileSystemConnector.PendingReadInfo> pendingReads);
+
+ /**
+ * IFS tracks all reads and reports them using onPageReads.
+ *
+ * @param reads array of blocks.
+ *
+ * TODO(b/136132412): avoid using collections
+ */
+ public abstract void onPageReads(@NonNull Collection<FileSystemConnector.ReadInfo> reads);
+
+ /**
+ * IFS informs data loader that a new file has been created.
+ * <p>
+ * This can be used to prepare the data loader before it starts loading data. For example,
+ * the data loader can keep a list of newly created files, so that it knows what files to
+ * download from the server.
+ *
+ * @param inode The inode value of the new file.
+ * @param metadata The metadata of the new file.
+ */
+ public abstract void onFileCreated(long inode, byte[] metadata);
+ }
+
+ /**
+ * DataLoader factory method.
+ *
+ * @return An instance of a DataLoader.
+ */
+ public abstract @Nullable DataLoader onCreateDataLoader();
+
+ /**
+ * @hide
+ */
+ public final @NonNull IBinder onBind(@NonNull Intent intent) {
+ return (IBinder) mBinder;
+ }
+
+ private class DataLoaderBinderService extends IDataLoader.Stub {
+ private int mId;
+
+ @Override
+ public void create(int id, @NonNull Bundle options,
+ @NonNull IDataLoaderStatusListener listener)
+ throws IllegalArgumentException, RuntimeException {
+ mId = id;
+ final IncrementalDataLoaderParamsParcel params = options.getParcelable("params");
+ if (params == null) {
+ throw new IllegalArgumentException("Must specify Incremental data loader params");
+ }
+ final IncrementalFileSystemControlParcel control =
+ options.getParcelable("control");
+ if (control == null) {
+ throw new IllegalArgumentException("Must specify Incremental control parcel");
+ }
+ mStatusListener = listener;
+ try {
+ if (!nativeCreateDataLoader(id, control, params, listener)) {
+ Slog.e(TAG, "Failed to create native loader for " + mId);
+ }
+ } catch (Exception ex) {
+ destroy();
+ throw new RuntimeException(ex);
+ } finally {
+ // Closing FDs.
+ if (control.cmd != null) {
+ try {
+ control.cmd.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e);
+ }
+ }
+ if (control.log != null) {
+ try {
+ control.log.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e);
+ }
+ }
+ NamedParcelFileDescriptor[] fds = params.dynamicArgs;
+ for (NamedParcelFileDescriptor nfd : fds) {
+ try {
+ nfd.fd.close();
+ } catch (IOException e) {
+ Slog.e(TAG,
+ "Failed to close DynamicArgs parcel file descriptor " + e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void start(List<InstallationFile> fileInfos) {
+ if (!nativeStartDataLoader(mId)) {
+ Slog.e(TAG, "Failed to start loader: loader not found for " + mId);
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (!nativeStopDataLoader(mId)) {
+ Slog.w(TAG, "Failed to stop loader: loader not found for " + mId);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ if (!nativeDestroyDataLoader(mId)) {
+ Slog.w(TAG, "Failed to destroy loader: loader not found for " + mId);
+ }
+ }
+
+ @Override
+ // TODO(b/136132412): remove this
+ public void onFileCreated(long inode, byte[] metadata) {
+ if (!nativeOnFileCreated(mId, inode, metadata)) {
+ Slog.w(TAG, "Failed to handle onFileCreated for storage:" + mId
+ + " inode:" + inode);
+ }
+ }
+ }
+
+ /**
+ * IncFs API wrapper for writing pages and getting page missing info. Non-hidden methods are
+ * expected to be called by the IncrementalDataLoaderService implemented by developers.
+ *
+ * @hide
+ *
+ * TODO(b/136132412) Should be @SystemApi
+ */
+ public static final class FileSystemConnector {
+ /**
+ * Defines a block address. A block is the unit of data chunk that IncFs operates with.
+ *
+ * @hide
+ */
+ public static class BlockAddress {
+ /**
+ * Linux inode uniquely identifies file within a single IFS instance.
+ */
+ private final long mFileIno;
+ /**
+ * Index of a 4K block within a file.
+ */
+ private final int mBlockIndex;
+
+ public BlockAddress(long fileIno, int blockIndex) {
+ this.mFileIno = fileIno;
+ this.mBlockIndex = blockIndex;
+ }
+
+ public long getFileIno() {
+ return mFileIno;
+ }
+
+ public int getBlockIndex() {
+ return mBlockIndex;
+ }
+ }
+
+ /**
+ * A block is the unit of data chunk that IncFs operates with.
+ *
+ * @hide
+ */
+ public static class Block extends BlockAddress {
+ /**
+ * Data content of the block.
+ */
+ private final @NonNull byte[] mDataBytes;
+
+ public Block(long fileIno, int blockIndex, @NonNull byte[] dataBytes) {
+ super(fileIno, blockIndex);
+ this.mDataBytes = dataBytes;
+ }
+ }
+
+ /**
+ * Defines a page/block inside a file.
+ */
+ public static class DataBlock extends Block {
+ /**
+ * Compression type of the data block.
+ */
+ private final @CompressionType int mCompressionType;
+
+ public DataBlock(long fileIno, int blockIndex, @NonNull byte[] dataBytes,
+ @CompressionType int compressionType) {
+ super(fileIno, blockIndex, dataBytes);
+ this.mCompressionType = compressionType;
+ }
+ }
+
+ /**
+ * Defines a hash block for a certain file. A hash block index is the index in an array of
+ * hashes which is the 1-d representation of the hash tree. One DataBlock might be
+ * associated with multiple HashBlocks.
+ */
+ public static class HashBlock extends Block {
+ public HashBlock(long fileIno, int blockIndex, @NonNull byte[] dataBytes) {
+ super(fileIno, blockIndex, dataBytes);
+ }
+ }
+
+ /**
+ * Information about a page that is pending to be read.
+ */
+ public static class PendingReadInfo extends BlockAddress {
+ PendingReadInfo(long fileIno, int blockIndex) {
+ super(fileIno, blockIndex);
+ }
+ }
+
+ /**
+ * Information about a page that is read.
+ */
+ public static class ReadInfo extends BlockAddress {
+ /**
+ * A monotonically increasing read timestamp.
+ */
+ private final long mTimePoint;
+ /**
+ * Number of blocks read starting from blockIndex.
+ */
+ private final int mBlockCount;
+
+ ReadInfo(long timePoint, long fileIno, int firstBlockIndex, int blockCount) {
+ super(fileIno, firstBlockIndex);
+ this.mTimePoint = timePoint;
+ this.mBlockCount = blockCount;
+ }
+
+ public long getTimePoint() {
+ return mTimePoint;
+ }
+
+ public int getBlockCount() {
+ return mBlockCount;
+ }
+ }
+
+ /**
+ * Defines the dynamic information about an IncFs file.
+ */
+ public static class FileInfo {
+ /**
+ * BitSet to show if any block is available at each block index.
+ */
+ private final @NonNull
+ byte[] mBlockBitmap;
+
+ /**
+ * @hide
+ */
+ public FileInfo(@NonNull byte[] blockBitmap) {
+ this.mBlockBitmap = blockBitmap;
+ }
+ }
+
+ /**
+ * Creates a wrapper for a native instance.
+ */
+ FileSystemConnector(long nativeInstance) {
+ mNativeInstance = nativeInstance;
+ }
+
+ /**
+ * Checks whether a range in a file if loaded.
+ *
+ * @param node inode of the file.
+ * @param start The starting offset of the range.
+ * @param end The ending offset of the range.
+ * @return True if the file is fully loaded.
+ */
+ public boolean isFileRangeLoaded(long node, long start, long end) {
+ return nativeIsFileRangeLoadedNode(mNativeInstance, node, start, end);
+ }
+
+ /**
+ * Gets the metadata of a file.
+ *
+ * @param node inode of the file.
+ * @return The metadata object.
+ */
+ @NonNull
+ public byte[] getFileMetadata(long node) throws IOException {
+ final byte[] metadata = nativeGetFileMetadataNode(mNativeInstance, node);
+ if (metadata == null || metadata.length == 0) {
+ throw new IOException(
+ "IncrementalFileSystem failed to obtain metadata for node: " + node);
+ }
+ return metadata;
+ }
+
+ /**
+ * Gets the dynamic information of a file, such as page bitmaps. Can be used to get missing
+ * page indices by the FileSystemConnector.
+ *
+ * @param node inode of the file.
+ * @return Dynamic file info.
+ */
+ @NonNull
+ public FileInfo getDynamicFileInfo(long node) throws IOException {
+ final byte[] blockBitmap = nativeGetFileInfoNode(mNativeInstance, node);
+ if (blockBitmap == null || blockBitmap.length == 0) {
+ throw new IOException(
+ "IncrementalFileSystem failed to obtain dynamic file info for node: "
+ + node);
+ }
+ return new FileInfo(blockBitmap);
+ }
+
+ /**
+ * Writes a page's data and/or hashes.
+ *
+ * @param dataBlocks the DataBlock objects that contain data block index and data bytes.
+ * @param hashBlocks the HashBlock objects that contain hash indices and hash bytes.
+ *
+ * TODO(b/136132412): change API to avoid dynamic allocation of data block objects
+ */
+ public void writeMissingData(@NonNull DataBlock[] dataBlocks,
+ @Nullable HashBlock[] hashBlocks) throws IOException {
+ if (!nativeWriteMissingData(mNativeInstance, dataBlocks, hashBlocks)) {
+ throw new IOException("IncrementalFileSystem failed to write missing data.");
+ }
+ }
+
+ /**
+ * Writes the signer block of a file. Expecting the connector to call this when it got
+ * signing data from data loader.
+ *
+ * @param node the file to be written to.
+ * @param signerData the raw signer data byte array.
+ */
+ public void writeSignerData(long node, @NonNull byte[] signerData)
+ throws IOException {
+ if (!nativeWriteSignerDataNode(mNativeInstance, node, signerData)) {
+ throw new IOException(
+ "IncrementalFileSystem failed to write signer data of node " + node);
+ }
+ }
+
+ private final long mNativeInstance;
+ }
+
+ /**
+ * Wrapper for native reporting DataLoader statuses.
+ *
+ * @hide
+ *
+ * TODO(b/136132412) Should be @SystemApi
+ */
+ public static final class StatusListener {
+ /**
+ * Creates a wrapper for a native instance.
+ *
+ * @hide
+ */
+ StatusListener(long nativeInstance) {
+ mNativeInstance = nativeInstance;
+ }
+
+ /**
+ * Report the status of DataLoader. Used for system-wide notifications e.g., disabling
+ * applications which rely on this data loader to function properly.
+ *
+ * @param status status to report.
+ * @return True if status was reported successfully.
+ */
+ public boolean onStatusChanged(@DataLoaderStatus int status) {
+ return nativeReportStatus(mNativeInstance, status);
+ }
+
+ private final long mNativeInstance;
+ }
+
+ private IDataLoaderStatusListener mStatusListener = null;
+
+ /* Native methods */
+ private native boolean nativeCreateDataLoader(int storageId,
+ @NonNull IncrementalFileSystemControlParcel control,
+ @NonNull IncrementalDataLoaderParamsParcel params,
+ IDataLoaderStatusListener listener);
+
+ private native boolean nativeStartDataLoader(int storageId);
+
+ private native boolean nativeStopDataLoader(int storageId);
+
+ private native boolean nativeDestroyDataLoader(int storageId);
+
+ private static native boolean nativeOnFileCreated(int storageId,
+ long inode, byte[] metadata);
+
+ private static native boolean nativeIsFileRangeLoadedNode(
+ long nativeInstance, long node, long start, long end);
+
+ private static native boolean nativeWriteMissingData(
+ long nativeInstance, FileSystemConnector.DataBlock[] dataBlocks,
+ FileSystemConnector.HashBlock[] hashBlocks);
+
+ private static native boolean nativeWriteSignerDataNode(
+ long nativeInstance, long node, byte[] signerData);
+
+ private static native byte[] nativeGetFileMetadataNode(
+ long nativeInstance, long node);
+
+ private static native byte[] nativeGetFileInfoNode(
+ long nativeInstance, long node);
+
+ private static native boolean nativeReportStatus(long nativeInstance, int status);
+}
diff --git a/core/java/android/service/sms/FinancialSmsService.java b/core/java/android/service/sms/FinancialSmsService.java
deleted file mode 100644
index 5fb7249b6ecb..000000000000
--- a/core/java/android/service/sms/FinancialSmsService.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.service.sms;
-
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.Service;
-import android.content.Intent;
-import android.database.CursorWindow;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteCallback;
-import android.os.RemoteException;
-
-/**
- * A service to support sms messages read for financial apps.
- *
- * {@hide}
- */
-@SystemApi
-public abstract class FinancialSmsService extends Service {
-
- private static final String TAG = "FinancialSmsService";
-
- /**
- * The {@link Intent} action that must be declared as handled by a service
- * in its manifest for the system to recognize it as a quota providing
- * service.
- */
- public static final String ACTION_FINANCIAL_SERVICE_INTENT =
- "android.service.sms.action.FINANCIAL_SERVICE_INTENT";
-
- /** {@hide} **/
- public static final String EXTRA_SMS_MSGS = "sms_messages";
-
- private FinancialSmsServiceWrapper mWrapper;
-
- private void getSmsMessages(RemoteCallback callback, Bundle params) {
- final Bundle data = new Bundle();
- CursorWindow smsMessages = onGetSmsMessages(params);
- if (smsMessages != null) {
- data.putParcelable(EXTRA_SMS_MSGS, smsMessages);
- }
- callback.sendResult(data);
- }
-
- private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
-
- /** @hide */
- public FinancialSmsService() {
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- mWrapper = new FinancialSmsServiceWrapper();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mWrapper;
- }
-
- /**
- * Get sms messages for financial apps.
- *
- * @param params parameters passed in by the calling app.
- * @return the {@code CursorWindow} with all sms messages for the app to read.
- *
- * {@hide}
- */
- @Nullable
- @SystemApi
- public abstract CursorWindow onGetSmsMessages(@NonNull Bundle params);
-
- private final class FinancialSmsServiceWrapper extends IFinancialSmsService.Stub {
- @Override
- public void getSmsMessages(RemoteCallback callback, Bundle params) throws RemoteException {
- mHandler.sendMessage(obtainMessage(
- FinancialSmsService::getSmsMessages,
- FinancialSmsService.this,
- callback, params));
- }
- }
-
-}
diff --git a/core/java/android/service/sms/IFinancialSmsService.aidl b/core/java/android/service/sms/IFinancialSmsService.aidl
deleted file mode 100644
index caabe5851948..000000000000
--- a/core/java/android/service/sms/IFinancialSmsService.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.sms;
-
-import android.os.Bundle;
-import android.os.RemoteCallback;
-
-/**
- * Service used by financial apps to read sms messages.
- *
- * @hide
- */
-oneway interface IFinancialSmsService
-{
- void getSmsMessages(in RemoteCallback callback, in Bundle params);
-} \ No newline at end of file
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 20dc2beeaa48..8dca69f856e5 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -37,7 +37,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
import android.view.textclassifier.ConversationActions;
@@ -437,28 +436,16 @@ public abstract class TextClassifierService extends Service {
/**
* Returns the component name of the system default textclassifier service if it can be found
* on the system. Otherwise, returns null.
- * @hide
- */
- public static ComponentName getServiceComponentName(@NonNull Context context) {
- return getServiceComponentName(context, new TextClassificationConstants(
- () -> Settings.Global.getString(
- context.getContentResolver(),
- Settings.Global.TEXT_CLASSIFIER_CONSTANTS)));
- }
-
- /**
- * Returns the component name of the system default textclassifier service if it can be found
- * on the system. Otherwise, returns null.
- * @param context the text classification context
- * @param settings TextClassifier specific settings.
*
+ * @param context the text classification context
* @hide
*/
@Nullable
- public static ComponentName getServiceComponentName(@NonNull Context context,
- @NonNull TextClassificationConstants settings) {
+ public static ComponentName getServiceComponentName(@NonNull Context context) {
+ final TextClassificationConstants settings = TextClassificationManager.getSettings(context);
// get override TextClassifierService package name
- String packageName = settings.getTextClassifierServiceName();
+ String packageName = settings.getTextClassifierServicePackageOverride();
+
ComponentName serviceComponent = null;
final boolean isOverrideService = !TextUtils.isEmpty(packageName);
if (isOverrideService) {
@@ -468,7 +455,7 @@ public abstract class TextClassifierService extends Service {
if (serviceComponent != null) {
return serviceComponent;
}
- // If no TextClassifierService overrode or invalid override package name, read the first
+ // If no TextClassifierService override or invalid override package name, read the first
// package defined in the config
final String[] packages = context.getPackageManager().getSystemTextClassifierPackages();
if (packages.length == 0 || TextUtils.isEmpty(packages[0])) {
diff --git a/core/java/android/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java
index 4474f3ecc620..8446253c6302 100644
--- a/core/java/android/telephony/CellBroadcastIntents.java
+++ b/core/java/android/telephony/CellBroadcastIntents.java
@@ -26,7 +26,6 @@ import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
-import android.util.Log;
/**
* A static helper class used to send Intents with prepopulated flags.
@@ -75,20 +74,20 @@ public class CellBroadcastIntents {
@Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@Nullable Bundle initialExtras) {
- Log.d(LOG_TAG, "sendOrderedBroadcastForBackgroundReceivers intent=" + intent.getAction());
int status = context.checkCallingOrSelfPermission(
"android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS");
if (status == PackageManager.PERMISSION_DENIED) {
throw new SecurityException(
"Caller does not have permission to send broadcast for background receivers");
}
- intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ Intent backgroundIntent = new Intent(intent);
+ backgroundIntent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
if (user != null) {
- context.createContextAsUser(user, 0).sendOrderedBroadcast(intent, receiverPermission,
- receiverAppOp, resultReceiver, scheduler, initialCode, initialData,
- initialExtras);
+ context.createContextAsUser(user, 0).sendOrderedBroadcast(backgroundIntent,
+ receiverPermission, receiverAppOp, resultReceiver, scheduler, initialCode,
+ initialData, initialExtras);
} else {
- context.sendOrderedBroadcast(intent, receiverPermission,
+ context.sendOrderedBroadcast(backgroundIntent, receiverPermission,
receiverAppOp, resultReceiver, scheduler, initialCode, initialData,
initialExtras);
}
diff --git a/core/java/android/text/AlteredCharSequence.java b/core/java/android/text/AlteredCharSequence.java
index 4cc71fd28e4b..971a47dba6e8 100644
--- a/core/java/android/text/AlteredCharSequence.java
+++ b/core/java/android/text/AlteredCharSequence.java
@@ -16,12 +16,14 @@
package android.text;
-// XXX should this really be in the public API at all?
/**
* An AlteredCharSequence is a CharSequence that is largely mirrored from
* another CharSequence, except that a specified range of characters are
* mirrored from a different char array instead.
+ *
+ * @deprecated The functionality this class offers is easily implemented outside the framework.
*/
+@Deprecated
public class AlteredCharSequence
implements CharSequence, GetChars
{
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 3a1df3ec861e..6a6bccf7052a 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -17,9 +17,11 @@
package android.util;
import android.annotation.UnsupportedAppUsage;
+import android.os.SystemClock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayDeque;
import java.util.Deque;
@@ -33,10 +35,22 @@ public final class LocalLog {
private final Deque<String> mLog;
private final int mMaxLines;
+ /**
+ * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log
+ * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is
+ * useful when logging behavior that modifies device time zone or system clock.
+ */
+ private final boolean mUseLocalTimestamps;
+
@UnsupportedAppUsage
public LocalLog(int maxLines) {
+ this(maxLines, true /* useLocalTimestamps */);
+ }
+
+ public LocalLog(int maxLines, boolean useLocalTimestamps) {
mMaxLines = Math.max(0, maxLines);
mLog = new ArrayDeque<>(mMaxLines);
+ mUseLocalTimestamps = useLocalTimestamps;
}
@UnsupportedAppUsage
@@ -44,7 +58,14 @@ public final class LocalLog {
if (mMaxLines <= 0) {
return;
}
- append(String.format("%s - %s", LocalDateTime.now(), msg));
+ final String logLine;
+ if (mUseLocalTimestamps) {
+ logLine = String.format("%s - %s", LocalDateTime.now(), msg);
+ } else {
+ logLine = String.format(
+ "%s / %s - %s", SystemClock.elapsedRealtime(), Instant.now(), msg);
+ }
+ append(logLine);
}
private synchronized void append(String logLine) {
diff --git a/core/java/android/util/StatsEvent.aidl b/core/java/android/util/StatsEvent.aidl
deleted file mode 100644
index deac873b0a04..000000000000
--- a/core/java/android/util/StatsEvent.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-parcelable StatsEvent cpp_header "android/util/StatsEvent.h";
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
index 7e7164042781..c7659457bdf9 100644
--- a/core/java/android/util/StatsEvent.java
+++ b/core/java/android/util/StatsEvent.java
@@ -31,14 +31,23 @@ import com.android.internal.annotations.VisibleForTesting;
*
* <p>Usage:</p>
* <pre>
+ * // Pushed event
* StatsEvent statsEvent = StatsEvent.newBuilder()
* .setAtomId(atomId)
* .writeBoolean(false)
* .writeString("annotated String field")
* .addBooleanAnnotation(annotationId, true)
+ * .usePooledBuffer()
* .build();
- *
* StatsLog.write(statsEvent);
+ *
+ * // Pulled event
+ * StatsEvent statsEvent = StatsEvent.newBuilder()
+ * .setAtomId(atomId)
+ * .writeBoolean(false)
+ * .writeString("annotated String field")
+ * .addBooleanAnnotation(annotationId, true)
+ * .build();
* </pre>
* @hide
**/
@@ -210,12 +219,15 @@ public final class StatsEvent {
private static final int MAX_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4;
private final int mAtomId;
- private final Buffer mBuffer;
+ private final byte[] mPayload;
+ private Buffer mBuffer;
private final int mNumBytes;
- private StatsEvent(final int atomId, @NonNull final Buffer buffer, final int numBytes) {
+ private StatsEvent(final int atomId, @Nullable final Buffer buffer,
+ @NonNull final byte[] payload, final int numBytes) {
mAtomId = atomId;
mBuffer = buffer;
+ mPayload = payload;
mNumBytes = numBytes;
}
@@ -243,7 +255,7 @@ public final class StatsEvent {
**/
@NonNull
public byte[] getBytes() {
- return mBuffer.getBytes();
+ return mPayload;
}
/**
@@ -256,10 +268,14 @@ public final class StatsEvent {
}
/**
- * Recycle this StatsEvent object.
+ * Recycle resources used by this StatsEvent object.
+ * No actions should be taken on this StatsEvent after release() is called.
**/
public void release() {
- mBuffer.release();
+ if (mBuffer != null) {
+ mBuffer.release();
+ mBuffer = null;
+ }
}
/**
@@ -280,7 +296,18 @@ public final class StatsEvent {
* optional string field3 = 3 [(annotation1) = true];
* }
*
- * // StatsEvent construction.
+ * // StatsEvent construction for pushed event.
+ * StatsEvent.newBuilder()
+ * StatsEvent statsEvent = StatsEvent.newBuilder()
+ * .setAtomId(atomId)
+ * .writeInt(3) // field1
+ * .writeLong(8L) // field2
+ * .writeString("foo") // field 3
+ * .addBooleanAnnotation(annotation1Id, true)
+ * .usePooledBuffer()
+ * .build();
+ *
+ * // StatsEvent construction for pulled event.
* StatsEvent.newBuilder()
* StatsEvent statsEvent = StatsEvent.newBuilder()
* .setAtomId(atomId)
@@ -306,6 +333,7 @@ public final class StatsEvent {
private byte mLastType;
private int mNumElements;
private int mErrorMask;
+ private boolean mUsePooledBuffer = false;
private Builder(final Buffer buffer) {
mBuffer = buffer;
@@ -569,6 +597,17 @@ public final class StatsEvent {
}
/**
+ * Indicates to reuse Buffer's byte array as the underlying payload in StatsEvent.
+ * This should be called for pushed events to reduce memory allocations and garbage
+ * collections.
+ **/
+ @NonNull
+ public Builder usePooledBuffer() {
+ mUsePooledBuffer = true;
+ return this;
+ }
+
+ /**
* Builds a StatsEvent object with values entered in this Builder.
**/
@NonNull
@@ -599,7 +638,18 @@ public final class StatsEvent {
size = mPos;
}
- return new StatsEvent(mAtomId, mBuffer, size);
+ if (mUsePooledBuffer) {
+ return new StatsEvent(mAtomId, mBuffer, mBuffer.getBytes(), size);
+ } else {
+ // Create a copy of the buffer with the required number of bytes.
+ final byte[] payload = new byte[size];
+ System.arraycopy(mBuffer.getBytes(), 0, payload, 0, size);
+
+ // Return Buffer instance to the pool.
+ mBuffer.release();
+
+ return new StatsEvent(mAtomId, null, payload, size);
+ }
}
private void writeTypeId(final byte typeId) {
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index 8cb5b05df685..9ac4cf267b47 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -248,12 +248,15 @@ public final class StatsLog extends StatsLogInternal {
/**
* Write an event to stats log using the raw format encapsulated in StatsEvent.
+ * After writing to stats log, release() is called on the StatsEvent object.
+ * No further action should be taken on the StatsEvent object following this call.
*
* @param statsEvent The StatsEvent object containing the encoded buffer of data to write.
* @hide
*/
public static void write(@NonNull final StatsEvent statsEvent) {
writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId());
+ statsEvent.release();
}
private static void enforceDumpCallingPermission(Context context) {
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index 443bbd8597af..e81e3f7b38d6 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -70,22 +70,6 @@ public abstract class VerityBuilder {
/**
* Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link
- * ByteBuffer} created by the {@link ByteBufferFactory}. The output is suitable to be used as
- * the on-disk format for fs-verity to use.
- *
- * @return VerityResult containing a buffer with the generated Merkle tree stored at the
- * front, the tree size, and the calculated root hash.
- */
- @NonNull
- public static VerityResult generateFsVerityTree(@NonNull RandomAccessFile apk,
- @NonNull ByteBufferFactory bufferFactory)
- throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
- return generateVerityTreeInternal(apk, bufferFactory, null /* signatureInfo */,
- false /* skipSigningBlock */);
- }
-
- /**
- * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link
* ByteBuffer} created by the {@link ByteBufferFactory}. The Merkle tree does not cover Signing
* Block specificed in {@code signatureInfo}. The output is suitable to be used as the on-disk
* format for fs-verity to use (with elide and patch extensions).
@@ -97,21 +81,16 @@ public abstract class VerityBuilder {
public static VerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,
@Nullable SignatureInfo signatureInfo, @NonNull ByteBufferFactory bufferFactory)
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
- return generateVerityTreeInternal(apk, bufferFactory, signatureInfo,
- true /* skipSigningBlock */);
+ return generateVerityTreeInternal(apk, bufferFactory, signatureInfo);
}
@NonNull
private static VerityResult generateVerityTreeInternal(@NonNull RandomAccessFile apk,
- @NonNull ByteBufferFactory bufferFactory, @Nullable SignatureInfo signatureInfo,
- boolean skipSigningBlock)
+ @NonNull ByteBufferFactory bufferFactory, @Nullable SignatureInfo signatureInfo)
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
- long dataSize = apk.length();
- if (skipSigningBlock) {
- long signingBlockSize =
- signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
- dataSize -= signingBlockSize;
- }
+ long signingBlockSize =
+ signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+ long dataSize = apk.length() - signingBlockSize;
int[] levelOffset = calculateVerityLevelOffset(dataSize);
int merkleTreeSize = levelOffset[levelOffset.length - 1];
@@ -120,10 +99,8 @@ public abstract class VerityBuilder {
+ CHUNK_SIZE_BYTES); // maximum size of apk-verity metadata
output.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer tree = slice(output, 0, merkleTreeSize);
- // Only use default salt in legacy case.
- byte[] salt = skipSigningBlock ? DEFAULT_SALT : null;
- byte[] apkRootHash = generateVerityTreeInternal(apk, signatureInfo, salt, levelOffset,
- tree, skipSigningBlock);
+ byte[] apkRootHash = generateVerityTreeInternal(apk, signatureInfo, DEFAULT_SALT,
+ levelOffset, tree);
return new VerityResult(output, merkleTreeSize, apkRootHash);
}
@@ -173,8 +150,7 @@ public abstract class VerityBuilder {
throws IOException, SignatureNotFoundException, SecurityException, DigestException,
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
- VerityResult result = generateVerityTreeInternal(apk, bufferFactory, signatureInfo,
- true /* skipSigningBlock */);
+ VerityResult result = generateVerityTreeInternal(apk, bufferFactory, signatureInfo);
ByteBuffer footer = slice(result.verityData, result.merkleTreeSize,
result.verityData.limit());
generateApkVerityFooter(apk, signatureInfo, footer);
@@ -351,17 +327,12 @@ public abstract class VerityBuilder {
@NonNull
private static byte[] generateVerityTreeInternal(@NonNull RandomAccessFile apk,
@Nullable SignatureInfo signatureInfo, @Nullable byte[] salt,
- @NonNull int[] levelOffset, @NonNull ByteBuffer output, boolean skipSigningBlock)
+ @NonNull int[] levelOffset, @NonNull ByteBuffer output)
throws IOException, NoSuchAlgorithmException, DigestException {
// 1. Digest the apk to generate the leaf level hashes.
- if (skipSigningBlock) {
- assertSigningBlockAlignedAndHasFullPages(signatureInfo);
- generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
- levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
- } else {
- generateFsVerityDigestAtLeafLevel(apk, slice(output,
- levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
- }
+ assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+ generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
+ levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
// 2. Digest the lower level hashes bottom up.
for (int level = levelOffset.length - 3; level >= 0; level--) {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 03e68b0058b2..ba2509302094 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1525,5 +1525,14 @@ public final class Display {
public int describeContents() {
return 0;
}
+
+ @Override
+ public String toString() {
+ return "HdrCapabilities{"
+ + "mSupportedHdrTypes=" + Arrays.toString(mSupportedHdrTypes)
+ + ", mMaxLuminance=" + mMaxLuminance
+ + ", mMaxAverageLuminance=" + mMaxAverageLuminance
+ + ", mMinLuminance=" + mMinLuminance + '}';
+ }
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index c699cdca4d00..d79abc207bfd 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1170,16 +1170,6 @@ public abstract class Window {
/**
* {@hide}
*/
- @UnsupportedAppUsage
- protected void setNeedsMenuKey(int value) {
- final WindowManager.LayoutParams attrs = getAttributes();
- attrs.needsMenuKey = value;
- dispatchWindowAttributesChanged(attrs);
- }
-
- /**
- * {@hide}
- */
protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
if (mCallback != null) {
mCallback.onWindowAttributesChanged(attrs);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d40f8325c320..9d5f98e4a24c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -29,7 +29,6 @@ import static android.view.WindowLayoutParamsProto.HAS_SYSTEM_UI_LISTENERS;
import static android.view.WindowLayoutParamsProto.HEIGHT;
import static android.view.WindowLayoutParamsProto.HORIZONTAL_MARGIN;
import static android.view.WindowLayoutParamsProto.INPUT_FEATURE_FLAGS;
-import static android.view.WindowLayoutParamsProto.NEEDS_MENU_KEY;
import static android.view.WindowLayoutParamsProto.PREFERRED_REFRESH_RATE;
import static android.view.WindowLayoutParamsProto.PRIVATE_FLAGS;
import static android.view.WindowLayoutParamsProto.ROTATION_ANIMATION;
@@ -1106,6 +1105,13 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;
/**
+ * Window type: Window for adding accessibility window magnification above other windows.
+ * This will place the window in the overlay windows.
+ * @hide
+ */
+ public static final int TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
@@ -1941,48 +1947,6 @@ public interface WindowManager extends ViewManager {
public int privateFlags;
/**
- * Value for {@link #needsMenuKey} for a window that has not explicitly specified if it
- * needs {@link #NEEDS_MENU_SET_TRUE} or doesn't need {@link #NEEDS_MENU_SET_FALSE} a menu
- * key. For this case, we should look at windows behind it to determine the appropriate
- * value.
- *
- * @hide
- */
- public static final int NEEDS_MENU_UNSET = 0;
-
- /**
- * Value for {@link #needsMenuKey} for a window that has explicitly specified it needs a
- * menu key.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static final int NEEDS_MENU_SET_TRUE = 1;
-
- /**
- * Value for {@link #needsMenuKey} for a window that has explicitly specified it doesn't
- * needs a menu key.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static final int NEEDS_MENU_SET_FALSE = 2;
-
- /**
- * State variable for a window belonging to an activity that responds to
- * {@link KeyEvent#KEYCODE_MENU} and therefore needs a Menu key. For devices where Menu is a
- * physical button this variable is ignored, but on devices where the Menu key is drawn in
- * software it may be hidden unless this variable is set to {@link #NEEDS_MENU_SET_TRUE}.
- *
- * (Note that Action Bars, when available, are the preferred way to offer additional
- * functions otherwise accessed via an options menu.)
- *
- * {@hide}
- */
- @UnsupportedAppUsage
- public int needsMenuKey = NEEDS_MENU_UNSET;
-
- /**
* Given a particular set of window manager flags, determine whether
* such a window may be a target for an input method when it has
* focus. In particular, this checks the
@@ -2784,7 +2748,6 @@ public interface WindowManager extends ViewManager {
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
- out.writeInt(needsMenuKey);
out.writeLong(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
out.writeInt(mColorMode);
@@ -2842,7 +2805,6 @@ public interface WindowManager extends ViewManager {
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
preservePreviousSurfaceInsets = in.readInt() != 0;
- needsMenuKey = in.readInt();
accessibilityIdOfAnchor = in.readLong();
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mColorMode = in.readInt();
@@ -2884,8 +2846,6 @@ public interface WindowManager extends ViewManager {
/** {@hide} */
public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
/** {@hide} */
- public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22;
- /** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
@@ -3059,11 +3019,6 @@ public interface WindowManager extends ViewManager {
changes |= SURFACE_INSETS_CHANGED;
}
- if (needsMenuKey != o.needsMenuKey) {
- needsMenuKey = o.needsMenuKey;
- changes |= NEEDS_MENU_KEY_CHANGED;
- }
-
if (accessibilityIdOfAnchor != o.accessibilityIdOfAnchor) {
accessibilityIdOfAnchor = o.accessibilityIdOfAnchor;
changes |= ACCESSIBILITY_ANCHOR_CHANGED;
@@ -3217,9 +3172,6 @@ public interface WindowManager extends ViewManager {
sb.append(" (!preservePreviousSurfaceInsets)");
}
}
- if (needsMenuKey == NEEDS_MENU_SET_TRUE) {
- sb.append(" needsMenuKey");
- }
if (mColorMode != COLOR_MODE_DEFAULT) {
sb.append(" colorMode=").append(ActivityInfo.colorModeToString(mColorMode));
}
@@ -3281,7 +3233,6 @@ public interface WindowManager extends ViewManager {
proto.write(HAS_SYSTEM_UI_LISTENERS, hasSystemUiListeners);
proto.write(INPUT_FEATURE_FLAGS, inputFeatures);
proto.write(USER_ACTIVITY_TIMEOUT, userActivityTimeout);
- proto.write(NEEDS_MENU_KEY, needsMenuKey);
proto.write(COLOR_MODE, mColorMode);
proto.write(FLAGS, flags);
proto.write(PRIVATE_FLAGS, privateFlags);
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index cc2884075c39..843f8e33c66a 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -117,7 +117,7 @@ public final class AccessibilityManager {
* Activity action: Launch UI to manage which accessibility service or feature is assigned
* to the navigation bar Accessibility button.
* <p>
- * Input: Nothing.
+ * Input: {@link #EXTRA_SHORTCUT_TYPE} is the shortcut type.
* </p>
* <p>
* Output: Nothing.
@@ -130,6 +130,42 @@ public final class AccessibilityManager {
"com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
/**
+ * Used as an int extra field in {@link #ACTION_CHOOSE_ACCESSIBILITY_BUTTON} intent to specify
+ * the shortcut type.
+ *
+ * @hide
+ */
+ public static final String EXTRA_SHORTCUT_TYPE =
+ "com.android.internal.intent.extra.SHORTCUT_TYPE";
+
+ /**
+ * Used as an int value for {@link #EXTRA_SHORTCUT_TYPE} to represent the accessibility button
+ * shortcut type.
+ *
+ * @hide
+ */
+ public static final int ACCESSIBILITY_BUTTON = 0;
+
+ /**
+ * Used as an int value for {@link #EXTRA_SHORTCUT_TYPE} to represent hardware key shortcut,
+ * such as volume key button.
+ *
+ * @hide
+ */
+ public static final int ACCESSIBILITY_SHORTCUT_KEY = 1;
+
+ /**
+ * Annotations for the shortcut type.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ ACCESSIBILITY_BUTTON,
+ ACCESSIBILITY_SHORTCUT_KEY
+ })
+ public @interface ShortcutType {}
+
+ /**
* Annotations for content flag of UI.
* @hide
*/
@@ -1242,27 +1278,28 @@ public final class AccessibilityManager {
}
/**
- * Get the component name of the service currently assigned to the accessibility shortcut.
+ * Returns the list of shortcut target names currently assigned to the given shortcut.
*
- * @return The flattened component name
+ * @param shortcutType The shortcut type.
+ * @return The list of shortcut target names.
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
- @Nullable
- public String getAccessibilityShortcutService() {
+ @NonNull
+ public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
final IAccessibilityManager service;
synchronized (mLock) {
service = getServiceLocked();
}
if (service != null) {
try {
- return service.getAccessibilityShortcutService();
+ return service.getAccessibilityShortcutTargets(shortcutType);
} catch (RemoteException re) {
re.rethrowFromSystemServer();
}
}
- return null;
+ return Collections.emptyList();
}
/**
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 023fda52a1b1..36515b3ba094 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -73,7 +73,7 @@ interface IAccessibilityManager {
void performAccessibilityShortcut();
// Requires Manifest.permission.MANAGE_ACCESSIBILITY
- String getAccessibilityShortcutService();
+ List<String> getAccessibilityShortcutTargets(int shortcutType);
// System process only
boolean sendFingerprintGesture(int gestureKeyCode);
diff --git a/core/java/android/view/textclassifier/ConfigParser.java b/core/java/android/view/textclassifier/ConfigParser.java
deleted file mode 100644
index 9b51458d27d9..000000000000
--- a/core/java/android/view/textclassifier/ConfigParser.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.view.textclassifier;
-
-import android.annotation.Nullable;
-import android.provider.DeviceConfig;
-import android.util.ArrayMap;
-import android.util.KeyValueListParser;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.annotations.VisibleForTesting.Visibility;
-import com.android.internal.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Supplier;
-
-/**
- * Retrieves settings from {@link DeviceConfig} and {@link android.provider.Settings}.
- * It will try DeviceConfig first and then Settings.
- *
- * @hide
- */
-@VisibleForTesting(visibility = Visibility.PACKAGE)
-public final class ConfigParser {
- private static final String TAG = "ConfigParser";
-
- public static final boolean ENABLE_DEVICE_CONFIG = true;
-
- private static final String STRING_LIST_DELIMITER = ":";
-
- private final Supplier<String> mLegacySettingsSupplier;
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private final Map<String, Object> mCache = new ArrayMap<>();
- @GuardedBy("mLock")
- private @Nullable KeyValueListParser mSettingsParser; // Call getLegacySettings() instead.
-
- public ConfigParser(Supplier<String> legacySettingsSupplier) {
- mLegacySettingsSupplier = Preconditions.checkNotNull(legacySettingsSupplier);
- }
-
- private KeyValueListParser getLegacySettings() {
- synchronized (mLock) {
- if (mSettingsParser == null) {
- final String legacySettings = mLegacySettingsSupplier.get();
- try {
- mSettingsParser = new KeyValueListParser(',');
- mSettingsParser.setString(legacySettings);
- } catch (IllegalArgumentException e) {
- // Failed to parse the settings string, log this and move on with defaults.
- Log.w(TAG, "Bad text_classifier_constants: " + legacySettings);
- }
- }
- return mSettingsParser;
- }
- }
-
- /**
- * Reads a boolean setting through the cache.
- */
- public boolean getBoolean(String key, boolean defaultValue) {
- synchronized (mLock) {
- final Object cached = mCache.get(key);
- if (cached instanceof Boolean) {
- return (boolean) cached;
- }
- final boolean value;
- if (ENABLE_DEVICE_CONFIG) {
- value = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- getLegacySettings().getBoolean(key, defaultValue));
- } else {
- value = getLegacySettings().getBoolean(key, defaultValue);
- }
- mCache.put(key, value);
- return value;
- }
- }
-
- /**
- * Reads an integer setting through the cache.
- */
- public int getInt(String key, int defaultValue) {
- synchronized (mLock) {
- final Object cached = mCache.get(key);
- if (cached instanceof Integer) {
- return (int) cached;
- }
- final int value;
- if (ENABLE_DEVICE_CONFIG) {
- value = DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- getLegacySettings().getInt(key, defaultValue));
- } else {
- value = getLegacySettings().getInt(key, defaultValue);
- }
- mCache.put(key, value);
- return value;
- }
- }
-
- /**
- * Reads a float setting through the cache.
- */
- public float getFloat(String key, float defaultValue) {
- synchronized (mLock) {
- final Object cached = mCache.get(key);
- if (cached instanceof Float) {
- return (float) cached;
- }
- final float value;
- if (ENABLE_DEVICE_CONFIG) {
- value = DeviceConfig.getFloat(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- getLegacySettings().getFloat(key, defaultValue));
- } else {
- value = getLegacySettings().getFloat(key, defaultValue);
- }
- mCache.put(key, value);
- return value;
- }
- }
-
- /**
- * Reads a string setting through the cache.
- */
- public String getString(String key, String defaultValue) {
- synchronized (mLock) {
- final Object cached = mCache.get(key);
- if (cached instanceof String) {
- return (String) cached;
- }
- final String value;
- if (ENABLE_DEVICE_CONFIG) {
- value = DeviceConfig.getString(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- getLegacySettings().getString(key, defaultValue));
- } else {
- value = getLegacySettings().getString(key, defaultValue);
- }
- mCache.put(key, value);
- return value;
- }
- }
-
- /**
- * Reads a string list setting through the cache.
- */
- public List<String> getStringList(String key, List<String> defaultValue) {
- synchronized (mLock) {
- final Object cached = mCache.get(key);
- if (cached instanceof List) {
- final List asList = (List) cached;
- if (asList.isEmpty()) {
- return Collections.emptyList();
- } else if (asList.get(0) instanceof String) {
- return (List<String>) cached;
- }
- }
- final List<String> value;
- if (ENABLE_DEVICE_CONFIG) {
- value = getDeviceConfigStringList(
- key,
- getSettingsStringList(key, defaultValue));
- } else {
- value = getSettingsStringList(key, defaultValue);
- }
- mCache.put(key, value);
- return value;
- }
- }
-
- /**
- * Reads a float array through the cache. The returned array should be expected to be of the
- * same length as that of the defaultValue.
- */
- public float[] getFloatArray(String key, float[] defaultValue) {
- synchronized (mLock) {
- final Object cached = mCache.get(key);
- if (cached instanceof float[]) {
- return (float[]) cached;
- }
- final float[] value;
- if (ENABLE_DEVICE_CONFIG) {
- value = getDeviceConfigFloatArray(
- key,
- getSettingsFloatArray(key, defaultValue));
- } else {
- value = getSettingsFloatArray(key, defaultValue);
- }
- mCache.put(key, value);
- return value;
- }
- }
-
- private List<String> getSettingsStringList(String key, List<String> defaultValue) {
- return parse(mSettingsParser.getString(key, null), defaultValue);
- }
-
- private static List<String> getDeviceConfigStringList(String key, List<String> defaultValue) {
- return parse(
- DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
- defaultValue);
- }
-
- private static float[] getDeviceConfigFloatArray(String key, float[] defaultValue) {
- return parse(
- DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
- defaultValue);
- }
-
- private float[] getSettingsFloatArray(String key, float[] defaultValue) {
- return parse(mSettingsParser.getString(key, null), defaultValue);
- }
-
- private static List<String> parse(@Nullable String listStr, List<String> defaultValue) {
- if (listStr != null) {
- return Collections.unmodifiableList(
- Arrays.asList(listStr.split(STRING_LIST_DELIMITER)));
- }
- return defaultValue;
- }
-
- private static float[] parse(@Nullable String arrayStr, float[] defaultValue) {
- if (arrayStr != null) {
- final String[] split = arrayStr.split(STRING_LIST_DELIMITER);
- if (split.length != defaultValue.length) {
- return defaultValue;
- }
- final float[] result = new float[split.length];
- for (int i = 0; i < split.length; i++) {
- try {
- result[i] = Float.parseFloat(split[i]);
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
- return result;
- } else {
- return defaultValue;
- }
- }
-}
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 12ed4b971e83..7d1077e50258 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -161,7 +161,6 @@ public final class SelectionEvent implements Parcelable {
mEntityType = in.readString();
mWidgetVersion = in.readInt() > 0 ? in.readString() : null;
mPackageName = in.readString();
- mUserId = in.readInt();
mWidgetType = in.readString();
mInvocationMethod = in.readInt();
mResultId = in.readString();
@@ -175,6 +174,7 @@ public final class SelectionEvent implements Parcelable {
mEnd = in.readInt();
mSmartStart = in.readInt();
mSmartEnd = in.readInt();
+ mUserId = in.readInt();
}
@Override
@@ -188,7 +188,6 @@ public final class SelectionEvent implements Parcelable {
dest.writeString(mWidgetVersion);
}
dest.writeString(mPackageName);
- dest.writeInt(mUserId);
dest.writeString(mWidgetType);
dest.writeInt(mInvocationMethod);
dest.writeString(mResultId);
@@ -204,6 +203,7 @@ public final class SelectionEvent implements Parcelable {
dest.writeInt(mEnd);
dest.writeInt(mSmartStart);
dest.writeInt(mSmartEnd);
+ dest.writeInt(mUserId);
}
@Override
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 9f8671aad313..ed69513b7f69 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -16,38 +16,31 @@
package android.view.textclassifier;
+import android.annotation.Nullable;
+import android.provider.DeviceConfig;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
-import java.util.function.Supplier;
/**
* TextClassifier specific settings.
- * This is encoded as a key=value list, separated by commas.
- * <p>
- * Example of setting the values for testing.
- * <p>
- * <pre>
- * adb shell settings put global text_classifier_constants \
- * model_dark_launch_enabled=true,smart_selection_enabled=true, \
- * entity_list_default=phone:address, \
- * lang_id_context_settings=20:1.0:0.4
- * </pre>
- * <p>
- * Settings are also available in device config. These take precedence over those in settings
- * global.
- * <p>
+ *
+ * <p>Currently, this class does not guarantee co-diverted flags are updated atomically.
+ *
* <pre>
* adb shell cmd device_config put textclassifier system_textclassifier_enabled true
* </pre>
*
- * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
- * @see android.provider.DeviceConfig.NAMESPACE_TEXTCLASSIFIER
+ * @see android.provider.DeviceConfig#NAMESPACE_TEXTCLASSIFIER
* @hide
*/
// TODO: Rename to TextClassifierSettings.
public final class TextClassificationConstants {
+ private static final String DELIMITER = ":";
/**
* Whether the smart linkify feature is enabled.
@@ -56,11 +49,12 @@ public final class TextClassificationConstants {
/**
* Whether SystemTextClassifier is enabled.
*/
- private static final String SYSTEM_TEXT_CLASSIFIER_ENABLED = "system_textclassifier_enabled";
+ static final String SYSTEM_TEXT_CLASSIFIER_ENABLED = "system_textclassifier_enabled";
/**
* Whether TextClassifierImpl is enabled.
*/
- private static final String LOCAL_TEXT_CLASSIFIER_ENABLED = "local_textclassifier_enabled";
+ @VisibleForTesting
+ static final String LOCAL_TEXT_CLASSIFIER_ENABLED = "local_textclassifier_enabled";
/**
* Enable smart selection without a visible UI changes.
*/
@@ -82,7 +76,8 @@ public final class TextClassificationConstants {
/**
* Max length of text that suggestSelection can accept.
*/
- private static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
+ @VisibleForTesting
+ static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
"suggest_selection_max_range_length";
/**
* Max length of text that classifyText can accept.
@@ -101,7 +96,8 @@ public final class TextClassificationConstants {
* A colon(:) separated string that specifies the default entities types for
* generateLinks when hint is not given.
*/
- private static final String ENTITY_LIST_DEFAULT = "entity_list_default";
+ @VisibleForTesting
+ static final String ENTITY_LIST_DEFAULT = "entity_list_default";
/**
* A colon(:) separated string that specifies the default entities types for
* generateLinks when the text is in a not editable UI widget.
@@ -127,7 +123,8 @@ public final class TextClassificationConstants {
/**
* Threshold to accept a suggested language from LangID model.
*/
- private static final String LANG_ID_THRESHOLD_OVERRIDE = "lang_id_threshold_override";
+ @VisibleForTesting
+ static final String LANG_ID_THRESHOLD_OVERRIDE = "lang_id_threshold_override";
/**
* Whether to enable {@link android.view.textclassifier.TemplateIntentFactory}.
*/
@@ -156,7 +153,8 @@ public final class TextClassificationConstants {
* Reject all text less than minimumTextSize with penalizeRatio=0
* @see {@code TextClassifierImpl#detectLanguages(String, int, int)} for reference.
*/
- private static final String LANG_ID_CONTEXT_SETTINGS = "lang_id_context_settings";
+ @VisibleForTesting
+ static final String LANG_ID_CONTEXT_SETTINGS = "lang_id_context_settings";
/**
* The TextClassifierService which would like to use. Example of setting the package:
@@ -164,9 +162,9 @@ public final class TextClassificationConstants {
* adb shell cmd device_config put textclassifier textclassifier_service_package_override \
* com.android.textclassifier
* </pre>
- *
*/
- private static final String TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE =
+ @VisibleForTesting
+ static final String TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE =
"textclassifier_service_package_override";
private static final String DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE = null;
@@ -213,142 +211,124 @@ public final class TextClassificationConstants {
private static final boolean DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT = true;
private static final float[] LANG_ID_CONTEXT_SETTINGS_DEFAULT = new float[] {20f, 1.0f, 0.4f};
- private final ConfigParser mConfigParser;
-
- public TextClassificationConstants(Supplier<String> legacySettingsSupplier) {
- mConfigParser = new ConfigParser(legacySettingsSupplier);
- }
-
- public String getTextClassifierServiceName() {
- return mConfigParser.getString(
+ @Nullable
+ public String getTextClassifierServicePackageOverride() {
+ return DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE,
DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE);
}
public boolean isLocalTextClassifierEnabled() {
- return mConfigParser.getBoolean(
- LOCAL_TEXT_CLASSIFIER_ENABLED,
- LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT);
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ LOCAL_TEXT_CLASSIFIER_ENABLED, LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT);
}
public boolean isSystemTextClassifierEnabled() {
- return mConfigParser.getBoolean(
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
SYSTEM_TEXT_CLASSIFIER_ENABLED,
SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT);
}
public boolean isModelDarkLaunchEnabled() {
- return mConfigParser.getBoolean(
- MODEL_DARK_LAUNCH_ENABLED,
- MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ MODEL_DARK_LAUNCH_ENABLED, MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
}
public boolean isSmartSelectionEnabled() {
- return mConfigParser.getBoolean(
- SMART_SELECTION_ENABLED,
- SMART_SELECTION_ENABLED_DEFAULT);
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ SMART_SELECTION_ENABLED, SMART_SELECTION_ENABLED_DEFAULT);
}
public boolean isSmartTextShareEnabled() {
- return mConfigParser.getBoolean(
- SMART_TEXT_SHARE_ENABLED,
- SMART_TEXT_SHARE_ENABLED_DEFAULT);
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ SMART_TEXT_SHARE_ENABLED, SMART_TEXT_SHARE_ENABLED_DEFAULT);
}
public boolean isSmartLinkifyEnabled() {
- return mConfigParser.getBoolean(
- SMART_LINKIFY_ENABLED,
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, SMART_LINKIFY_ENABLED,
SMART_LINKIFY_ENABLED_DEFAULT);
}
public boolean isSmartSelectionAnimationEnabled() {
- return mConfigParser.getBoolean(
- SMART_SELECT_ANIMATION_ENABLED,
- SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ SMART_SELECT_ANIMATION_ENABLED, SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
}
public int getSuggestSelectionMaxRangeLength() {
- return mConfigParser.getInt(
- SUGGEST_SELECTION_MAX_RANGE_LENGTH,
- SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
+ return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ SUGGEST_SELECTION_MAX_RANGE_LENGTH, SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
}
public int getClassifyTextMaxRangeLength() {
- return mConfigParser.getInt(
- CLASSIFY_TEXT_MAX_RANGE_LENGTH,
- CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
+ return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ CLASSIFY_TEXT_MAX_RANGE_LENGTH, CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
}
public int getGenerateLinksMaxTextLength() {
- return mConfigParser.getInt(
- GENERATE_LINKS_MAX_TEXT_LENGTH,
- GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
+ return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ GENERATE_LINKS_MAX_TEXT_LENGTH, GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
}
public int getGenerateLinksLogSampleRate() {
- return mConfigParser.getInt(
- GENERATE_LINKS_LOG_SAMPLE_RATE,
- GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
+ return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ GENERATE_LINKS_LOG_SAMPLE_RATE, GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
}
public List<String> getEntityListDefault() {
- return mConfigParser.getStringList(
- ENTITY_LIST_DEFAULT,
- ENTITY_LIST_DEFAULT_VALUE);
+ return getDeviceConfigStringList(ENTITY_LIST_DEFAULT, ENTITY_LIST_DEFAULT_VALUE);
}
public List<String> getEntityListNotEditable() {
- return mConfigParser.getStringList(
- ENTITY_LIST_NOT_EDITABLE,
- ENTITY_LIST_DEFAULT_VALUE);
+ return getDeviceConfigStringList(ENTITY_LIST_NOT_EDITABLE, ENTITY_LIST_DEFAULT_VALUE);
}
public List<String> getEntityListEditable() {
- return mConfigParser.getStringList(
- ENTITY_LIST_EDITABLE,
- ENTITY_LIST_DEFAULT_VALUE);
+ return getDeviceConfigStringList(ENTITY_LIST_EDITABLE, ENTITY_LIST_DEFAULT_VALUE);
}
public List<String> getInAppConversationActionTypes() {
- return mConfigParser.getStringList(
+ return getDeviceConfigStringList(
IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT,
CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
}
public List<String> getNotificationConversationActionTypes() {
- return mConfigParser.getStringList(
+ return getDeviceConfigStringList(
NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT,
CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
}
public float getLangIdThresholdOverride() {
- return mConfigParser.getFloat(
+ return DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
LANG_ID_THRESHOLD_OVERRIDE,
LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
}
public boolean isTemplateIntentFactoryEnabled() {
- return mConfigParser.getBoolean(
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
TEMPLATE_INTENT_FACTORY_ENABLED,
TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
}
public boolean isTranslateInClassificationEnabled() {
- return mConfigParser.getBoolean(
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
TRANSLATE_IN_CLASSIFICATION_ENABLED,
TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
}
public boolean isDetectLanguagesFromTextEnabled() {
- return mConfigParser.getBoolean(
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
DETECT_LANGUAGES_FROM_TEXT_ENABLED,
DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
}
public float[] getLangIdContextSettings() {
- return mConfigParser.getFloatArray(
- LANG_ID_CONTEXT_SETTINGS,
- LANG_ID_CONTEXT_SETTINGS_DEFAULT);
+ return getDeviceConfigFloatArray(
+ LANG_ID_CONTEXT_SETTINGS, LANG_ID_CONTEXT_SETTINGS_DEFAULT);
}
void dump(IndentingPrintWriter pw) {
@@ -356,7 +336,7 @@ public final class TextClassificationConstants {
pw.increaseIndent();
pw.printPair("classify_text_max_range_length", getClassifyTextMaxRangeLength())
.println();
- pw.printPair("detect_language_from_text_enabled", isDetectLanguagesFromTextEnabled())
+ pw.printPair("detect_languages_from_text_enabled", isDetectLanguagesFromTextEnabled())
.println();
pw.printPair("entity_list_default", getEntityListDefault())
.println();
@@ -396,8 +376,47 @@ public final class TextClassificationConstants {
.println();
pw.printPair("translate_in_classification_enabled", isTranslateInClassificationEnabled())
.println();
- pw.printPair("textclassifier_service_package_override", getTextClassifierServiceName())
- .println();
+ pw.printPair("textclassifier_service_package_override",
+ getTextClassifierServicePackageOverride()).println();
pw.decreaseIndent();
}
+
+ private static List<String> getDeviceConfigStringList(String key, List<String> defaultValue) {
+ return parse(
+ DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
+ defaultValue);
+ }
+
+ private static float[] getDeviceConfigFloatArray(String key, float[] defaultValue) {
+ return parse(
+ DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
+ defaultValue);
+ }
+
+ private static List<String> parse(@Nullable String listStr, List<String> defaultValue) {
+ if (listStr != null) {
+ return Collections.unmodifiableList(Arrays.asList(listStr.split(DELIMITER)));
+ }
+ return defaultValue;
+ }
+
+ private static float[] parse(@Nullable String arrayStr, float[] defaultValue) {
+ if (arrayStr != null) {
+ final String[] split = arrayStr.split(DELIMITER);
+ if (split.length != defaultValue.length) {
+ return defaultValue;
+ }
+ final float[] result = new float[split.length];
+ for (int i = 0; i < split.length; i++) {
+ try {
+ result[i] = Float.parseFloat(split[i]);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+ return result;
+ } else {
+ return defaultValue;
+ }
+ }
} \ No newline at end of file
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 3e0f7eef33a7..7c25bf0f277d 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -22,11 +22,9 @@ import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
import android.content.Context;
-import android.database.ContentObserver;
import android.os.ServiceManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
-import android.provider.Settings;
import android.service.textclassifier.TextClassifierService;
import android.view.textclassifier.TextClassifier.TextClassifierType;
@@ -36,6 +34,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import java.lang.ref.WeakReference;
+import java.util.Set;
/**
* Interface to the text classification service.
@@ -46,7 +45,7 @@ public final class TextClassificationManager {
private static final String LOG_TAG = "TextClassificationManager";
private static final TextClassificationConstants sDefaultSettings =
- new TextClassificationConstants(() -> null);
+ new TextClassificationConstants();
private final Object mLock = new Object();
private final TextClassificationSessionFactory mDefaultSessionFactory =
@@ -132,10 +131,7 @@ public final class TextClassificationManager {
private TextClassificationConstants getSettings() {
synchronized (mLock) {
if (mSettings == null) {
- mSettings = new TextClassificationConstants(
- () -> Settings.Global.getString(
- getApplicationContext().getContentResolver(),
- Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
+ mSettings = new TextClassificationConstants();
}
return mSettings;
}
@@ -201,11 +197,7 @@ public final class TextClassificationManager {
try {
// Note that fields could be null if the constructor threw.
if (mSettingsObserver != null) {
- getApplicationContext().getContentResolver()
- .unregisterContentObserver(mSettingsObserver);
- if (ConfigParser.ENABLE_DEVICE_CONFIG) {
- DeviceConfig.removeOnPropertiesChangedListener(mSettingsObserver);
- }
+ DeviceConfig.removeOnPropertiesChangedListener(mSettingsObserver);
}
} finally {
super.finalize();
@@ -250,7 +242,7 @@ public final class TextClassificationManager {
private boolean isSystemTextClassifierEnabled() {
return getSettings().isSystemTextClassifierEnabled()
- && TextClassifierService.getServiceComponentName(mContext, getSettings()) != null;
+ && TextClassifierService.getServiceComponentName(mContext) != null;
}
/** @hide */
@@ -262,6 +254,12 @@ public final class TextClassificationManager {
private void invalidate() {
synchronized (mLock) {
mSettings = null;
+ invalidateTextClassifiers();
+ }
+ }
+
+ private void invalidateTextClassifiers() {
+ synchronized (mLock) {
mLocalTextClassifier = null;
mSystemTextClassifier = null;
}
@@ -293,40 +291,29 @@ public final class TextClassificationManager {
}
}
- private static final class SettingsObserver extends ContentObserver
- implements DeviceConfig.OnPropertiesChangedListener {
+ private static final class SettingsObserver implements
+ DeviceConfig.OnPropertiesChangedListener {
private final WeakReference<TextClassificationManager> mTcm;
SettingsObserver(TextClassificationManager tcm) {
- super(null);
mTcm = new WeakReference<>(tcm);
- tcm.getApplicationContext().getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_CONSTANTS),
- false /* notifyForDescendants */,
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ ActivityThread.currentApplication().getMainExecutor(),
this);
- if (ConfigParser.ENABLE_DEVICE_CONFIG) {
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- ActivityThread.currentApplication().getMainExecutor(),
- this);
- }
- }
-
- @Override
- public void onChange(boolean selfChange) {
- invalidateSettings();
}
@Override
public void onPropertiesChanged(Properties properties) {
- invalidateSettings();
- }
-
- private void invalidateSettings() {
final TextClassificationManager tcm = mTcm.get();
if (tcm != null) {
- tcm.invalidate();
+ final Set<String> keys = properties.getKeyset();
+ if (keys.contains(TextClassificationConstants.SYSTEM_TEXT_CLASSIFIER_ENABLED)
+ || keys.contains(
+ TextClassificationConstants.LOCAL_TEXT_CLASSIFIER_ENABLED)) {
+ tcm.invalidateTextClassifiers();
+ }
}
}
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index c571737cec8f..7cec440dd80b 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3473,18 +3473,10 @@ public class RemoteViews implements Parcelable, Filter {
return applyAsync(context, parent, executor, listener, null);
}
- private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) {
- CancellationSignal cancelSignal = new CancellationSignal();
- cancelSignal.setOnCancelListener(task);
-
- task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
- return cancelSignal;
- }
-
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent,
Executor executor, OnViewAppliedListener listener, OnClickHandler handler) {
- return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor);
+ return getAsyncApplyTask(context, parent, listener, handler).startTaskOnExecutor(executor);
}
private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
@@ -3495,6 +3487,7 @@ public class RemoteViews implements Parcelable, Filter {
private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
implements CancellationSignal.OnCancelListener {
+ final CancellationSignal mCancelSignal = new CancellationSignal();
final RemoteViews mRV;
final ViewGroup mParent;
final Context mContext;
@@ -3545,6 +3538,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
protected void onPostExecute(ViewTree viewTree) {
+ mCancelSignal.setOnCancelListener(null);
if (mError == null) {
if (mListener != null) {
mListener.onViewInflated(viewTree.mRoot);
@@ -3581,6 +3575,13 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void onCancel() {
cancel(true);
+ mCancelSignal.setOnCancelListener(null);
+ }
+
+ private CancellationSignal startTaskOnExecutor(Executor executor) {
+ mCancelSignal.setOnCancelListener(this);
+ executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
+ return mCancelSignal;
}
}
@@ -3646,8 +3647,8 @@ public class RemoteViews implements Parcelable, Filter {
}
}
- return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
- context, listener, handler, v), executor);
+ return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
+ context, listener, handler, v).startTaskOnExecutor(executor);
}
private void performApply(View v, ViewGroup parent, OnClickHandler handler) {
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 0b15cd06a7ea..3fdedc88fe53 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -17,6 +17,7 @@
package com.android.internal.accessibility;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static com.android.internal.util.ArrayUtils.convertToLongArray;
@@ -34,6 +35,7 @@ import android.media.AudioAttributes;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Handler;
import android.os.UserHandle;
import android.os.Vibrator;
@@ -52,11 +54,12 @@ import com.android.internal.R;
import com.android.internal.util.function.pooled.PooledLambda;
import java.util.Collections;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
- * Class to help manage the accessibility shortcut
+ * Class to help manage the accessibility shortcut key
*/
public class AccessibilityShortcutController {
private static final String TAG = "AccessibilityShortcutController";
@@ -66,6 +69,8 @@ public class AccessibilityShortcutController {
new ComponentName("com.android.server.accessibility", "ColorInversion");
public static final ComponentName DALTONIZER_COMPONENT_NAME =
new ComponentName("com.android.server.accessibility", "Daltonizer");
+ public static final String MAGNIFICATION_CONTROLLER_NAME =
+ "com.android.server.accessibility.MagnificationController";
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -84,26 +89,6 @@ public class AccessibilityShortcutController {
public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider();
/**
- * Get the component name string for the service or feature currently assigned to the
- * accessiblity shortcut
- *
- * @param context A valid context
- * @param userId The user ID of interest
- * @return The flattened component name string of the service selected by the user, or the
- * string for the default service if the user has not made a selection
- */
- public static String getTargetServiceComponentNameString(
- Context context, int userId) {
- final String currentShortcutServiceId = Settings.Secure.getStringForUser(
- context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
- userId);
- if (currentShortcutServiceId != null) {
- return currentShortcutServiceId;
- }
- return context.getString(R.string.config_defaultAccessibilityService);
- }
-
- /**
* @return An immutable map from dummy component names to feature info for toggling a framework
* feature
*/
@@ -163,7 +148,7 @@ public class AccessibilityShortcutController {
/**
* Check if the shortcut is available.
*
- * @param onLockScreen Whether or not the phone is currently locked.
+ * @param phoneLocked Whether or not the phone is currently locked.
*
* @return {@code true} if the shortcut is available
*/
@@ -172,8 +157,7 @@ public class AccessibilityShortcutController {
}
public void onSettingsChanged() {
- final boolean haveValidService =
- !TextUtils.isEmpty(getTargetServiceComponentNameString(mContext, mUserId));
+ final boolean hasShortcutTarget = hasShortcutTarget();
final ContentResolver cr = mContext.getContentResolver();
final boolean enabled = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
@@ -183,7 +167,7 @@ public class AccessibilityShortcutController {
mEnabledOnLockScreen = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
dialogAlreadyShown, mUserId) == 1;
- mIsShortcutEnabled = enabled && haveValidService;
+ mIsShortcutEnabled = enabled && hasShortcutTarget;
}
/**
@@ -205,7 +189,6 @@ public class AccessibilityShortcutController {
vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES);
}
-
if (dialogAlreadyShown == 0) {
// The first time, we show a warning rather than toggle the service to give the user a
// chance to turn off this feature before stuff gets enabled.
@@ -229,32 +212,44 @@ public class AccessibilityShortcutController {
mAlertDialog.dismiss();
mAlertDialog = null;
}
-
- // Show a toast alerting the user to what's happening
- final String serviceName = getShortcutFeatureDescription(false /* no summary */);
- if (serviceName == null) {
- Slog.e(TAG, "Accessibility shortcut set to invalid service");
- return;
- }
- // For accessibility services, show a toast explaining what we're doing.
- final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
- if (serviceInfo != null) {
- String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
- ? R.string.accessibility_shortcut_disabling_service
- : R.string.accessibility_shortcut_enabling_service);
- String toastMessage = String.format(toastMessageFormatString, serviceName);
- Toast warningToast = mFrameworkObjectProvider.makeToastFromText(
- mContext, toastMessage, Toast.LENGTH_LONG);
- warningToast.getWindowParams().privateFlags |=
- WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
- warningToast.show();
- }
-
+ showToast();
mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext)
.performAccessibilityShortcut();
}
}
+ /**
+ * Show toast if current assigned shortcut target is an accessibility service and its target
+ * sdk version is less than or equal to Q, or greater than Q and does not request
+ * accessibility button.
+ */
+ private void showToast() {
+ final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+ if (serviceInfo == null) {
+ return;
+ }
+ final String serviceName = getShortcutFeatureDescription(/* no summary */ false);
+ if (serviceName == null) {
+ return;
+ }
+ final boolean requestA11yButton = (serviceInfo.flags
+ & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+ if (serviceInfo.getResolveInfo().serviceInfo.applicationInfo
+ .targetSdkVersion > Build.VERSION_CODES.Q && requestA11yButton) {
+ return;
+ }
+ // For accessibility services, show a toast explaining what we're doing.
+ String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
+ ? R.string.accessibility_shortcut_disabling_service
+ : R.string.accessibility_shortcut_enabling_service);
+ String toastMessage = String.format(toastMessageFormatString, serviceName);
+ Toast warningToast = mFrameworkObjectProvider.makeToastFromText(
+ mContext, toastMessage, Toast.LENGTH_LONG);
+ warningToast.getWindowParams().privateFlags |=
+ WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ warningToast.show();
+ }
+
private AlertDialog createShortcutWarningDialog(int userId) {
final String serviceDescription = getShortcutFeatureDescription(true /* Include summary */);
@@ -288,25 +283,21 @@ public class AccessibilityShortcutController {
}
private AccessibilityServiceInfo getInfoForTargetService() {
- final String currentShortcutServiceString = getTargetServiceComponentNameString(
- mContext, UserHandle.USER_CURRENT);
- if (currentShortcutServiceString == null) {
+ final ComponentName targetComponentName = getShortcutTargetComponentName();
+ if (targetComponentName == null) {
return null;
}
AccessibilityManager accessibilityManager =
mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
return accessibilityManager.getInstalledServiceInfoWithComponentName(
- ComponentName.unflattenFromString(currentShortcutServiceString));
+ targetComponentName);
}
private String getShortcutFeatureDescription(boolean includeSummary) {
- final String currentShortcutServiceString = getTargetServiceComponentNameString(
- mContext, UserHandle.USER_CURRENT);
- if (currentShortcutServiceString == null) {
+ final ComponentName targetComponentName = getShortcutTargetComponentName();
+ if (targetComponentName == null) {
return null;
}
- final ComponentName targetComponentName =
- ComponentName.unflattenFromString(currentShortcutServiceString);
final ToggleableFrameworkFeatureInfo frameworkFeatureInfo =
getFrameworkShortcutFeaturesMap().get(targetComponentName);
if (frameworkFeatureInfo != null) {
@@ -372,6 +363,36 @@ public class AccessibilityShortcutController {
}
/**
+ * Returns {@code true} if any shortcut targets were assigned to accessibility shortcut key.
+ */
+ private boolean hasShortcutTarget() {
+ // AccessibilityShortcutController is initialized earlier than AccessibilityManagerService.
+ // AccessibilityManager#getAccessibilityShortcutTargets may not return correct shortcut
+ // targets during boot. Needs to read settings directly here.
+ String shortcutTargets = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, mUserId);
+ if (TextUtils.isEmpty(shortcutTargets)) {
+ shortcutTargets = mContext.getString(R.string.config_defaultAccessibilityService);
+ }
+ return !TextUtils.isEmpty(shortcutTargets);
+ }
+
+ /**
+ * Gets the component name of the shortcut target.
+ *
+ * @return The component name, or null if it's assigned by multiple targets.
+ */
+ private ComponentName getShortcutTargetComponentName() {
+ final List<String> shortcutTargets = mFrameworkObjectProvider
+ .getAccessibilityManagerInstance(mContext)
+ .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY);
+ if (shortcutTargets.size() != 1) {
+ return null;
+ }
+ return ComponentName.unflattenFromString(shortcutTargets.get(0));
+ }
+
+ /**
* Class to wrap TextToSpeech for shortcut dialog spoken feedback.
*/
private class TtsPrompt implements TextToSpeech.OnInitListener {
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
new file mode 100644
index 000000000000..2fd5bfd71656
--- /dev/null
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.app;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.os.UserHandle;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.PagerAdapter;
+
+import com.android.internal.util.Preconditions;
+import com.android.internal.widget.ViewPager;
+
+/**
+ * Skeletal {@link PagerAdapter} implementation of a work or personal profile page for
+ * intent resolution (including share sheet).
+ */
+public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
+
+ static final int PROFILE_PERSONAL = 0;
+ static final int PROFILE_WORK = 1;
+ @IntDef({PROFILE_PERSONAL, PROFILE_WORK})
+ @interface Profile {}
+
+ private final Context mContext;
+ private int mCurrentPage;
+
+ AbstractMultiProfilePagerAdapter(Context context, int currentPage) {
+ mContext = Preconditions.checkNotNull(context);
+ mCurrentPage = currentPage;
+ }
+
+ Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Sets this instance of this class as {@link ViewPager}'s {@link PagerAdapter} and sets
+ * an {@link ViewPager.OnPageChangeListener} where it keeps track of the currently displayed
+ * page and rebuilds the list.
+ */
+ void setupViewPager(ViewPager viewPager) {
+ viewPager.setCurrentItem(mCurrentPage);
+ viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ mCurrentPage = position;
+ getCurrentListAdapter().rebuildList();
+ }
+ });
+ viewPager.setAdapter(this);
+ }
+
+ @Override
+ public ViewGroup instantiateItem(ViewGroup container, int position) {
+ final ProfileDescriptor profileDescriptor = getItem(position);
+ setupListAdapter(position);
+ container.addView(profileDescriptor.rootView);
+ return profileDescriptor.rootView;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object view) {
+ container.removeView((View) view);
+ }
+
+ @Override
+ public int getCount() {
+ return getItemCount();
+ }
+
+ protected int getCurrentPage() {
+ return mCurrentPage;
+ }
+
+ UserHandle getCurrentUserHandle() {
+ return getCurrentListAdapter().mResolverListController.getUserHandle();
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return null;
+ }
+
+ /**
+ * Returns the {@link ProfileDescriptor} relevant to the given <code>pageIndex</code>.
+ * <ul>
+ * <li>For a device with only one user, <code>pageIndex</code> value of
+ * <code>0</code> would return the personal profile {@link ProfileDescriptor}.</li>
+ * <li>For a device with a work profile, <code>pageIndex</code> value of <code>0</code> would
+ * return the personal profile {@link ProfileDescriptor}, and <code>pageIndex</code> value of
+ * <code>1</code> would return the work profile {@link ProfileDescriptor}.</li>
+ * </ul>
+ */
+ abstract ProfileDescriptor getItem(int pageIndex);
+
+ /**
+ * Returns the number of {@link ProfileDescriptor} objects.
+ * <p>For a normal consumer device with only one user returns <code>1</code>.
+ * <p>For a device with a work profile returns <code>2</code>.
+ */
+ abstract int getItemCount();
+
+ /**
+ * Responsible for assigning an adapter to the list view for the relevant page, specified by
+ * <code>pageIndex</code>, and other list view-related initialization procedures.
+ */
+ abstract void setupListAdapter(int pageIndex);
+
+ /**
+ * Returns the adapter of the list view for the relevant page specified by
+ * <code>pageIndex</code>.
+ * <p>This method is meant to be implemented with an implementation-specific return type
+ * depending on the adapter type.
+ */
+ abstract Object getAdapterForIndex(int pageIndex);
+
+ @VisibleForTesting
+ public abstract ResolverListAdapter getCurrentListAdapter();
+
+ abstract Object getCurrentRootAdapter();
+
+ abstract ViewGroup getCurrentAdapterView();
+
+ protected class ProfileDescriptor {
+ final ViewGroup rootView;
+ ProfileDescriptor(ViewGroup rootView) {
+ this.rootView = rootView;
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 183e9a6faf09..1af39265dbcb 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -98,6 +98,7 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.WindowInsets;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
@@ -173,7 +174,6 @@ public class ChooserActivity extends ResolverActivity implements
@VisibleForTesting
public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;
- private static final int SINGLE_CELL_SPAN_SIZE = 1;
private boolean mIsAppPredictorComponentAvailable;
private AppPredictor mAppPredictor;
@@ -229,9 +229,6 @@ public class ChooserActivity extends ResolverActivity implements
private long mQueriedTargetServicesTimeMs;
private long mQueriedSharingShortcutsTimeMs;
- private RecyclerView mRecyclerView;
- private ChooserListAdapter mChooserListAdapter;
- private ChooserGridAdapter mChooserGridAdapter;
private int mChooserRowServiceSpacing;
private int mCurrAvailableWidth = 0;
@@ -265,6 +262,9 @@ public class ChooserActivity extends ResolverActivity implements
private ContentPreviewCoordinator mPreviewCoord;
+ @VisibleForTesting
+ protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter;
+
private class ContentPreviewCoordinator {
private static final int IMAGE_FADE_IN_MILLIS = 150;
private static final int IMAGE_LOAD_TIMEOUT = 1;
@@ -362,8 +362,8 @@ public class ChooserActivity extends ResolverActivity implements
Log.i(TAG, "Hiding image preview area. Timed out waiting for preview to load"
+ " within " + mImageLoadTimeoutMillis + "ms.");
collapseParentView();
- if (mChooserGridAdapter != null) {
- mChooserGridAdapter.hideContentPreview();
+ if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) {
+ mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().hideContentPreview();
}
mHideParentOnFail = false;
}
@@ -431,13 +431,14 @@ public class ChooserActivity extends ResolverActivity implements
logDirectShareTargetReceived(
MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
sendVoiceChoicesIfNeeded();
- mChooserListAdapter.completeServiceTargetLoading();
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+ .completeServiceTargetLoading();
}
}
@Override
public void handleMessage(Message msg) {
- if (mChooserListAdapter == null || isDestroyed()) {
+ if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter() == null || isDestroyed()) {
return;
}
@@ -452,8 +453,10 @@ public class ChooserActivity extends ResolverActivity implements
break;
}
if (sri.resultTargets != null) {
- mChooserListAdapter.addServiceResults(sri.originalTarget,
- sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET);
+ // TODO(arangelov): Instead of using getCurrentListAdapter(), pass the
+ // profileId as part of the message.
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+ sri.originalTarget, sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET);
}
unbindService(sri.connection);
sri.connection.destroy();
@@ -476,15 +479,15 @@ public class ChooserActivity extends ResolverActivity implements
Log.d(TAG, "LIST_VIEW_UPDATE_MESSAGE; ");
}
- mChooserListAdapter.refreshListView();
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().refreshListView();
break;
case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT");
final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj;
if (resultInfo.resultTargets != null) {
- mChooserListAdapter.addServiceResults(resultInfo.originalTarget,
- resultInfo.resultTargets, msg.arg1);
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+ resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1);
}
break;
@@ -504,6 +507,7 @@ public class ChooserActivity extends ResolverActivity implements
protected void onCreate(Bundle savedInstanceState) {
final long intentReceivedTime = System.currentTimeMillis();
// This is the only place this value is being set. Effectively final.
+ //TODO(arangelov) - should there be a mIsAppPredictorComponentAvailable flag for work tab?
mIsAppPredictorComponentAvailable = isAppPredictionServiceAvailable();
mIsSuccessfullySelected = false;
@@ -638,19 +642,24 @@ public class ChooserActivity extends ResolverActivity implements
if (appPredictor != null) {
mDirectShareAppTargetCache = new HashMap<>();
mAppPredictorCallback = resultList -> {
+ //TODO(arangelov) Take care of edge case when callback called after swiping tabs
if (isFinishing() || isDestroyed()) {
return;
}
- if (mChooserListAdapter.getCount() == 0) {
+ if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) {
return;
}
if (resultList.isEmpty()) {
// APS may be disabled, so try querying targets ourselves.
- queryDirectShareTargets(mChooserListAdapter, true);
+ //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents.
+ // Investigate implications for work tab.
+ queryDirectShareTargets(
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter(), true);
return;
}
final List<DisplayResolveInfo> driList =
- getDisplayResolveInfos(mChooserListAdapter);
+ getDisplayResolveInfos(
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter());
final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
new ArrayList<>();
for (AppTarget appTarget : resultList) {
@@ -684,21 +693,22 @@ public class ChooserActivity extends ResolverActivity implements
final float chooserHeaderScrollElevation =
getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
- mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
- public void onScrollStateChanged(RecyclerView view, int scrollState) {
- }
-
- public void onScrolled(RecyclerView view, int dx, int dy) {
- if (view.getChildCount() > 0) {
- View child = view.getLayoutManager().findViewByPosition(0);
- if (child == null || child.getTop() < 0) {
- chooserHeader.setElevation(chooserHeaderScrollElevation);
- return;
+ mChooserMultiProfilePagerAdapter.getCurrentAdapterView().addOnScrollListener(
+ new RecyclerView.OnScrollListener() {
+ public void onScrollStateChanged(RecyclerView view, int scrollState) {
}
- }
- chooserHeader.setElevation(defaultElevation);
- }
+ public void onScrolled(RecyclerView view, int dx, int dy) {
+ if (view.getChildCount() > 0) {
+ View child = view.getLayoutManager().findViewByPosition(0);
+ if (child == null || child.getTop() < 0) {
+ chooserHeader.setElevation(chooserHeaderScrollElevation);
+ return;
+ }
+ }
+
+ chooserHeader.setElevation(defaultElevation);
+ }
});
mResolverDrawerLayout.setOnCollapsedChangedListener(
@@ -738,6 +748,71 @@ public class ChooserActivity extends ResolverActivity implements
return context.getSharedPreferences(prefsFile, MODE_PRIVATE);
}
+ @Override
+ protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
+ mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForTwoProfiles(
+ initialIntents, rList, filterLastUsed);
+ } else {
+ mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForOneProfile(
+ initialIntents, rList, filterLastUsed);
+ }
+ return mChooserMultiProfilePagerAdapter;
+ }
+
+ private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForOneProfile(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ ChooserGridAdapter adapter = createChooserGridAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ UserHandle.of(UserHandle.myUserId()));
+ return new ChooserMultiProfilePagerAdapter(
+ /* context */ this,
+ adapter);
+ }
+
+ private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ ChooserGridAdapter personalAdapter = createChooserGridAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getPersonalProfileUserHandle());
+ ChooserGridAdapter workAdapter = createChooserGridAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getWorkProfileUserHandle());
+ return new ChooserMultiProfilePagerAdapter(
+ /* context */ this,
+ personalAdapter,
+ workAdapter,
+ /* defaultProfile */ getCurrentProfile());
+ }
+
+ @Override
+ protected boolean postRebuildList(boolean rebuildCompleted) {
+ mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().maybeLogActionShareWithPreview();
+ return postRebuildListInternal(rebuildCompleted);
+ }
+
/**
* Returns true if app prediction service is defined and the component exists on device.
*/
@@ -776,7 +851,7 @@ public class ChooserActivity extends ResolverActivity implements
* set up)
*/
protected boolean isWorkProfile() {
- return ((UserManager) getSystemService(Context.USER_SERVICE))
+ return getSystemService(UserManager.class)
.getUserInfo(UserHandle.myUserId()).isManagedProfile();
}
@@ -785,7 +860,9 @@ public class ChooserActivity extends ResolverActivity implements
return new PackageMonitor() {
@Override
public void onSomePackagesChanged() {
- mAdapter.handlePackagesChanged();
+ // TODO(arangelov): Dispatch this to all adapters when we have the helper methods
+ // in a follow-up CL
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
updateProfileViewButton();
}
};
@@ -1239,36 +1316,14 @@ public class ChooserActivity extends ResolverActivity implements
}
@Override
- public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) {
- mRecyclerView = findViewById(R.id.resolver_list);
- if (!isVisible) {
- mRecyclerView.setVisibility(View.GONE);
- return;
- }
- mRecyclerView.setVisibility(View.VISIBLE);
+ public void onPrepareAdapterView(ResolverListAdapter adapter) {
+ mChooserMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE);
if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) {
- mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets),
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+ /* origTarget */ null,
+ Lists.newArrayList(mCallerChooserTargets),
TARGET_TYPE_DEFAULT);
}
- mChooserGridAdapter = new ChooserGridAdapter(mChooserListAdapter);
- GridLayoutManager glm = (GridLayoutManager) mRecyclerView.getLayoutManager();
- glm.setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow());
- glm.setSpanSizeLookup(
- new GridLayoutManager.SpanSizeLookup() {
- @Override
- public int getSpanSize(int position) {
- return mChooserGridAdapter.getItemViewType(position)
- == ChooserGridAdapter.VIEW_TYPE_NORMAL
- ? SINGLE_CELL_SPAN_SIZE
- : glm.getSpanCount();
- }
- });
- }
-
- @Override
- protected boolean postRebuildList(boolean rebuildCompleted) {
- mChooserListAdapter = (ChooserListAdapter) mAdapter;
- return postRebuildListInternal(rebuildCompleted);
}
@Override
@@ -1348,7 +1403,10 @@ public class ChooserActivity extends ResolverActivity implements
@Override
public void startSelected(int which, boolean always, boolean filtered) {
- TargetInfo targetInfo = mChooserListAdapter.targetInfoForPosition(which, filtered);
+ ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ TargetInfo targetInfo = currentListAdapter
+ .targetInfoForPosition(which, filtered);
if (targetInfo != null && targetInfo instanceof NotSelectableTargetInfo) {
return;
}
@@ -1356,7 +1414,7 @@ public class ChooserActivity extends ResolverActivity implements
final long selectionCost = System.currentTimeMillis() - mChooserShownTime;
super.startSelected(which, always, filtered);
- if (mChooserListAdapter.getCount() > 0) {
+ if (currentListAdapter.getCount() > 0) {
// Log the index of which type of target the user picked.
// Lower values mean the ranking was better.
int cat = 0;
@@ -1364,13 +1422,12 @@ public class ChooserActivity extends ResolverActivity implements
int directTargetAlsoRanked = -1;
int numCallerProvided = 0;
HashedStringCache.HashResult directTargetHashed = null;
- switch (mChooserListAdapter.getPositionTargetType(which)) {
+ switch (currentListAdapter.getPositionTargetType(which)) {
case ChooserListAdapter.TARGET_SERVICE:
cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET;
// Log the package name + target name to answer the question if most users
// share to mostly the same person or to a bunch of different people.
- ChooserTarget target =
- mChooserListAdapter.getChooserTargetForValue(value);
+ ChooserTarget target = currentListAdapter.getChooserTargetForValue(value);
directTargetHashed = HashedStringCache.getInstance().hashString(
this,
TAG,
@@ -1386,8 +1443,8 @@ public class ChooserActivity extends ResolverActivity implements
case ChooserListAdapter.TARGET_CALLER:
case ChooserListAdapter.TARGET_STANDARD:
cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
- value -= mChooserListAdapter.getSelectableServiceTargetCount();
- numCallerProvided = mChooserListAdapter.getCallerTargetCount();
+ value -= currentListAdapter.getSelectableServiceTargetCount();
+ numCallerProvided = currentListAdapter.getCallerTargetCount();
break;
case ChooserListAdapter.TARGET_STANDARD_AZ:
// A-Z targets are unranked standard targets; we use -1 to mark that they
@@ -1429,11 +1486,13 @@ public class ChooserActivity extends ResolverActivity implements
private int getRankedPosition(SelectableTargetInfo targetInfo) {
String targetPackageName =
targetInfo.getChooserTarget().getComponentName().getPackageName();
- int maxRankedResults = Math.min(mChooserListAdapter.mDisplayList.size(),
- MAX_LOG_RANK_POSITION);
+ ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ int maxRankedResults = Math.min(currentListAdapter.mDisplayList.size(),
+ MAX_LOG_RANK_POSITION);
for (int i = 0; i < maxRankedResults; i++) {
- if (mChooserListAdapter.mDisplayList.get(i)
+ if (currentListAdapter.mDisplayList.get(i)
.getResolveInfo().activityInfo.packageName.equals(targetPackageName)) {
return i;
}
@@ -1577,6 +1636,7 @@ public class ChooserActivity extends ResolverActivity implements
}
}
// Default to just querying ShortcutManager if AppPredictor not present.
+ //TODO(arangelov) we're using mIntents here, investicate possible implications on work tab
final IntentFilter filter = getTargetIntentFilter();
if (filter == null) {
return;
@@ -1584,6 +1644,7 @@ public class ChooserActivity extends ResolverActivity implements
final List<DisplayResolveInfo> driList = getDisplayResolveInfos(adapter);
AsyncTask.execute(() -> {
+ //TODO(arangelov) use the selected probile tab's ShortcutManager
ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE);
List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter);
sendShareShortcutInfoList(resultList, driList, null);
@@ -1779,9 +1840,11 @@ public class ChooserActivity extends ResolverActivity implements
final ResolveInfo ri = info.getResolveInfo();
Intent targetIntent = getTargetIntent();
if (ri != null && ri.activityInfo != null && targetIntent != null) {
- if (mAdapter != null) {
- mAdapter.updateModel(info.getResolvedComponentName());
- mAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(),
+ ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ if (currentListAdapter != null) {
+ currentListAdapter.updateModel(info.getResolvedComponentName());
+ currentListAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(),
targetIntent.getAction());
}
if (DEBUG) {
@@ -1956,8 +2019,9 @@ public class ChooserActivity extends ResolverActivity implements
Intent targetIntent,
String referrerPackageName,
int launchedFromUid,
+ UserHandle userId,
AbstractResolverComparator resolverComparator) {
- super(context, pm, targetIntent, referrerPackageName, launchedFromUid,
+ super(context, pm, targetIntent, referrerPackageName, launchedFromUid, userId,
resolverComparator);
}
@@ -1980,17 +2044,18 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- @Override
- public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
- Intent[] initialIntents, List<ResolveInfo> rList,
- boolean filterLastUsed, boolean useLayoutForBrowsables) {
- return new ChooserListAdapter(context, payloadIntents,
- initialIntents, rList, filterLastUsed, createListController(),
- useLayoutForBrowsables, this, this);
+ @VisibleForTesting
+ public ChooserGridAdapter createChooserGridAdapter(Context context,
+ List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) {
+ return new ChooserGridAdapter(
+ new ChooserListAdapter(context, payloadIntents, initialIntents, rList,
+ filterLastUsed, createListController(userHandle), useLayoutForBrowsables,
+ this, this));
}
@VisibleForTesting
- protected ResolverListController createListController() {
+ protected ResolverListController createListController(UserHandle userHandle) {
AppPredictor appPredictor = getAppPredictorForShareActivitesIfEnabled();
AbstractResolverComparator resolverComparator;
if (appPredictor != null) {
@@ -2008,6 +2073,7 @@ public class ChooserActivity extends ResolverActivity implements
getTargetIntent(),
getReferrerPackageName(),
mLaunchedFromUid,
+ userHandle,
resolverComparator);
}
@@ -2041,8 +2107,8 @@ public class ChooserActivity extends ResolverActivity implements
}
private void handleScroll(View view, int x, int y, int oldx, int oldy) {
- if (mChooserGridAdapter != null) {
- mChooserGridAdapter.handleScroll(view, y, oldy);
+ if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) {
+ mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().handleScroll(view, y, oldy);
}
}
@@ -2053,37 +2119,42 @@ public class ChooserActivity extends ResolverActivity implements
*/
private void handleLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- if (mChooserGridAdapter == null || mRecyclerView == null) {
+ if (mChooserMultiProfilePagerAdapter == null) {
+ return;
+ }
+ RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getCurrentAdapterView();
+ ChooserGridAdapter gridAdapter = mChooserMultiProfilePagerAdapter.getCurrentRootAdapter();
+ if (gridAdapter == null || recyclerView == null) {
return;
}
final int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight();
- if (mChooserGridAdapter.consumeLayoutRequest()
- || mChooserGridAdapter.calculateChooserTargetWidth(availableWidth)
- || mRecyclerView.getAdapter() == null
+ if (gridAdapter.consumeLayoutRequest()
+ || gridAdapter.calculateChooserTargetWidth(availableWidth)
+ || recyclerView.getAdapter() == null
|| availableWidth != mCurrAvailableWidth) {
mCurrAvailableWidth = availableWidth;
- mRecyclerView.setAdapter(mChooserGridAdapter);
- ((GridLayoutManager) mRecyclerView.getLayoutManager())
- .setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow());
+ recyclerView.setAdapter(gridAdapter);
+ ((GridLayoutManager) recyclerView.getLayoutManager())
+ .setSpanCount(gridAdapter.getMaxTargetsPerRow());
getMainThreadHandler().post(() -> {
- if (mResolverDrawerLayout == null || mChooserGridAdapter == null) {
+ if (mResolverDrawerLayout == null || gridAdapter == null) {
return;
}
final int bottomInset = mSystemWindowInsets != null
? mSystemWindowInsets.bottom : 0;
int offset = bottomInset;
- int rowsToShow = mChooserGridAdapter.getContentPreviewRowCount()
- + mChooserGridAdapter.getProfileRowCount()
- + mChooserGridAdapter.getServiceTargetRowCount()
- + mChooserGridAdapter.getCallerAndRankedTargetRowCount();
+ int rowsToShow = gridAdapter.getContentPreviewRowCount()
+ + gridAdapter.getProfileRowCount()
+ + gridAdapter.getServiceTargetRowCount()
+ + gridAdapter.getCallerAndRankedTargetRowCount();
// then this is most likely not a SEND_* action, so check
// the app target count
if (rowsToShow == 0) {
- rowsToShow = mChooserGridAdapter.getRowCount();
+ rowsToShow = gridAdapter.getRowCount();
}
// still zero? then use a default height and leave, which
@@ -2097,9 +2168,9 @@ public class ChooserActivity extends ResolverActivity implements
int directShareHeight = 0;
rowsToShow = Math.min(4, rowsToShow);
- for (int i = 0, childCount = mRecyclerView.getChildCount();
+ for (int i = 0, childCount = recyclerView.getChildCount();
i < childCount && rowsToShow > 0; i++) {
- View child = mRecyclerView.getChildAt(i);
+ View child = recyclerView.getChildAt(i);
if (((GridLayoutManager.LayoutParams)
child.getLayoutParams()).getSpanIndex() != 0) {
continue;
@@ -2107,9 +2178,9 @@ public class ChooserActivity extends ResolverActivity implements
int height = child.getHeight();
offset += height;
- if (mChooserGridAdapter.getTargetType(
- mRecyclerView.getChildAdapterPosition(child))
- == mChooserListAdapter.TARGET_SERVICE) {
+ if (gridAdapter.getTargetType(
+ recyclerView.getChildAdapterPosition(child))
+ == ChooserListAdapter.TARGET_SERVICE) {
directShareHeight = height;
}
rowsToShow--;
@@ -2145,13 +2216,13 @@ public class ChooserActivity extends ResolverActivity implements
@Override // ResolverListCommunicator
public void onHandlePackagesChanged() {
mServicesRequested.clear();
- mAdapter.notifyDataSetChanged();
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().notifyDataSetChanged();
super.onHandlePackagesChanged();
}
@Override // SelectableTargetInfoCommunicator
public ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo info) {
- return mChooserListAdapter.makePresentationGetter(info);
+ return mChooserMultiProfilePagerAdapter.getCurrentListAdapter().makePresentationGetter(info);
}
@Override // SelectableTargetInfoCommunicator
@@ -2161,9 +2232,9 @@ public class ChooserActivity extends ResolverActivity implements
@Override // ChooserListCommunicator
public int getMaxRankedTargets() {
- return mChooserGridAdapter == null
+ return mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() == null
? ChooserGridAdapter.MAX_TARGETS_PER_ROW_PORTRAIT
- : mChooserGridAdapter.getMaxTargetsPerRow();
+ : mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().getMaxTargetsPerRow();
}
@Override // ChooserListCommunicator
@@ -2174,19 +2245,21 @@ public class ChooserActivity extends ResolverActivity implements
@Override
public void onListRebuilt() {
- if (mChooserListAdapter.mDisplayList == null
- || mChooserListAdapter.mDisplayList.isEmpty()) {
- mChooserListAdapter.notifyDataSetChanged();
+ final ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ if (currentListAdapter.mDisplayList == null
+ || currentListAdapter.mDisplayList.isEmpty()) {
+ currentListAdapter.notifyDataSetChanged();
} else {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
- mChooserListAdapter.updateAlphabeticalList();
+ currentListAdapter.updateAlphabeticalList();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
- mChooserListAdapter.notifyDataSetChanged();
+ currentListAdapter.notifyDataSetChanged();
}
}.execute();
}
@@ -2202,14 +2275,14 @@ public class ChooserActivity extends ResolverActivity implements
Log.d(TAG, "querying direct share targets from ShortcutManager");
}
- queryDirectShareTargets(mChooserListAdapter, false);
+ queryDirectShareTargets(currentListAdapter, false);
}
if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) {
if (DEBUG) {
Log.d(TAG, "List built querying services");
}
- queryTargetServices(mChooserListAdapter);
+ queryTargetServices(currentListAdapter);
}
}
@@ -2250,8 +2323,8 @@ public class ChooserActivity extends ResolverActivity implements
false/* always */, true/* filterd */));
itemView.setOnLongClickListener(v -> {
showTargetDetails(
- mChooserListAdapter.resolveInfoForPosition(
- mListPosition, true/* filtered */));
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(mListPosition, /* filtered */ true));
return true;
});
}
@@ -2259,6 +2332,29 @@ public class ChooserActivity extends ResolverActivity implements
}
/**
+ * Intentionally override the {@link ResolverActivity} implementation as we only need that
+ * implementation for the intent resolver case.
+ */
+ @Override
+ protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ return insets.consumeSystemWindowInsets();
+ }
+
+ /**
+ * Intentionally override the {@link ResolverActivity} implementation as we only need that
+ * implementation for the intent resolver case.
+ */
+ @Override
+ public void onButtonClick(View v) {}
+
+ /**
+ * Intentionally override the {@link ResolverActivity} implementation as we only need that
+ * implementation for the intent resolver case.
+ */
+ @Override
+ protected void resetButtonBar() {}
+
+ /**
* Adapter for all types of items and targets in ShareSheet.
* Note that ranked sections like Direct Share - while appearing grid-like - are handled on the
* row level by this adapter but not on the item level. Individual targets within the row are
@@ -2329,12 +2425,11 @@ public class ChooserActivity extends ResolverActivity implements
return false;
}
- private int getMaxTargetsPerRow() {
+ int getMaxTargetsPerRow() {
int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
if (shouldDisplayLandscape(getResources().getConfiguration().orientation)) {
maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
}
-
return maxTargets;
}
@@ -2477,10 +2572,6 @@ public class ChooserActivity extends ResolverActivity implements
private ViewGroup createContentPreviewView(ViewGroup parent) {
Intent targetIntent = getTargetIntent();
int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
-
- getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
- .setSubtype(previewType));
-
return displayContentPreview(previewType, targetIntent, mLayoutInflater, parent);
}
@@ -2667,6 +2758,7 @@ public class ChooserActivity extends ResolverActivity implements
for (int i = 0; i < columnCount; i++) {
final View v = holder.getView(i);
+
if (start + i <= end) {
holder.setViewVisibility(i, View.VISIBLE);
holder.setItemIndex(i, start + i);
@@ -2712,9 +2804,29 @@ public class ChooserActivity extends ResolverActivity implements
&& !isInMultiWindowMode();
if (mDirectShareViewHolder != null && canExpandDirectShare) {
- mDirectShareViewHolder.handleScroll(mRecyclerView, y, oldy, getMaxTargetsPerRow());
+ mDirectShareViewHolder.handleScroll(
+ mChooserMultiProfilePagerAdapter.getCurrentAdapterView(), y, oldy,
+ getMaxTargetsPerRow());
}
}
+
+ public ChooserListAdapter getListAdapter() {
+ return mChooserListAdapter;
+ }
+
+ void maybeLogActionShareWithPreview() {
+ if (getContentPreviewRowCount() == 0) {
+ return;
+ }
+ Intent targetIntent = getTargetIntent();
+ int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+ getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
+ .setSubtype(previewType));
+ }
+
+ boolean shouldCellSpan(int position) {
+ return getItemViewType(position) == VIEW_TYPE_NORMAL;
+ }
}
/**
@@ -2898,7 +3010,8 @@ public class ChooserActivity extends ResolverActivity implements
// only expand if we have more than maxTargetsPerRow, and delay that decision
// until they start to scroll
- if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
+ if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getSelectableServiceTargetCount() <= maxTargetsPerRow) {
mHideDirectShareExpansion = true;
return;
}
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
new file mode 100644
index 000000000000..aa8ab2865d92
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.GridLayoutManager;
+import com.android.internal.widget.PagerAdapter;
+import com.android.internal.widget.RecyclerView;
+
+/**
+ * A {@link PagerAdapter} which describes the work and personal profile share sheet screens.
+ */
+@VisibleForTesting
+public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter {
+ private static final int SINGLE_CELL_SPAN_SIZE = 1;
+
+ private final ChooserProfileDescriptor[] mItems;
+
+ ChooserMultiProfilePagerAdapter(Context context,
+ ChooserActivity.ChooserGridAdapter adapter) {
+ super(context, /* currentPage */ 0);
+ mItems = new ChooserProfileDescriptor[] {
+ createProfileDescriptor(adapter)
+ };
+ }
+
+ ChooserMultiProfilePagerAdapter(Context context,
+ ChooserActivity.ChooserGridAdapter personalAdapter,
+ ChooserActivity.ChooserGridAdapter workAdapter,
+ @Profile int defaultProfile) {
+ super(context, /* currentPage */ defaultProfile);
+ mItems = new ChooserProfileDescriptor[] {
+ createProfileDescriptor(personalAdapter),
+ createProfileDescriptor(workAdapter)
+ };
+ }
+
+ private ChooserProfileDescriptor createProfileDescriptor(
+ ChooserActivity.ChooserGridAdapter adapter) {
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ final ViewGroup rootView =
+ (ViewGroup) inflater.inflate(R.layout.chooser_list_per_profile, null, false);
+ return new ChooserProfileDescriptor(rootView, adapter);
+ }
+
+ RecyclerView getListViewForIndex(int index) {
+ return getItem(index).recyclerView;
+ }
+
+ @Override
+ ChooserProfileDescriptor getItem(int pageIndex) {
+ return mItems[pageIndex];
+ }
+
+ @Override
+ int getItemCount() {
+ return mItems.length;
+ }
+
+ @Override
+ ChooserActivity.ChooserGridAdapter getAdapterForIndex(int pageIndex) {
+ return mItems[pageIndex].chooserGridAdapter;
+ }
+
+ @Override
+ void setupListAdapter(int pageIndex) {
+ final RecyclerView recyclerView = getItem(pageIndex).recyclerView;
+ ChooserActivity.ChooserGridAdapter chooserGridAdapter =
+ getItem(pageIndex).chooserGridAdapter;
+ recyclerView.setAdapter(chooserGridAdapter);
+ GridLayoutManager glm = (GridLayoutManager) recyclerView.getLayoutManager();
+ glm.setSpanCount(chooserGridAdapter.getMaxTargetsPerRow());
+ glm.setSpanSizeLookup(
+ new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ return chooserGridAdapter.shouldCellSpan(position)
+ ? SINGLE_CELL_SPAN_SIZE
+ : glm.getSpanCount();
+ }
+ });
+ }
+
+ @Override
+ @VisibleForTesting
+ public ChooserListAdapter getCurrentListAdapter() {
+ return getAdapterForIndex(getCurrentPage()).getListAdapter();
+ }
+
+ @Override
+ ChooserActivity.ChooserGridAdapter getCurrentRootAdapter() {
+ return getAdapterForIndex(getCurrentPage());
+ }
+
+ @Override
+ RecyclerView getCurrentAdapterView() {
+ return getListViewForIndex(getCurrentPage());
+ }
+
+ class ChooserProfileDescriptor extends ProfileDescriptor {
+ private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
+ private RecyclerView recyclerView;
+ ChooserProfileDescriptor(ViewGroup rootView, ChooserActivity.ChooserGridAdapter adapter) {
+ super(rootView);
+ chooserGridAdapter = adapter;
+ recyclerView = rootView.findViewById(R.id.resolver_list);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9e38f3847f65..9cf5e9f47e7f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -18,11 +18,15 @@ package com.android.internal.app;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
+import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_WORK;
+
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UiThread;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.VoiceInteractor.PickOptionRequest;
@@ -32,6 +36,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.PermissionChecker;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -71,6 +76,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.Profile;
import com.android.internal.app.chooser.DisplayResolveInfo;
import com.android.internal.app.chooser.TargetInfo;
import com.android.internal.content.PackageMonitor;
@@ -98,10 +104,7 @@ public class ResolverActivity extends Activity implements
public ResolverActivity() {
}
- @UnsupportedAppUsage
- protected ResolverListAdapter mAdapter;
private boolean mSafeForwardingMode;
- private AbsListView mAdapterView;
private Button mAlwaysButton;
private Button mOnceButton;
protected View mProfileView;
@@ -142,8 +145,16 @@ public class ResolverActivity extends Activity implements
private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
private static final String OPEN_LINKS_COMPONENT_KEY = "app_link_state";
+ /**
+ * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
+ */
+ static final boolean ENABLE_TABBED_VIEW = false;
+
private final PackageMonitor mPackageMonitor = createPackageMonitor();
+ @VisibleForTesting
+ protected AbstractMultiProfilePagerAdapter mMultiProfilePagerAdapter;
+
// Intent extra for connected audio devices
public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device";
@@ -229,7 +240,7 @@ public class ResolverActivity extends Activity implements
return new PackageMonitor() {
@Override
public void onSomePackagesChanged() {
- mAdapter.handlePackagesChanged();
+ mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
updateProfileViewButton();
}
@@ -324,15 +335,13 @@ public class ResolverActivity extends Activity implements
mSupportsAlwaysUseOption = supportsAlwaysUseOption;
- // The last argument of createAdapter is whether to do special handling
+ // The last argument of createResolverListAdapter is whether to do special handling
// of the last used choice to highlight it in the list. We need to always
// turn this off when running under voice interaction, since it results in
// a more complicated UI that the current voice interaction flow is not able
// to handle.
boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction();
- mAdapter = createAdapter(this, mIntents, initialIntents, rList,
- filterLastUsed, mUseLayoutForBrowsables);
-
+ mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
if (configureContentView()) {
return;
}
@@ -363,15 +372,96 @@ public class ResolverActivity extends Activity implements
}
final Set<String> categories = intent.getCategories();
- MetricsLogger.action(this, mAdapter.hasFilteredItem()
+ MetricsLogger.action(this, mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem()
? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED
: MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED,
intent.getAction() + ":" + intent.getType() + ":"
+ (categories != null ? Arrays.toString(categories.toArray()) : ""));
}
+ protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ AbstractMultiProfilePagerAdapter resolverMultiProfilePagerAdapter = null;
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
+ resolverMultiProfilePagerAdapter =
+ createResolverMultiProfilePagerAdapterForTwoProfiles(
+ initialIntents, rList, filterLastUsed);
+ } else {
+ resolverMultiProfilePagerAdapter = createResolverMultiProfilePagerAdapterForOneProfile(
+ initialIntents, rList, filterLastUsed);
+ }
+ return resolverMultiProfilePagerAdapter;
+ }
+
+ private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForOneProfile(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList, boolean filterLastUsed) {
+ ResolverListAdapter adapter = createResolverListAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ UserHandle.of(UserHandle.myUserId()));
+ return new ResolverMultiProfilePagerAdapter(
+ /* context */ this,
+ adapter);
+ }
+
+ private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForTwoProfiles(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ ResolverListAdapter personalAdapter = createResolverListAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getPersonalProfileUserHandle());
+ ResolverListAdapter workAdapter = createResolverListAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getWorkProfileUserHandle());
+ return new ResolverMultiProfilePagerAdapter(
+ /* context */ this,
+ personalAdapter,
+ workAdapter,
+ /* defaultProfile */ getCurrentProfile());
+ }
+
+ protected @Profile int getCurrentProfile() {
+ return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK);
+ }
+
+ protected UserHandle getPersonalProfileUserHandle() {
+ return UserHandle.of(ActivityManager.getCurrentUser());
+ }
+ protected @Nullable UserHandle getWorkProfileUserHandle() {
+ UserManager userManager = getSystemService(UserManager.class);
+ for (final UserInfo userInfo : userManager.getProfiles(ActivityManager.getCurrentUser())) {
+ if (userInfo.isManagedProfile()) {
+ return userInfo.getUserHandle();
+ }
+ }
+ return null;
+ }
+
+ protected boolean hasWorkProfile() {
+ return getWorkProfileUserHandle() != null;
+ }
+
protected void onProfileClick(View v) {
- final DisplayResolveInfo dri = mAdapter.getOtherProfile();
+ final DisplayResolveInfo dri =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile();
if (dri == null) {
return;
}
@@ -394,11 +484,13 @@ public class ResolverActivity extends Activity implements
if (mFooterSpacer == null) {
mFooterSpacer = new Space(getApplicationContext());
} else {
- ((ListView) mAdapterView).removeFooterView(mFooterSpacer);
+ ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
+ .getCurrentAdapterView().removeFooterView(mFooterSpacer);
}
mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
mSystemWindowInsets.bottom));
- ((ListView) mAdapterView).addFooterView(mFooterSpacer);
+ ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
+ .getCurrentAdapterView().addFooterView(mFooterSpacer);
} else {
View emptyView = findViewById(R.id.empty);
if (emptyView != null) {
@@ -416,7 +508,7 @@ public class ResolverActivity extends Activity implements
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- mAdapter.handlePackagesChanged();
+ mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
if (mSystemWindowInsets != null) {
mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
@@ -431,9 +523,10 @@ public class ResolverActivity extends Activity implements
return;
}
- final Option[] options = new Option[mAdapter.getCount()];
+ int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getCount();
+ final Option[] options = new Option[count];
for (int i = 0, N = options.length; i < N; i++) {
- TargetInfo target = mAdapter.getItem(i);
+ TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter().getItem(i);
if (target == null) {
// If this occurs, a new set of targets is being loaded. Let that complete,
// and have the next call to send voice choices proceed instead.
@@ -482,8 +575,9 @@ public class ResolverActivity extends Activity implements
return;
}
- final DisplayResolveInfo dri = mAdapter.getOtherProfile();
- if (dri != null) {
+ final DisplayResolveInfo dri =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile();
+ if (dri != null && !ENABLE_TABBED_VIEW) {
mProfileView.setVisibility(View.VISIBLE);
View text = mProfileView.findViewById(R.id.profile_button);
if (!(text instanceof TextView)) {
@@ -534,7 +628,8 @@ public class ResolverActivity extends Activity implements
// While there may already be a filtered item, we can only use it in the title if the list
// is already sorted and all information relevant to it is already in the list.
- final boolean named = mAdapter.getFilteredPosition() >= 0;
+ final boolean named =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredPosition() >= 0;
if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
return getString(defaultTitleRes);
} else if (isHttpSchemeAndViewAction(intent)) {
@@ -543,12 +638,14 @@ public class ResolverActivity extends Activity implements
String dialogTitle = null;
if (named && !mUseLayoutForBrowsables) {
dialogTitle = getString(ActionTitle.BROWSABLE_APP_TITLE_RES,
- mAdapter.getFilteredItem().getDisplayLabel());
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem()
+ .getDisplayLabel());
} else if (named && mUseLayoutForBrowsables) {
dialogTitle = getString(ActionTitle.BROWSABLE_HOST_APP_TITLE_RES,
intent.getData().getHost(),
- mAdapter.getFilteredItem().getDisplayLabel());
- } else if (mAdapter.areAllTargetsBrowsers()) {
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem()
+ .getDisplayLabel());
+ } else if (mMultiProfilePagerAdapter.getCurrentListAdapter().areAllTargetsBrowsers()) {
dialogTitle = getString(ActionTitle.BROWSABLE_TITLE_RES);
} else {
dialogTitle = getString(ActionTitle.BROWSABLE_HOST_TITLE_RES,
@@ -557,7 +654,8 @@ public class ResolverActivity extends Activity implements
return dialogTitle;
} else {
return named
- ? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel())
+ ? getString(title.namedTitleRes, mMultiProfilePagerAdapter
+ .getCurrentListAdapter().getFilteredItem().getDisplayLabel())
: getString(title.titleRes);
}
}
@@ -575,7 +673,7 @@ public class ResolverActivity extends Activity implements
mPackageMonitor.register(this, getMainLooper(), false);
mRegistered = true;
}
- mAdapter.handlePackagesChanged();
+ mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
updateProfileViewButton();
}
@@ -608,8 +706,8 @@ public class ResolverActivity extends Activity implements
if (!isChangingConfigurations() && mPickOptionRequest != null) {
mPickOptionRequest.cancel();
}
- if (mAdapter != null) {
- mAdapter.onDestroy();
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter() != null) {
+ mMultiProfilePagerAdapter.getCurrentListAdapter().onDestroy();
}
}
@@ -657,8 +755,10 @@ public class ResolverActivity extends Activity implements
private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
boolean filtered) {
boolean enabled = false;
+ ResolveInfo ri = null;
if (hasValidSelection) {
- ResolveInfo ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
+ ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(checkedPos, filtered);
if (ri == null) {
Log.e(TAG, "Invalid position supplied to setAlwaysButtonEnabled");
return;
@@ -676,16 +776,36 @@ public class ResolverActivity extends Activity implements
.getString(R.string.activity_resolver_use_always));
}
}
+
+ ActivityInfo activityInfo = ri.activityInfo;
+
+ boolean hasRecordPermission =
+ PermissionChecker.checkPermissionForPreflight(
+ getApplicationContext(),
+ android.Manifest.permission.RECORD_AUDIO, -1,
+ activityInfo.applicationInfo.uid,
+ activityInfo.packageName)
+ == android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+ if (!hasRecordPermission) {
+ // OK, we know the record permission, is this a capture device
+ boolean hasAudioCapture =
+ getIntent().getBooleanExtra(
+ ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
+ enabled = !hasAudioCapture;
+ }
mAlwaysButton.setEnabled(enabled);
}
public void onButtonClick(View v) {
final int id = v.getId();
- int which = mAdapter.hasFilteredItem()
- ? mAdapter.getFilteredPosition()
- : mAdapterView.getCheckedItemPosition();
- boolean hasIndexBeenFiltered = !mAdapter.hasFilteredItem();
- ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
+ ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getCurrentListAdapter();
+ int which = currentListAdapter.hasFilteredItem()
+ ? currentListAdapter.getFilteredPosition()
+ : listView.getCheckedItemPosition();
+ boolean hasIndexBeenFiltered = !currentListAdapter.hasFilteredItem();
+ ResolveInfo ri = currentListAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
if (mUseLayoutForBrowsables
&& !ri.handleAllWebDataURI && id == R.id.button_always) {
showSettingsForSelected(ri);
@@ -716,7 +836,8 @@ public class ResolverActivity extends Activity implements
if (isFinishing()) {
return;
}
- ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
+ ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(which, hasIndexBeenFiltered);
if (mResolvingHome && hasManagedProfile() && !supportsManagedProfiles(ri)) {
Toast.makeText(this, String.format(getResources().getString(
com.android.internal.R.string.activity_resolver_work_profiles_support),
@@ -725,7 +846,8 @@ public class ResolverActivity extends Activity implements
return;
}
- TargetInfo target = mAdapter.targetInfoForPosition(which, hasIndexBeenFiltered);
+ TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .targetInfoForPosition(which, hasIndexBeenFiltered);
if (target == null) {
return;
}
@@ -740,7 +862,8 @@ public class ResolverActivity extends Activity implements
MetricsLogger.action(
this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_TAP);
}
- MetricsLogger.action(this, mAdapter.hasFilteredItem()
+ MetricsLogger.action(this,
+ mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem()
? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED
: MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED);
finish();
@@ -763,10 +886,11 @@ public class ResolverActivity extends Activity implements
}
protected void onListRebuilt() {
- int count = mAdapter.getUnfilteredCount();
- if (count == 1 && mAdapter.getOtherProfile() == null) {
+ int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount();
+ if (count == 1 && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) {
// Only one target, so we're a candidate to auto-launch!
- final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
+ final TargetInfo target =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().targetInfoForPosition(0, false);
if (shouldAutoLaunchSingleChoice(target)) {
safelyStartActivity(target);
finish();
@@ -778,8 +902,9 @@ public class ResolverActivity extends Activity implements
final ResolveInfo ri = target.getResolveInfo();
final Intent intent = target != null ? target.getResolvedIntent() : null;
- if (intent != null && (mSupportsAlwaysUseOption || mAdapter.hasFilteredItem())
- && mAdapter.mUnfilteredResolveList != null) {
+ if (intent != null && (mSupportsAlwaysUseOption
+ || mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem())
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredResolveList() != null) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
Intent filterIntent;
@@ -864,13 +989,14 @@ public class ResolverActivity extends Activity implements
}
if (filter != null) {
- final int N = mAdapter.mUnfilteredResolveList.size();
+ final int N = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getUnfilteredResolveList().size();
ComponentName[] set;
// If we don't add back in the component for forwarding the intent to a managed
// profile, the preferred activity may not be updated correctly (as the set of
// components we tell it we knew about will have changed).
final boolean needToAddBackProfileForwardingComponent =
- mAdapter.getOtherProfile() != null;
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() != null;
if (!needToAddBackProfileForwardingComponent) {
set = new ComponentName[N];
} else {
@@ -879,15 +1005,18 @@ public class ResolverActivity extends Activity implements
int bestMatch = 0;
for (int i=0; i<N; i++) {
- ResolveInfo r = mAdapter.mUnfilteredResolveList.get(i).getResolveInfoAt(0);
+ ResolveInfo r = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getUnfilteredResolveList().get(i).getResolveInfoAt(0);
set[i] = new ComponentName(r.activityInfo.packageName,
r.activityInfo.name);
if (r.match > bestMatch) bestMatch = r.match;
}
if (needToAddBackProfileForwardingComponent) {
- set[N] = mAdapter.getOtherProfile().getResolvedComponentName();
- final int otherProfileMatch = mAdapter.getOtherProfile().getResolveInfo().match;
+ set[N] = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getOtherProfile().getResolvedComponentName();
+ final int otherProfileMatch = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getOtherProfile().getResolveInfo().match;
if (otherProfileMatch > bestMatch) bestMatch = otherProfileMatch;
}
@@ -926,7 +1055,8 @@ public class ResolverActivity extends Activity implements
}
} else {
try {
- mAdapter.mResolverListController.setLastChosen(intent, filter, bestMatch);
+ mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .mResolverListController.setLastChosen(intent, filter, bestMatch);
} catch (RemoteException re) {
Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
}
@@ -964,14 +1094,15 @@ public class ResolverActivity extends Activity implements
if (mProfileSwitchMessageId != -1) {
Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
}
+ UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
if (!mSafeForwardingMode) {
- if (cti.start(this, null)) {
+ if (cti.startAsUser(this, null, currentUserHandle)) {
onActivityStarted(cti);
}
return;
}
try {
- if (cti.startAsCaller(this, null, UserHandle.USER_NULL)) {
+ if (cti.startAsCaller(this, null, currentUserHandle.getIdentifier())) {
onActivityStarted(cti);
}
} catch (RuntimeException e) {
@@ -1041,27 +1172,27 @@ public class ResolverActivity extends Activity implements
startActivity(in);
}
- public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
- Intent[] initialIntents, List<ResolveInfo> rList,
- boolean filterLastUsed, boolean useLayoutForBrowsables) {
-
+ @VisibleForTesting
+ protected ResolverListAdapter createResolverListAdapter(Context context,
+ List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) {
Intent startIntent = getIntent();
boolean isAudioCaptureDevice =
startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
-
return new ResolverListAdapter(context, payloadIntents, initialIntents, rList,
- filterLastUsed, createListController(), useLayoutForBrowsables, this,
+ filterLastUsed, createListController(userHandle), useLayoutForBrowsables, this,
isAudioCaptureDevice);
}
@VisibleForTesting
- protected ResolverListController createListController() {
+ protected ResolverListController createListController(UserHandle userHandle) {
return new ResolverListController(
this,
mPm,
getTargetIntent(),
getReferrerPackageName(),
- mLaunchedFromUid);
+ mLaunchedFromUid,
+ userHandle);
}
/**
@@ -1069,16 +1200,17 @@ public class ResolverActivity extends Activity implements
* @return <code>true</code> if the activity is finishing and creation should halt.
*/
private boolean configureContentView() {
- if (mAdapter == null) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter() == null) {
throw new IllegalStateException("mAdapter cannot be null.");
}
- boolean rebuildCompleted = mAdapter.rebuildList();
+ boolean rebuildCompleted = mMultiProfilePagerAdapter.getCurrentListAdapter().rebuildList();
if (useLayoutWithDefault()) {
mLayoutId = R.layout.resolver_list_with_default;
} else {
mLayoutId = getLayoutResource();
}
setContentView(mLayoutId);
+ mMultiProfilePagerAdapter.setupViewPager(findViewById(R.id.profile_pager));
return postRebuildList(rebuildCompleted);
}
@@ -1099,14 +1231,16 @@ public class ResolverActivity extends Activity implements
*/
final boolean postRebuildListInternal(boolean rebuildCompleted) {
- int count = mAdapter.getUnfilteredCount();
+ int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount();
// We only rebuild asynchronously when we have multiple elements to sort. In the case where
// we're already done, we can check if we should auto-launch immediately.
if (rebuildCompleted) {
- if (count == 1 && mAdapter.getOtherProfile() == null) {
+ if (count == 1
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) {
// Only one target, so we're a candidate to auto-launch!
- final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
+ final TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .targetInfoForPosition(0, false);
if (shouldAutoLaunchSingleChoice(target)) {
safelyStartActivity(target);
mPackageMonitor.unregister();
@@ -1117,37 +1251,32 @@ public class ResolverActivity extends Activity implements
}
}
- boolean isAdapterViewVisible = true;
- if (count == 0 && mAdapter.getPlaceholderCount() == 0) {
+ setupViewVisibilities(count);
+ return false;
+ }
+
+ private void setupViewVisibilities(int count) {
+ if (count == 0
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) {
final TextView emptyView = findViewById(R.id.empty);
emptyView.setVisibility(View.VISIBLE);
- isAdapterViewVisible = false;
+ findViewById(R.id.profile_pager).setVisibility(View.GONE);
+ } else {
+ onPrepareAdapterView(mMultiProfilePagerAdapter.getCurrentListAdapter());
}
-
- onPrepareAdapterView(mAdapter, isAdapterViewVisible);
- return false;
}
/**
* Prepare the scrollable view which consumes data in the list adapter.
* @param adapter The adapter used to provide data to item views.
- * @param isVisible True if the scrollable view should be visible; false, otherwise.
*/
- public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) {
- mAdapterView = findViewById(R.id.resolver_list);
- if (!isVisible) {
- mAdapterView.setVisibility(View.GONE);
- return;
- }
- mAdapterView.setVisibility(View.VISIBLE);
+ public void onPrepareAdapterView(ResolverListAdapter adapter) {
+ mMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE);
final boolean useHeader = adapter.hasFilteredItem();
- final ListView listView = mAdapterView instanceof ListView ? (ListView) mAdapterView : null;
-
- mAdapterView.setAdapter(mAdapter);
-
+ final ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
final ItemClickListener listener = new ItemClickListener();
- mAdapterView.setOnItemClickListener(listener);
- mAdapterView.setOnItemLongClickListener(listener);
+ listView.setOnItemClickListener(listener);
+ listView.setOnItemLongClickListener(listener);
if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) {
listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
@@ -1166,7 +1295,8 @@ public class ResolverActivity extends Activity implements
* Configure the area above the app selection list (title, content preview, etc).
*/
public void setHeader() {
- if (mAdapter.getCount() == 0 && mAdapter.getPlaceholderCount() == 0) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) {
final TextView titleView = findViewById(R.id.title);
if (titleView != null) {
titleView.setVisibility(View.GONE);
@@ -1187,11 +1317,11 @@ public class ResolverActivity extends Activity implements
final ImageView iconView = findViewById(R.id.icon);
if (iconView != null) {
- mAdapter.loadFilteredItemIconTaskAsync(iconView);
+ mMultiProfilePagerAdapter.getCurrentListAdapter().loadFilteredItemIconTaskAsync(iconView);
}
}
- private void resetButtonBar() {
+ protected void resetButtonBar() {
if (!mSupportsAlwaysUseOption && !mUseLayoutForBrowsables) {
return;
}
@@ -1215,24 +1345,27 @@ public class ResolverActivity extends Activity implements
}
private void resetAlwaysOrOnceButtonBar() {
- if (useLayoutWithDefault()
- && mAdapter.getFilteredPosition() != ListView.INVALID_POSITION) {
- setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
+ int filteredPosition = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getFilteredPosition();
+ if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) {
+ setAlwaysButtonEnabled(true, filteredPosition, false);
mOnceButton.setEnabled(true);
return;
}
// When the items load in, if an item was already selected, enable the buttons
- if (mAdapterView != null
- && mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
- setAlwaysButtonEnabled(true, mAdapterView.getCheckedItemPosition(), true);
+ ListView currentAdapterView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ if (currentAdapterView != null
+ && currentAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
+ setAlwaysButtonEnabled(true, currentAdapterView.getCheckedItemPosition(), true);
mOnceButton.setEnabled(true);
}
}
@Override // ResolverListCommunicator
public boolean useLayoutWithDefault() {
- return mSupportsAlwaysUseOption && mAdapter.hasFilteredItem();
+ return mSupportsAlwaysUseOption
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem();
}
/**
@@ -1256,7 +1389,7 @@ public class ResolverActivity extends Activity implements
@Override // ResolverListCommunicator
public void onHandlePackagesChanged() {
- if (mAdapter.getCount() == 0) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) {
// We no longer have any items... just finish the activity.
finish();
}
@@ -1331,11 +1464,14 @@ public class ResolverActivity extends Activity implements
return;
}
// If we're still loading, we can't yet enable the buttons.
- if (mAdapter.resolveInfoForPosition(position, true) == null) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(position, true) == null) {
return;
}
- final int checkedPos = mAdapterView.getCheckedItemPosition();
+ ListView currentAdapterView =
+ (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ final int checkedPos = currentAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (!useLayoutWithDefault()
&& (!hasValidSelection || mLastSelected != checkedPos)
@@ -1343,7 +1479,7 @@ public class ResolverActivity extends Activity implements
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
- mAdapterView.smoothScrollToPosition(checkedPos);
+ currentAdapterView.smoothScrollToPosition(checkedPos);
}
mLastSelected = checkedPos;
} else {
@@ -1361,7 +1497,8 @@ public class ResolverActivity extends Activity implements
// Header views don't count.
return false;
}
- ResolveInfo ri = mAdapter.resolveInfoForPosition(position, true);
+ ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(position, true);
showTargetDetails(ri);
return true;
}
@@ -1401,7 +1538,8 @@ public class ResolverActivity extends Activity implements
final ResolverActivity ra = (ResolverActivity) getActivity();
if (ra != null) {
- final TargetInfo ti = ra.mAdapter.getItem(selections[0].getIndex());
+ final TargetInfo ti = ra.mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getItem(selections[0].getIndex());
if (ra.onTargetSelected(ti, false)) {
ra.mPickOptionRequest = null;
ra.finish();
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index bb7ca358f815..48064da7c35c 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -37,7 +37,6 @@ import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -81,7 +80,7 @@ public class ResolverListAdapter extends BaseAdapter {
// This one is the list that the Adapter will actually present.
List<DisplayResolveInfo> mDisplayList;
- List<ResolvedComponentInfo> mUnfilteredResolveList;
+ private List<ResolvedComponentInfo> mUnfilteredResolveList;
private int mLastChosenPosition = -1;
private boolean mFilterLastUsed;
@@ -162,6 +161,10 @@ public class ResolverListAdapter extends BaseAdapter {
mResolverListController.updateChooserCounts(packageName, userId, action);
}
+ List<ResolvedComponentInfo> getUnfilteredResolveList() {
+ return mUnfilteredResolveList;
+ }
+
/**
* @return true if all items in the display list are defined as browsers by
* ResolveInfo.handleAllWebDataURI
@@ -576,7 +579,7 @@ public class ResolverListAdapter extends BaseAdapter {
Drawable loadIconForResolveInfo(ResolveInfo ri) {
// Load icons based on the current process. If in work profile icons should be badged.
- return makePresentationGetter(ri).getIcon(Process.myUserHandle());
+ return makePresentationGetter(ri).getIcon(mResolverListController.getUserHandle());
}
void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) {
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index b456ca00fe2b..abd3eb2453df 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -28,6 +28,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -55,6 +56,7 @@ public class ResolverListController {
private static final String TAG = "ResolverListController";
private static final boolean DEBUG = false;
+ private final UserHandle mUserHandle;
private AbstractResolverComparator mResolverComparator;
private boolean isComputed = false;
@@ -64,8 +66,9 @@ public class ResolverListController {
PackageManager pm,
Intent targetIntent,
String referrerPackage,
- int launchedFromUid) {
- this(context, pm, targetIntent, referrerPackage, launchedFromUid,
+ int launchedFromUid,
+ UserHandle userHandle) {
+ this(context, pm, targetIntent, referrerPackage, launchedFromUid, userHandle,
new ResolverRankerServiceResolverComparator(
context, targetIntent, referrerPackage, null));
}
@@ -76,12 +79,14 @@ public class ResolverListController {
Intent targetIntent,
String referrerPackage,
int launchedFromUid,
+ UserHandle userHandle,
AbstractResolverComparator resolverComparator) {
mContext = context;
mpm = pm;
mLaunchedFromUid = launchedFromUid;
mTargetIntent = targetIntent;
mReferrerPackage = referrerPackage;
+ mUserHandle = userHandle;
mResolverComparator = resolverComparator;
}
@@ -116,7 +121,8 @@ public class ResolverListController {
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
flags |= PackageManager.MATCH_INSTANT;
}
- final List<ResolveInfo> infos = mpm.queryIntentActivities(intent, flags);
+ final List<ResolveInfo> infos = mpm.queryIntentActivitiesAsUser(intent, flags,
+ mUserHandle);
if (infos != null) {
if (resolvedComponents == null) {
resolvedComponents = new ArrayList<>();
@@ -127,6 +133,10 @@ public class ResolverListController {
return resolvedComponents;
}
+ UserHandle getUserHandle() {
+ return mUserHandle;
+ }
+
@VisibleForTesting
public void addResolveListDedupe(List<ResolverActivity.ResolvedComponentInfo> into,
Intent intent,
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
new file mode 100644
index 000000000000..9e814ab5d0aa
--- /dev/null
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.PagerAdapter;
+
+/**
+ * A {@link PagerAdapter} which describes the work and personal profile intent resolver screens.
+ */
+@VisibleForTesting
+public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter {
+
+ private final ResolverProfileDescriptor[] mItems;
+
+ ResolverMultiProfilePagerAdapter(Context context,
+ ResolverListAdapter adapter) {
+ super(context, /* currentPage */ 0);
+ mItems = new ResolverProfileDescriptor[] {
+ createProfileDescriptor(adapter)
+ };
+ }
+
+ ResolverMultiProfilePagerAdapter(Context context,
+ ResolverListAdapter personalAdapter,
+ ResolverListAdapter workAdapter,
+ @Profile int defaultProfile) {
+ super(context, /* currentPage */ defaultProfile);
+ mItems = new ResolverProfileDescriptor[] {
+ createProfileDescriptor(personalAdapter),
+ createProfileDescriptor(workAdapter)
+ };
+ }
+
+ private ResolverProfileDescriptor createProfileDescriptor(
+ ResolverListAdapter adapter) {
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ final ViewGroup rootView =
+ (ViewGroup) inflater.inflate(R.layout.resolver_list_per_profile, null, false);
+ return new ResolverProfileDescriptor(rootView, adapter);
+ }
+
+ ListView getListViewForIndex(int index) {
+ return getItem(index).listView;
+ }
+
+ @Override
+ ResolverProfileDescriptor getItem(int pageIndex) {
+ return mItems[pageIndex];
+ }
+
+ @Override
+ int getItemCount() {
+ return mItems.length;
+ }
+
+ @Override
+ void setupListAdapter(int pageIndex) {
+ final ListView listView = getItem(pageIndex).listView;
+ listView.setAdapter(getItem(pageIndex).resolverListAdapter);
+ }
+
+ @Override
+ ResolverListAdapter getAdapterForIndex(int pageIndex) {
+ return mItems[pageIndex].resolverListAdapter;
+ }
+
+ @Override
+ @VisibleForTesting
+ public ResolverListAdapter getCurrentListAdapter() {
+ return getAdapterForIndex(getCurrentPage());
+ }
+
+ @Override
+ ResolverListAdapter getCurrentRootAdapter() {
+ return getCurrentListAdapter();
+ }
+
+ @Override
+ ListView getCurrentAdapterView() {
+ return getListViewForIndex(getCurrentPage());
+ }
+
+ class ResolverProfileDescriptor extends ProfileDescriptor {
+ private ResolverListAdapter resolverListAdapter;
+ final ListView listView;
+ ResolverProfileDescriptor(ViewGroup rootView, ResolverListAdapter adapter) {
+ super(rootView);
+ resolverListAdapter = adapter;
+ listView = rootView.findViewById(R.id.resolver_list);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/WrapHeightViewPager.java b/core/java/com/android/internal/app/WrapHeightViewPager.java
new file mode 100644
index 000000000000..b017bb44d751
--- /dev/null
+++ b/core/java/com/android/internal/app/WrapHeightViewPager.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.internal.widget.ViewPager;
+
+/**
+ * A {@link ViewPager} which wraps around its first child's height.
+ * <p>Normally {@link ViewPager} instances expand their height to cover all remaining space in
+ * the layout.
+ * <p>This class is used for the intent resolver picker's tabbed view to maintain
+ * consistency with the previous behavior.
+ */
+public class WrapHeightViewPager extends ViewPager {
+
+ public WrapHeightViewPager(Context context) {
+ super(context);
+ }
+
+ public WrapHeightViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public WrapHeightViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public WrapHeightViewPager(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ // TODO(arangelov): When we have multiple pages, the height should wrap to the currently
+ // displayed page. Investigate whether onMeasure is called when changing a page, and instead
+ // of getChildAt(0), use the currently displayed one.
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.AT_MOST) {
+ return;
+ }
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
+ int height = getMeasuredHeight();
+ if (getChildCount() > 0) {
+ View firstChild = getChildAt(0);
+ firstChild.measure(widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
+ height = firstChild.getMeasuredHeight();
+ }
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 0847fbdd2291..f5fae1932cc4 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -28,9 +28,9 @@ import static android.system.OsConstants.S_IXOTH;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
import android.os.SELinux;
import android.system.ErrnoException;
@@ -87,11 +87,12 @@ public class NativeLibraryHelper {
}
}
- public static Handle create(Package pkg) throws IOException {
- return create(pkg.getAllCodePaths(),
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0,
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+ public static Handle create(AndroidPackage pkg) throws IOException {
+ return create(
+ pkg.makeListAllCodePaths(),
+ (pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0,
+ (pkg.getFlags() & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
+ (pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
}
public static Handle create(PackageLite lite) throws IOException {
@@ -455,7 +456,7 @@ public class NativeLibraryHelper {
* @param useIsaSubdir Whether or not to set up a sub dir for the ISA.
* @return ABI code if installation succeeds or error code if installation fails.
*/
- public static int configureNativeBinariesForSupportedAbi(Package pkg, Handle handle,
+ public static int configureNativeBinariesForSupportedAbi(AndroidPackage pkg, Handle handle,
File libraryRoot, String[] abiList, boolean useIsaSubdir) {
// TODO(b/136132412): Implement this.
return -1;
diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index c8929e93f030..d78bd73b080b 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -513,6 +513,11 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
try {
result = get();
} catch (Exception t) {
+ // Exceptions coming out of get() are wrapped in ExecutionException, which is not
+ // handled by Parcel.
+ if (t instanceof ExecutionException && t.getCause() instanceof Exception) {
+ t = (Exception) t.getCause();
+ }
dest.writeBoolean(true);
dest.writeException(t);
return;
diff --git a/core/java/com/android/internal/infra/TEST_MAPPING b/core/java/com/android/internal/infra/TEST_MAPPING
index 3781d637f68c..3de107e892b6 100644
--- a/core/java/com/android/internal/infra/TEST_MAPPING
+++ b/core/java/com/android/internal/infra/TEST_MAPPING
@@ -6,10 +6,18 @@
{
"name": "CtsPermissionTestCases",
"options": [
- {
- "include-filter": "android.permission.cts.PermissionControllerTest"
- }
+ {
+ "include-filter": "android.permission.cts.PermissionControllerTest"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.infra."
+ }
]
}
]
-} \ No newline at end of file
+}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index a21187165c65..fa823c4bf2f6 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -367,8 +367,8 @@ public class RuntimeInit {
if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}
- protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
- ClassLoader classLoader) {
+ protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
+ String[] argv, ClassLoader classLoader) {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
@@ -377,6 +377,7 @@ public class RuntimeInit {
nativeSetExitWithoutCleanup(true);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
+ VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
final Arguments args = new Arguments(argv);
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index f0e779694c90..790d7f7ab694 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -23,16 +23,18 @@ import android.system.Os;
import android.system.OsConstants;
import android.system.StructCapUserData;
import android.system.StructCapUserHeader;
-import android.util.TimingsTraceLog;
import android.util.Slog;
+import android.util.TimingsTraceLog;
+
import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+
import java.io.DataOutputStream;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
-import libcore.io.IoUtils;
-
/**
* Startup class for the wrapper process.
* @hide
@@ -166,10 +168,10 @@ public class WrapperInit {
System.arraycopy(argv, 2, removedArgs, 0, argv.length - 2);
argv = removedArgs;
}
-
// Perform the same initialization that would happen after the Zygote forks.
Zygote.nativePreApplicationInit();
- return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
+ return RuntimeInit.applicationInit(targetSdkVersion, /*disabledCompatChanges*/ null,
+ argv, classLoader);
}
/**
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index fbacdd73dabb..2b988c155412 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -672,6 +672,7 @@ public final class Zygote {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
+ args.mDisabledCompatChanges,
args.mRemainingArgs,
null /* classLoader */);
} finally {
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index a23e659db49a..54b2a2063451 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -215,6 +215,12 @@ class ZygoteArguments {
boolean mIsTopApp;
/**
+ * A set of disabled app compatibility changes for the running app. From
+ * --disabled-compat-changes.
+ */
+ long[] mDisabledCompatChanges = null;
+
+ /**
* Constructs instance and parses args
*
* @param args zygote command-line args
@@ -421,6 +427,16 @@ class ZygoteArguments {
expectRuntimeArgs = false;
} else if (arg.startsWith(Zygote.START_AS_TOP_APP_ARG)) {
mIsTopApp = true;
+ } else if (arg.startsWith("--disabled-compat-changes=")) {
+ if (mDisabledCompatChanges != null) {
+ throw new IllegalArgumentException("Duplicate arg specified");
+ }
+ final String[] params = getAssignmentList(arg);
+ final int length = params.length;
+ mDisabledCompatChanges = new long[length];
+ for (int i = 0; i < length; i++) {
+ mDisabledCompatChanges[i] = Long.parseLong(params[i]);
+ }
} else {
break;
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index a14b09343a01..3111b6ff0f72 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -501,6 +501,7 @@ class ZygoteConnection {
} else {
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
+ parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9ee79eada626..49b4cf828db6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -553,6 +553,7 @@ public class ZygoteInit {
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
+ parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}
@@ -988,14 +989,16 @@ public class ZygoteInit {
*
* Current recognized args:
* <ul>
- * <li> <code> [--] &lt;start class name&gt; &lt;args&gt;
+ * <li> <code> [--] &lt;start class name&gt; &lt;args&gt;
* </ul>
*
* @param targetSdkVersion target SDK version
- * @param argv arg strings
+ * @param disabledCompatChanges set of disabled compat changes for the process (all others
+ * are enabled)
+ * @param argv arg strings
*/
- public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
- ClassLoader classLoader) {
+ public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
+ String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
@@ -1005,7 +1008,8 @@ public class ZygoteInit {
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
- return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
+ return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
+ classLoader);
}
/**
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 764d4a598bd5..9aa56f03275f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -22,7 +22,6 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
@@ -2423,19 +2422,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final Context context = getContext();
final int targetSdk = context.getApplicationInfo().targetSdkVersion;
- final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
- final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q;
- final boolean targetHcNeedsOptions = context.getResources().getBoolean(
- R.bool.target_honeycomb_needs_options_menu);
- final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
-
- if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
- setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
- } else {
- setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
- }
if (!mForcedStatusBarColor) {
mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 821022f1f917..bc8019796d22 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -600,6 +600,14 @@ public class ArrayUtils {
return cur;
}
+ public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, int index, T val) {
+ if (cur == null) {
+ cur = new ArrayList<>();
+ }
+ cur.add(index, val);
+ return cur;
+ }
+
public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
if (cur == null) {
return null;
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 731b93c18b09..3fff5c233890 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -102,6 +102,24 @@ public class Preconditions {
}
/**
+ * Ensures that an string reference passed as a parameter to the calling method is not empty.
+ *
+ * @param string an string reference
+ * @param messageTemplate a printf-style message template to use if the check fails; will be
+ * converted to a string using {@link String#format(String, Object...)}
+ * @param messageArgs arguments for {@code messageTemplate}
+ * @return the string reference that was validated
+ * @throws IllegalArgumentException if {@code string} is empty
+ */
+ public static @NonNull <T extends CharSequence> T checkStringNotEmpty(
+ final T string, final String messageTemplate, final Object... messageArgs) {
+ if (TextUtils.isEmpty(string)) {
+ throw new IllegalArgumentException(String.format(messageTemplate, messageArgs));
+ }
+ return string;
+ }
+
+ /**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 148b0a2799b4..b91d3595fe6a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -144,6 +144,7 @@ cc_library_shared {
"android_os_VintfRuntimeInfo.cpp",
"android_net_LocalSocketImpl.cpp",
"android_net_NetUtils.cpp",
+ "android_service_DataLoaderService.cpp",
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
"android_util_StatsLog.cpp",
@@ -152,6 +153,7 @@ cc_library_shared {
"android_util_StringBlock.cpp",
"android_util_XmlBlock.cpp",
"android_util_jar_StrictJarFile.cpp",
+ "android_media_AudioDeviceAddress.cpp",
"android_media_AudioEffectDescriptor.cpp",
"android_media_AudioRecord.cpp",
"android_media_AudioSystem.cpp",
@@ -239,6 +241,8 @@ cc_library_shared {
"libGLESv1_CM",
"libGLESv2",
"libGLESv3",
+ "libincfs",
+ "libdataloader",
"libvulkan",
"libETC1",
"libhardware",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 378e125a3a3e..b8fd3ad43ce5 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -86,6 +86,7 @@ extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
extern int register_android_hardware_UsbRequest(JNIEnv *env);
extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env);
+extern int register_android_media_AudioDeviceAddress(JNIEnv *env);
extern int register_android_media_AudioEffectDescriptor(JNIEnv *env);
extern int register_android_media_AudioRecord(JNIEnv *env);
extern int register_android_media_AudioSystem(JNIEnv *env);
@@ -150,6 +151,7 @@ extern int register_android_os_UEventObserver(JNIEnv* env);
extern int register_android_os_HidlMemory(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
extern int register_android_os_SharedMemory(JNIEnv* env);
+extern int register_android_service_DataLoaderService(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
@@ -648,6 +650,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p
char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
std::string fingerprintBuf;
char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
+ char opaqueJniIds[sizeof("-Xopaque-jni-ids:") - 1 + PROPERTY_VALUE_MAX];
char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];
// Read if we are using the profile configuration, do this at the start since the last ART args
@@ -839,6 +842,14 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p
"default");
}
+ // Only pass an explicit opaque-jni-ids to apps forked from zygote
+ if (zygote) {
+ parseRuntimeOption("dalvik.vm.opaque-jni-ids",
+ opaqueJniIds,
+ "-Xopaque-jni-ids:",
+ "swapable");
+ }
+
parseRuntimeOption("dalvik.vm.lockprof.threshold",
lockProfThresholdBuf,
"-Xlockprofthreshold:");
@@ -1442,6 +1453,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_NativeHandle),
REG_JNI(register_android_os_VintfObject),
REG_JNI(register_android_os_VintfRuntimeInfo),
+ REG_JNI(register_android_service_DataLoaderService),
REG_JNI(register_android_view_DisplayEventReceiver),
REG_JNI(register_android_view_RenderNodeAnimator),
REG_JNI(register_android_view_InputApplicationHandle),
@@ -1501,6 +1513,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_hardware_UsbDeviceConnection),
REG_JNI(register_android_hardware_UsbRequest),
REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),
+ REG_JNI(register_android_media_AudioDeviceAddress),
REG_JNI(register_android_media_AudioEffectDescriptor),
REG_JNI(register_android_media_AudioSystem),
REG_JNI(register_android_media_AudioRecord),
diff --git a/core/jni/android_media_AudioDeviceAddress.cpp b/core/jni/android_media_AudioDeviceAddress.cpp
new file mode 100644
index 000000000000..5f39f7efb6a2
--- /dev/null
+++ b/core/jni/android_media_AudioDeviceAddress.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "core_jni_helpers.h"
+#include "android_media_AudioDeviceAddress.h"
+#include "android_media_AudioErrors.h"
+
+#include <media/AudioDeviceTypeAddr.h>
+
+using namespace android;
+
+static jclass gAudioDeviceAddressClass;
+static jmethodID gAudioDeviceAddressCstor;
+
+namespace android {
+
+jint createAudioDeviceAddressFromNative(
+ JNIEnv *env, jobject *jAudioDeviceAddress,
+ const AudioDeviceTypeAddr *devTypeAddr) {
+ jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
+ jint jNativeType = (jint)devTypeAddr->mType;
+ ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->mAddress.data()));
+
+ *jAudioDeviceAddress = env->NewObject(gAudioDeviceAddressClass, gAudioDeviceAddressCstor,
+ jNativeType, jAddress.get());
+
+ return jStatus;
+}
+
+}
+
+int register_android_media_AudioDeviceAddress(JNIEnv *env)
+{
+ jclass audioDeviceTypeAddressClass = FindClassOrDie(env, "android/media/AudioDeviceAddress");
+ gAudioDeviceAddressClass = MakeGlobalRefOrDie(env, audioDeviceTypeAddressClass);
+ gAudioDeviceAddressCstor = GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>",
+ "(ILjava/lang/String;)V");
+
+ return 0;
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java b/core/jni/android_media_AudioDeviceAddress.h
index faa6e9cff2b2..c66b17978776 100644
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java
+++ b/core/jni/android_media_AudioDeviceAddress.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -12,19 +12,22 @@
* 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.frameworks.coretests;
+#ifndef ANDROID_MEDIA_AUDIODEVICEADDRESS_H
+#define ANDROID_MEDIA_AUDIODEVICEADDRESS_H
+
+#include <system/audio.h>
+#include <media/AudioDeviceTypeAddr.h>
+
+#include "jni.h"
+
+namespace android {
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
+// Create a Java AudioDeviceAddress instance from a C++ AudioDeviceTypeAddress
-public class FirstChildTestService extends Service {
+extern jint createAudioDeviceAddressFromNative(JNIEnv *env, jobject *jAudioDeviceAddress,
+ const AudioDeviceTypeAddr *devTypeAddr);
+} // namespace android
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-}
+#endif \ No newline at end of file
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 01f9d0b0cde5..79cf0191057d 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -26,19 +26,19 @@
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
+#include "android_media_AudioAttributes.h"
+#include "android_media_AudioDeviceAddress.h"
+#include "android_media_AudioEffectDescriptor.h"
+#include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
+#include "android_media_MicrophoneInfo.h"
#include <audiomanager/AudioManager.h>
-#include <media/AudioDeviceTypeAddr.h>
-#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
+#include <media/AudioSystem.h>
#include <media/MicrophoneInfo.h>
#include <nativehelper/ScopedLocalRef.h>
#include <system/audio.h>
#include <system/audio_policy.h>
-#include "android_media_AudioEffectDescriptor.h"
-#include "android_media_AudioFormat.h"
-#include "android_media_AudioErrors.h"
-#include "android_media_MicrophoneInfo.h"
-#include "android_media_AudioAttributes.h"
// ----------------------------------------------------------------------------
@@ -2254,9 +2254,9 @@ static jint
android_media_AudioSystem_setAudioHalPids(JNIEnv *env, jobject clazz, jintArray jPids)
{
if (jPids == NULL) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return (jint) AUDIO_JAVA_BAD_VALUE;
}
- pid_t *nPidsArray = (pid_t *)env->GetIntArrayElements(jPids, NULL);
+ pid_t *nPidsArray = (pid_t *) env->GetIntArrayElements(jPids, NULL);
std::vector<pid_t> nPids(nPidsArray, nPidsArray + env->GetArrayLength(jPids));
status_t status = AudioSystem::setAudioHalPids(nPids);
env->ReleaseIntArrayElements(jPids, nPidsArray, 0);
@@ -2270,6 +2270,48 @@ android_media_AudioSystem_isCallScreeningModeSupported(JNIEnv *env, jobject thiz
return AudioSystem::isCallScreenModeSupported();
}
+static jint
+android_media_AudioSystem_setPreferredDeviceForStrategy(JNIEnv *env, jobject thiz,
+ jint strategy, jint deviceType, jstring deviceAddress) {
+
+ const char *c_address = env->GetStringUTFChars(deviceAddress, NULL);
+ int status = check_AudioSystem_Command(
+ AudioSystem::setPreferredDeviceForStrategy((product_strategy_t) strategy,
+ AudioDeviceTypeAddr(deviceType, c_address)));
+ env->ReleaseStringUTFChars(deviceAddress, c_address);
+ return (jint) status;
+}
+
+static jint
+android_media_AudioSystem_removePreferredDeviceForStrategy(JNIEnv *env, jobject thiz, jint strategy)
+{
+ return (jint) check_AudioSystem_Command(
+ AudioSystem::removePreferredDeviceForStrategy((product_strategy_t) strategy));
+}
+
+static jint
+android_media_AudioSystem_getPreferredDeviceForStrategy(JNIEnv *env, jobject thiz,
+ jint strategy, jobjectArray jDeviceArray)
+{
+ if (jDeviceArray == nullptr || env->GetArrayLength(jDeviceArray) != 1) {
+ ALOGE("%s invalid array to store AudioDeviceAddress", __FUNCTION__);
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ AudioDeviceTypeAddr elDevice;
+ status_t status = check_AudioSystem_Command(
+ AudioSystem::getPreferredDeviceForStrategy((product_strategy_t) strategy, elDevice));
+ if (status != NO_ERROR) {
+ return (jint) status;
+ }
+ jobject jAudioDeviceAddress = NULL;
+ jint jStatus = createAudioDeviceAddressFromNative(env, &jAudioDeviceAddress, &elDevice);
+ if (jStatus == AUDIO_JAVA_SUCCESS) {
+ env->SetObjectArrayElement(jDeviceArray, 0, jAudioDeviceAddress);
+ }
+ return jStatus;
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -2350,6 +2392,9 @@ static const JNINativeMethod gMethods[] = {
{"setRttEnabled", "(Z)I", (void *)android_media_AudioSystem_setRttEnabled},
{"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids},
{"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported},
+ {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setPreferredDeviceForStrategy},
+ {"removePreferredDeviceForStrategy", "(I)I", (void *)android_media_AudioSystem_removePreferredDeviceForStrategy},
+ {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getPreferredDeviceForStrategy},
};
static const JNINativeMethod gEventHandlerMethods[] = {
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index bd82bd91c55d..0f7611a8ead1 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -50,10 +50,6 @@ inline static void withString(JNIEnv* env, jstring jstr, F callback) {
callback(buffer.data());
}
-static jlong android_os_Trace_nativeGetEnabledTags(JNIEnv*, jclass) {
- return atrace_get_enabled_tags();
-}
-
static void android_os_Trace_nativeTraceCounter(JNIEnv* env, jclass,
jlong tag, jstring nameStr, jlong value) {
withString(env, nameStr, [tag, value](char* str) {
@@ -96,9 +92,6 @@ static void android_os_Trace_nativeSetTracingEnabled(JNIEnv*, jclass, jboolean e
static const JNINativeMethod gTraceMethods[] = {
/* name, signature, funcPtr */
- { "nativeGetEnabledTags",
- "()J",
- (void*)android_os_Trace_nativeGetEnabledTags },
{ "nativeSetAppTracingAllowed",
"(Z)V",
(void*)android_os_Trace_nativeSetAppTracingAllowed },
@@ -123,6 +116,11 @@ static const JNINativeMethod gTraceMethods[] = {
{ "nativeAsyncTraceEnd",
"(JLjava/lang/String;I)V",
(void*)android_os_Trace_nativeAsyncTraceEnd },
+
+ // ----------- @CriticalNative ----------------
+ { "nativeGetEnabledTags",
+ "()J",
+ (void*)atrace_get_enabled_tags },
};
int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/jni/android_service_DataLoaderService.cpp b/core/jni/android_service_DataLoaderService.cpp
new file mode 100644
index 000000000000..4c0f55f2bf23
--- /dev/null
+++ b/core/jni/android_service_DataLoaderService.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "dataloader-jni"
+
+#include <vector>
+
+#include "core_jni_helpers.h"
+#include "dataloader_ndk.h"
+#include "jni.h"
+
+namespace android {
+namespace {
+
+struct JniIds {
+ jfieldID dataBlockFileIno;
+ jfieldID dataBlockBlockIndex;
+ jfieldID dataBlockDataBytes;
+ jfieldID dataBlockCompressionType;
+
+ JniIds(JNIEnv* env) {
+ const auto dataBlock =
+ FindClassOrDie(env,
+ "android/service/incremental/"
+ "IncrementalDataLoaderService$FileSystemConnector$DataBlock");
+ dataBlockFileIno = GetFieldIDOrDie(env, dataBlock, "mFileIno", "J");
+ dataBlockBlockIndex =
+ GetFieldIDOrDie(env, dataBlock, "mBlockIndex", "I");
+ dataBlockDataBytes = GetFieldIDOrDie(env, dataBlock, "mDataBytes", "[B");
+ dataBlockCompressionType =
+ GetFieldIDOrDie(env, dataBlock, "mCompressionType", "I");
+ }
+};
+
+const JniIds& jniIds(JNIEnv* env) {
+ static const JniIds ids(env);
+ return ids;
+}
+
+class ScopedJniArrayCritical {
+public:
+ ScopedJniArrayCritical(JNIEnv* env, jarray array) : mEnv(env), mArr(array) {
+ mPtr = array ? env->GetPrimitiveArrayCritical(array, nullptr) : nullptr;
+ }
+ ~ScopedJniArrayCritical() {
+ if (mPtr) {
+ mEnv->ReleasePrimitiveArrayCritical(mArr, mPtr, 0);
+ mPtr = nullptr;
+ }
+ }
+
+ ScopedJniArrayCritical(const ScopedJniArrayCritical&) = delete;
+ void operator=(const ScopedJniArrayCritical&) = delete;
+
+ ScopedJniArrayCritical(ScopedJniArrayCritical&& other)
+ : mEnv(other.mEnv),
+ mArr(std::exchange(mArr, nullptr)),
+ mPtr(std::exchange(mPtr, nullptr)) {}
+ ScopedJniArrayCritical& operator=(ScopedJniArrayCritical&& other) {
+ mEnv = other.mEnv;
+ mArr = std::exchange(other.mArr, nullptr);
+ mPtr = std::exchange(other.mPtr, nullptr);
+ return *this;
+ }
+
+ void* ptr() const { return mPtr; }
+ jsize size() const { return mArr ? mEnv->GetArrayLength(mArr) : 0; }
+
+private:
+ JNIEnv* mEnv;
+ jarray mArr;
+ void* mPtr;
+};
+
+static jboolean nativeCreateDataLoader(JNIEnv* env,
+ jobject thiz,
+ jint storageId,
+ jobject control,
+ jobject params,
+ jobject callback) {
+ ALOGE("nativeCreateDataLoader: %p/%d, %d, %p, %p, %p", thiz,
+ env->GetObjectRefType(thiz), storageId, params, control, callback);
+ return DataLoaderService_OnCreate(env, thiz,
+ storageId, control, params, callback);
+}
+
+static jboolean nativeStartDataLoader(JNIEnv* env,
+ jobject thiz,
+ jint storageId) {
+ ALOGE("nativeStartDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz),
+ storageId);
+ return DataLoaderService_OnStart(storageId);
+}
+
+static jboolean nativeStopDataLoader(JNIEnv* env,
+ jobject thiz,
+ jint storageId) {
+ ALOGE("nativeStopDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz),
+ storageId);
+ return DataLoaderService_OnStop(storageId);
+}
+
+static jboolean nativeDestroyDataLoader(JNIEnv* env,
+ jobject thiz,
+ jint storageId) {
+ ALOGE("nativeDestroyDataLoader: %p/%d, %d", thiz,
+ env->GetObjectRefType(thiz), storageId);
+ return DataLoaderService_OnDestroy(storageId);
+}
+
+
+static jboolean nativeOnFileCreated(JNIEnv* env,
+ jobject thiz,
+ jint storageId,
+ jlong inode,
+ jbyteArray metadata) {
+ ALOGE("nativeOnFileCreated: %p/%d, %d", thiz,
+ env->GetObjectRefType(thiz), storageId);
+ return DataLoaderService_OnFileCreated(storageId, inode, metadata);
+}
+
+static jboolean nativeIsFileRangeLoadedNode(JNIEnv* env,
+ jobject clazz,
+ jlong self,
+ jlong node,
+ jlong start,
+ jlong end) {
+ // TODO(b/136132412): implement this
+ return JNI_FALSE;
+}
+
+static jboolean nativeWriteMissingData(JNIEnv* env,
+ jobject clazz,
+ jlong self,
+ jobjectArray data_block,
+ jobjectArray hash_blocks) {
+ const auto& jni = jniIds(env);
+ auto length = env->GetArrayLength(data_block);
+ std::vector<incfs_new_data_block> instructions(length);
+
+ // May not call back into Java after even a single jniArrayCritical, so
+ // let's collect the Java pointers to byte buffers first and lock them in
+ // memory later.
+
+ std::vector<jbyteArray> blockBuffers(length);
+ for (int i = 0; i != length; ++i) {
+ auto& inst = instructions[i];
+ auto jniBlock = env->GetObjectArrayElement(data_block, i);
+ inst.file_ino = env->GetLongField(jniBlock, jni.dataBlockFileIno);
+ inst.block_index = env->GetIntField(jniBlock, jni.dataBlockBlockIndex);
+ blockBuffers[i] = (jbyteArray)env->GetObjectField(
+ jniBlock, jni.dataBlockDataBytes);
+ inst.compression = (incfs_compression_alg)env->GetIntField(
+ jniBlock, jni.dataBlockCompressionType);
+ }
+
+ std::vector<ScopedJniArrayCritical> jniScopedArrays;
+ jniScopedArrays.reserve(length);
+ for (int i = 0; i != length; ++i) {
+ auto buffer = blockBuffers[i];
+ jniScopedArrays.emplace_back(env, buffer);
+ auto& inst = instructions[i];
+ inst.data = (uint64_t)jniScopedArrays.back().ptr();
+ inst.data_len = jniScopedArrays.back().size();
+ }
+
+ auto connector = (DataLoaderFilesystemConnectorPtr)self;
+ if (auto err = DataLoader_FilesystemConnector_writeBlocks(
+ connector, instructions.data(), length);
+ err < 0) {
+ jniScopedArrays.clear();
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+static jboolean nativeWriteSignerDataNode(JNIEnv* env,
+ jobject clazz,
+ jlong self,
+ jstring relative_path,
+ jbyteArray signer_data) {
+ // TODO(b/136132412): implement this
+ return JNI_TRUE;
+}
+
+static jbyteArray nativeGetFileMetadataNode(JNIEnv* env,
+ jobject clazz,
+ jlong self,
+ jlong inode) {
+ auto connector = (DataLoaderFilesystemConnectorPtr)self;
+ std::vector<char> metadata(INCFS_MAX_FILE_ATTR_SIZE);
+ size_t size = metadata.size();
+ if (DataLoader_FilesystemConnector_getRawMetadata(connector, inode,
+ metadata.data(), &size) < 0) {
+ size = 0;
+ }
+ metadata.resize(size);
+
+ auto buffer = env->NewByteArray(metadata.size());
+ env->SetByteArrayRegion(buffer, 0, metadata.size(),
+ (jbyte*)metadata.data());
+ return buffer;
+}
+
+static jbyteArray nativeGetFileInfoNode(JNIEnv* env,
+ jobject clazz,
+ jlong self,
+ jlong inode) {
+ // TODO(b/136132412): implement this
+ return nullptr;
+}
+
+static jboolean nativeReportStatus(JNIEnv* env,
+ jobject clazz,
+ jlong self,
+ jint status) {
+ auto listener = (DataLoaderStatusListenerPtr)self;
+ return DataLoader_StatusListener_reportStatus(listener,
+ (DataLoaderStatus)status);
+}
+
+static const JNINativeMethod dlc_method_table[] = {
+ {"nativeCreateDataLoader",
+ "(ILandroid/os/incremental/IncrementalFileSystemControlParcel;"
+ "Landroid/os/incremental/IncrementalDataLoaderParamsParcel;"
+ "Landroid/content/pm/IDataLoaderStatusListener;)Z",
+ (void*)nativeCreateDataLoader},
+ {"nativeStartDataLoader", "(I)Z", (void*)nativeStartDataLoader},
+ {"nativeStopDataLoader", "(I)Z", (void*)nativeStopDataLoader},
+ {"nativeDestroyDataLoader", "(I)Z", (void*)nativeDestroyDataLoader},
+ {"nativeIsFileRangeLoadedNode", "(JJJJ)Z",
+ (void*)nativeIsFileRangeLoadedNode},
+ {"nativeWriteMissingData",
+ "(J[Landroid/service/incremental/"
+ "IncrementalDataLoaderService$FileSystemConnector$DataBlock;[Landroid/service/incremental/"
+ "IncrementalDataLoaderService$FileSystemConnector$HashBlock;)Z",
+ (void*)nativeWriteMissingData},
+ {"nativeWriteSignerDataNode", "(JJ[B)Z",
+ (void*)nativeWriteSignerDataNode},
+ {"nativeGetFileMetadataNode", "(JJ)[B",
+ (void*)nativeGetFileMetadataNode},
+ {"nativeGetFileInfoNode", "(JJ)[B", (void*)nativeGetFileInfoNode},
+ {"nativeReportStatus", "(JI)Z", (void*)nativeReportStatus},
+ {"nativeOnFileCreated", "(IJ[B)Z", (void*)nativeOnFileCreated},
+};
+
+} // namespace
+
+int register_android_service_DataLoaderService(JNIEnv* env) {
+ return jniRegisterNativeMethods(env,
+ "android/service/incremental/IncrementalDataLoaderService",
+ dlc_method_table, NELEM(dlc_method_table));
+}
+
+} // namespace android
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index fd6984b830d7..0c21076065d5 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -37,6 +37,8 @@ static const char* kPathWhitelist[] = {
"/apex/com.android.ipsec/javalib/ike.jar",
"/apex/com.android.media/javalib/updatable-media.jar",
"/apex/com.android.sdkext/javalib/framework-sdkext.jar",
+ "/apex/com.android.telephony/javalib/telephony-common.jar",
+ "/apex/com.android.telephony/javalib/ims-common.jar",
"/dev/null",
"/dev/socket/zygote",
"/dev/socket/zygote_secondary",
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 24456d80625d..0c7484216367 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -163,6 +163,7 @@ message DisplayContentProto {
repeated IdentifierProto opening_apps = 17;
repeated IdentifierProto closing_apps = 18;
repeated IdentifierProto changing_apps = 19;
+ repeated WindowTokenProto overlay_windows = 20;
}
/* represents DisplayFrames */
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 1ec05fb5e9fc..ecb4193a2c6c 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -264,3 +264,14 @@ message ZenPolicyProto {
optional Sender priority_calls = 16;
optional Sender priority_messages = 17;
}
+
+// Next Tag: 2
+message PackageRemoteViewInfoProto {
+ optional string package_name = 1;
+ // add per-package additional info here (like channels)
+}
+
+// Next Tag: 2
+message NotificationRemoteViewsProto {
+ repeated PackageRemoteViewInfoProto package_remote_view_info = 1;
+} \ No newline at end of file
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 93a9fe2e5848..e7c282751d6a 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -56,13 +56,6 @@ message WindowLayoutParamsProto {
optional uint32 input_feature_flags = 19;
optional int64 user_activity_timeout = 20;
- enum NeedsMenuState {
- NEEDS_MENU_UNSET = 0;
- NEEDS_MENU_SET_TRUE = 1;
- NEEDS_MENU_SET_FALSE = 2;
- }
- optional NeedsMenuState needs_menu_key = 22;
-
optional DisplayProto.ColorMode color_mode = 23;
optional uint32 flags = 24;
optional uint32 private_flags = 26;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f6e91efd2ad7..c925744fea3b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -635,10 +635,9 @@
<protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
- <!-- NETWORK_SET_TIME / NETWORK_SET_TIMEZONE moved from com.android.phone to system server.
- They should ultimately be removed. -->
+ <!-- NETWORK_SET_TIME moved from com.android.phone to system server. It should ultimately be
+ removed. -->
<protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
- <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIMEZONE" />
<!-- For tether entitlement recheck-->
<protected-broadcast
@@ -3265,13 +3264,6 @@
<permission android:name="android.permission.BIND_TV_INPUT"
android:protectionLevel="signature|privileged" />
- <!-- Must be required by an {@link android.service.sms.FinancialSmsService}
- to ensure that only the system can bind to it.
- @hide This is not a third-party API (intended for OEMs and system apps).
- -->
- <permission android:name="android.permission.BIND_FINANCIAL_SMS_SERVICE"
- android:protectionLevel="signature" />
-
<!-- @SystemApi
Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
to ensure that only the system can bind to it.
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 6807f9af3980..9f296f8f7c08 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -29,7 +29,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
- android:elevation="1dp"
+ android:elevation="0dp"
android:background="@drawable/bottomsheet_background">
<ImageView
@@ -55,16 +55,10 @@
android:layout_centerHorizontal="true"/>
</RelativeLayout>
- <com.android.internal.widget.RecyclerView
+ <com.android.internal.widget.ViewPager
+ android:id="@+id/profile_pager"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layoutManager="com.android.internal.widget.GridLayoutManager"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:background="?attr/colorBackgroundFloating"
- android:scrollbars="none"
- android:elevation="1dp"
- android:nestedScrollingEnabled="true"/>
+ android:layout_height="wrap_content"/>
<TextView android:id="@+id/empty"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/chooser_list_per_profile.xml b/core/res/res/layout/chooser_list_per_profile.xml
new file mode 100644
index 000000000000..212813f10bd4
--- /dev/null
+++ b/core/res/res/layout/chooser_list_per_profile.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<com.android.internal.widget.RecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layoutManager="com.android.internal.widget.GridLayoutManager"
+ android:id="@+id/resolver_list"
+ android:clipToPadding="false"
+ android:background="?attr/colorBackgroundFloating"
+ android:scrollbars="none"
+ android:elevation="1dp"
+ android:nestedScrollingEnabled="true"/> \ No newline at end of file
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 6e45e7a4c509..c5d891254227 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -63,25 +63,22 @@
</RelativeLayout>
<View
+ android:id="@+id/divider"
android:layout_alwaysShow="true"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
- <ListView
+
+ <com.android.internal.app.WrapHeightViewPager
+ android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="@dimen/resolver_elevation"
- android:nestedScrollingEnabled="true"
- android:scrollbarStyle="outsideOverlay"
- android:scrollIndicators="top|bottom"
android:divider="?attr/dividerVertical"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
- android:dividerHeight="1dp" />
+ android:dividerHeight="1dp"/>
+
<View
android:layout_alwaysShow="true"
android:layout_width="match_parent"
@@ -89,7 +86,6 @@
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
-
<TextView android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/layout/resolver_list_per_profile.xml b/core/res/res/layout/resolver_list_per_profile.xml
new file mode 100644
index 000000000000..68b991755e73
--- /dev/null
+++ b/core/res/res/layout/resolver_list_per_profile.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<ListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/resolver_list"
+ android:clipToPadding="false"
+ android:background="?attr/colorBackgroundFloating"
+ android:elevation="@dimen/resolver_elevation"
+ android:nestedScrollingEnabled="true"
+ android:scrollbarStyle="outsideOverlay"
+ android:scrollIndicators="top|bottom"
+ android:divider="?attr/dividerVertical"
+ android:footerDividersEnabled="false"
+ android:headerDividersEnabled="false"
+ android:dividerHeight="1dp" /> \ No newline at end of file
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index dbba0b7bcc25..5b3d929d23a5 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -144,25 +144,21 @@
</LinearLayout>
<View
+ android:id="@+id/divider"
android:layout_alwaysShow="true"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
- <ListView
+
+ <com.android.internal.app.WrapHeightViewPager
+ android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="@dimen/resolver_elevation"
- android:nestedScrollingEnabled="true"
- android:scrollbarStyle="outsideOverlay"
- android:scrollIndicators="top|bottom"
+ android:dividerHeight="1dp"
android:divider="?attr/dividerVertical"
android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"
- android:dividerHeight="1dp" />
+ android:headerDividersEnabled="false"/>
<View
android:layout_alwaysShow="true"
android:layout_width="match_parent"
diff --git a/core/res/res/values-sw600dp/bools.xml b/core/res/res/values-sw600dp/bools.xml
index 00f45c1512a2..b3397179b5c8 100644
--- a/core/res/res/values-sw600dp/bools.xml
+++ b/core/res/res/values-sw600dp/bools.xml
@@ -15,7 +15,6 @@
-->
<resources>
- <bool name="target_honeycomb_needs_options_menu">false</bool>
<bool name="show_ongoing_ime_switcher">true</bool>
<bool name="kg_share_status_area">false</bool>
<bool name="kg_sim_puk_account_full_screen">false</bool>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 655d4dde5e57..3ecb1dddd916 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -42,8 +42,4 @@
<!-- Allow SystemUI to show the shutdown dialog -->
<bool name="config_showSysuiShutdown">true</bool>
-
- <!-- The time in milliseconds of prolonged user inactivity after which device goes to sleep,
- even if wakelocks are held. On TVs, this defaults to 4 hours. -->
- <integer name="config_attentiveTimeout">14400000</integer>
</resources>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index b49fe49c087b..29f9f6c2d736 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -23,7 +23,6 @@
<bool name="preferences_prefer_dual_pane">false</bool>
<bool name="show_ongoing_ime_switcher">true</bool>
<bool name="action_bar_expanded_action_views_exclusive">true</bool>
- <bool name="target_honeycomb_needs_options_menu">true</bool>
<!-- Whether or not to use the drawable/lockscreen_notselected and
drawable/lockscreen_selected instead of the generic dots when displaying
the LockPatternView.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bfbd959df1a8..ced5deb66899 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4185,4 +4185,18 @@
<!-- The package name for the default bug report handler app from power menu short press. This app must be whitelisted. -->
<string name="config_defaultBugReportHandlerApp" translatable="false"></string>
+
+ <!-- The default value used for RawContacts.ACCOUNT_NAME when contacts are inserted without this
+ column set. These contacts are stored locally on the device and will not be removed even
+ if an android.account.Account with this name and type exists. A null string will be used
+ if the value is left empty. When this is non-empty then config_rawContactsLocalAccountType
+ should also be non-empty. -->
+ <string name="config_rawContactsLocalAccountName" translatable="false"></string>
+
+ <!-- The default value used for RawContacts.ACCOUNT_TYPE when contacts are inserted without this
+ column set. These contacts are stored locally on the device and will not be removed even
+ if an android.account.Account with this name and type exists. A null string will be used
+ if the value is left empty. When this is non-empty then config_rawContactsLocalAccountName
+ should also be non-empty.-->
+ <string name="config_rawContactsLocalAccountType" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ee9287c7d64c..29b92817c67a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -247,6 +247,7 @@
<java-symbol type="id" name="mic" />
<java-symbol type="id" name="overlay" />
<java-symbol type="id" name="app_ops" />
+ <java-symbol type="id" name="profile_pager" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -1533,6 +1534,8 @@
<java-symbol type="layout" name="user_switching_dialog" />
<java-symbol type="layout" name="common_tab_settings" />
<java-symbol type="layout" name="notification_material_media_seekbar" />
+ <java-symbol type="layout" name="resolver_list_per_profile" />
+ <java-symbol type="layout" name="chooser_list_per_profile" />
<java-symbol type="anim" name="slide_in_child_bottom" />
<java-symbol type="anim" name="slide_in_right" />
@@ -1657,7 +1660,6 @@
<java-symbol type="bool" name="config_perDisplayFocusEnabled" />
<java-symbol type="bool" name="config_showNavigationBar" />
<java-symbol type="bool" name="config_supportAutoRotation" />
- <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
<java-symbol type="dimen" name="docked_stack_divider_thickness" />
<java-symbol type="dimen" name="docked_stack_divider_insets" />
<java-symbol type="dimen" name="docked_stack_minimize_thickness" />
@@ -3768,4 +3770,8 @@
<java-symbol type="string" name="accessibility_system_action_toggle_split_screen_label" />
<java-symbol type="string" name="accessibility_freeform_caption" />
+
+ <!-- For contacts provider. -->
+ <java-symbol type="string" name="config_rawContactsLocalAccountName" />
+ <java-symbol type="string" name="config_rawContactsLocalAccountType" />
</resources>
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index a4c504b9cbdf..c009f588f8a9 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -74,7 +74,6 @@ java_genrule {
":FrameworksCoreTests_install_loc_internal",
":FrameworksCoreTests_install_loc_sdcard",
":FrameworksCoreTests_install_loc_unspecified",
- ":FrameworksCoreTests_install_multi_package",
":FrameworksCoreTests_install_split_base",
":FrameworksCoreTests_install_split_feature_a",
":FrameworksCoreTests_install_use_perm_good",
diff --git a/core/tests/coretests/apks/install_multi_package/Android.bp b/core/tests/coretests/apks/install_multi_package/Android.bp
deleted file mode 100644
index 249242e239e4..000000000000
--- a/core/tests/coretests/apks/install_multi_package/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-android_test_helper_app {
- name: "FrameworksCoreTests_install_multi_package",
- defaults: ["FrameworksCoreTests_apks_defaults"],
-
- srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml b/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
deleted file mode 100644
index 5164cae9e5c0..000000000000
--- a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.coretests.install_multi_package">
-
-<!--
- This manifest is has child packages with components.
--->
-
- <uses-feature
- android:name="com.android.frameworks.coretests.nonexistent" />
- <uses-configuration
- android:reqFiveWayNav="false" />
-
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.frameworks.coretests"
- android:label="Frameworks Core Tests" />
-
- <permission
- android:label="test permission"
- android:name="test_permission"
- android:protectionLevel="normal" />
- <uses-permission android:name="android.permission.INTERNET" />
-
-<!--
- NOTE: This declares a child package, application, then another child
- package, to test potential bugs that are order-dependent. Also, each
- one varies the order.
--->
-
- <package package="com.android.frameworks.coretests.install_multi_package.first_child">
- <uses-permission android:name="android.permission.NFC" />
- <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
- <permission
- android:label="test permission"
- android:name="first_child_permission"
- android:protectionLevel="signature" />
- <application
- android:hasCode="true">
- <activity
- android:name="com.android.frameworks.coretests.FirstChildTestActivity">
- </activity>
- <provider
- android:name="com.android.frameworks.coretests.FirstChildTestProvider"
- android:authorities="com.android.frameworks.coretests.testprovider" />
- <receiver
- android:name="com.android.frameworks.coretests.FirstChildTestReceiver" />
- <service
- android:name="com.android.frameworks.coretests.FirstChildTestService" />
- </application>
- </package>
-
- <application
- android:hasCode="true">
- <service
- android:name="com.android.frameworks.coretests.TestService" />
- <activity
- android:name="com.android.frameworks.coretests.TestActivity">
- </activity>
- <provider
- android:name="com.android.frameworks.coretests.TestProvider"
- android:authorities="com.android.frameworks.coretests.testprovider" />
- <receiver
- android:name="com.android.frameworks.coretests.TestReceiver" />
- </application>
-
- <package package="com.android.frameworks.coretests.blah.second_child">
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" />
- <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
- <permission
- android:label="test permission"
- android:name="second_child_permission"
- android:protectionLevel="dangerous" />
- <application
- android:hasCode="true">
- <receiver
- android:name="com.android.frameworks.coretests.SecondChildTestReceiver" />
- <service
- android:name="com.android.frameworks.coretests.SecondChildTestService" />
- <activity
- android:name="com.android.frameworks.coretests.SecondChildTestActivity">
- </activity>
- <provider
- android:name="com.android.frameworks.coretests.SecondChildTestProvider"
- android:authorities="com.android.frameworks.coretests.testprovider" />
- </application>
- </package>
-</manifest>
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
deleted file mode 100644
index 57afcb0e1a0d..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Activity;
-
-public class FirstChildTestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
deleted file mode 100644
index 2816865b2f1f..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class FirstChildTestProvider extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- return null;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
deleted file mode 100644
index ffe84b73dd37..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class FirstChildTestReceiver extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- return null;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
deleted file mode 100644
index e89f26489959..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Activity;
-
-public class SecondChildTestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
deleted file mode 100644
index 2bd40a5df94d..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class SecondChildTestProvider extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- return null;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
deleted file mode 100644
index a6c4ddc90c6a..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class SecondChildTestReceiver extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- return null;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
deleted file mode 100644
index 1e721aa8ae5b..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class SecondChildTestService extends Service {
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
deleted file mode 100644
index 59f9f10c6efe..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestProvider extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- return null;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
deleted file mode 100644
index 21f6263a38bc..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestReceiver extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- return null;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
deleted file mode 100644
index b330e75308f9..000000000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class TestService extends Service {
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
deleted file mode 100644
index cc48239c4526..000000000000
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link AndroidHidlUpdater}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
- private static final String OTHER_LIBRARY = "other.library";
-
- @Test
- public void targeted_at_P() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.P);
-
- // no change, not system
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_P_system() {
- PackageBuilder before = builder().asSystemApp()
- .targetSdkVersion(Build.VERSION_CODES.P);
-
- // Should add both HIDL libraries
- PackageBuilder after = builder().asSystemApp()
- .targetSdkVersion(Build.VERSION_CODES.P)
- .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_P_not_empty_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.P)
- .requiredLibraries(OTHER_LIBRARY);
-
- // no change, not system
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_P_not_empty_usesLibraries_system() {
- PackageBuilder before = builder().asSystemApp()
- .targetSdkVersion(Build.VERSION_CODES.P)
- .requiredLibraries(OTHER_LIBRARY);
-
- // The hidl jars should be added at the start of the list because it
- // is not on the bootclasspath and the package targets pre-P.
- PackageBuilder after = builder().asSystemApp()
- .targetSdkVersion(Build.VERSION_CODES.P)
- .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_P_in_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.P)
- .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.P);
-
- // Libraries are removed because they are not available for non-system apps
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_P_in_usesLibraries_system() {
- PackageBuilder before = builder().asSystemApp()
- .targetSdkVersion(Build.VERSION_CODES.P)
- .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
- // No change is required because the package explicitly requests the HIDL libraries
- // and is targeted at the current version so does not need backwards compatibility.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void in_usesLibraries() {
- PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE);
-
- // Dependency is removed, it is not available.
- PackageBuilder after = builder();
-
- // Libraries are removed because they are not available for apps targetting Q+
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void in_usesOptionalLibraries() {
- PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE);
-
- // Dependency is removed, it is not available.
- PackageBuilder after = builder();
-
- // Libraries are removed because they are not available for apps targetting Q+
- checkBackwardsCompatibility(before, after);
- }
-
- private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
- checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
deleted file mode 100644
index 03108ced4816..000000000000
--- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test for {@link AndroidTestBaseUpdater}
- */
-@SmallTest
-@RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.AndroidTestBaseUpdater")
-public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
- private static final String OTHER_LIBRARY = "other.library";
-
- @Test
- public void targeted_at_Q() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.Q);
-
- // Should add org.apache.http.legacy.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.Q)
- .requiredLibraries(ANDROID_TEST_BASE);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_Q_not_empty_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.Q)
- .requiredLibraries(OTHER_LIBRARY);
-
- // The org.apache.http.legacy jar should be added at the start of the list because it
- // is not on the bootclasspath and the package targets pre-Q.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.Q)
- .requiredLibraries(ANDROID_TEST_BASE, OTHER_LIBRARY);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_Q_in_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.Q)
- .requiredLibraries(ANDROID_TEST_BASE);
-
- // No change is required because although org.apache.http.legacy has been removed from
- // the bootclasspath the package explicitly requests it.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_Q_in_usesOptionalLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.Q)
- .optionalLibraries(ANDROID_TEST_BASE);
-
- // No change is required because although org.apache.http.legacy has been removed from
- // the bootclasspath the package explicitly requests it.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void in_usesLibraries() {
- PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE);
-
- // No change is required because the package explicitly requests org.apache.http.legacy
- // and is targeted at the current version so does not need backwards compatibility.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void in_usesOptionalLibraries() {
- PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE);
-
- // No change is required because the package explicitly requests org.apache.http.legacy
- // and is targeted at the current version so does not need backwards compatibility.
- checkBackwardsCompatibility(before, before);
- }
-
- private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
- checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
deleted file mode 100644
index 7f817d66caf7..000000000000
--- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-
-import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link AndroidTestRunnerSplitUpdater}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
- @Test
- public void android_test_runner_in_usesOptionalLibraries() {
- PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_RUNNER);
-
- PackageBuilder after = builder()
- .optionalLibraries(ANDROID_TEST_MOCK, ANDROID_TEST_RUNNER);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
- PackageBuilder before = builder()
- .requiredLibraries(ANDROID_TEST_RUNNER)
- .optionalLibraries(ANDROID_TEST_MOCK);
-
- PackageBuilder after = builder()
- .requiredLibraries(ANDROID_TEST_RUNNER)
- .optionalLibraries(ANDROID_TEST_MOCK);
-
- checkBackwardsCompatibility(before, after);
- }
-
- private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
- checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
deleted file mode 100644
index 834a0bbeab89..000000000000
--- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test for {@link OrgApacheHttpLegacyUpdater}
- */
-@SmallTest
-@RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.OrgApacheHttpLegacyUpdater")
-public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
- private static final String OTHER_LIBRARY = "other.library";
-
- @Test
- public void targeted_at_O() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
-
- // Should add org.apache.http.legacy.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_O_not_empty_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(OTHER_LIBRARY);
-
- // The org.apache.http.legacy jar should be added at the start of the list because it
- // is not on the bootclasspath and the package targets pre-P.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_O_in_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // No change is required because although org.apache.http.legacy has been removed from
- // the bootclasspath the package explicitly requests it.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_O_in_usesOptionalLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // No change is required because although org.apache.http.legacy has been removed from
- // the bootclasspath the package explicitly requests it.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void in_usesLibraries() {
- PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // No change is required because the package explicitly requests org.apache.http.legacy
- // and is targeted at the current version so does not need backwards compatibility.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void in_usesOptionalLibraries() {
- PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // No change is required because the package explicitly requests org.apache.http.legacy
- // and is targeted at the current version so does not need backwards compatibility.
- checkBackwardsCompatibility(before, before);
- }
-
- private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
- checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
deleted file mode 100644
index f7544af43461..000000000000
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Build;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Test support for building {@link PackageParser.Package} instances.
- */
-class PackageBuilder {
-
- private int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
-
- private int mFlags = 0;
-
- private ArrayList<String> mRequiredLibraries;
-
- private ArrayList<String> mOptionalLibraries;
-
- public static PackageBuilder builder() {
- return new PackageBuilder();
- }
-
- public PackageParser.Package build() {
- PackageParser.Package pkg = new PackageParser.Package("org.package.name");
- pkg.applicationInfo.targetSdkVersion = mTargetSdkVersion;
- pkg.applicationInfo.flags = mFlags;
- pkg.usesLibraries = mRequiredLibraries;
- pkg.usesOptionalLibraries = mOptionalLibraries;
- return pkg;
- }
-
- PackageBuilder targetSdkVersion(int version) {
- this.mTargetSdkVersion = version;
- return this;
- }
-
- PackageBuilder asSystemApp() {
- this.mFlags |= ApplicationInfo.FLAG_SYSTEM;
- return this;
- }
-
- PackageBuilder requiredLibraries(String... names) {
- this.mRequiredLibraries = arrayListOrNull(names);
- return this;
- }
-
- PackageBuilder requiredLibraries(List<String> names) {
- this.mRequiredLibraries = arrayListOrNull(names.toArray(new String[names.size()]));
- return this;
- }
-
- PackageBuilder optionalLibraries(String... names) {
- this.mOptionalLibraries = arrayListOrNull(names);
- return this;
- }
-
- /**
- * Check that this matches the supplied {@link PackageParser.Package}.
- *
- * @param pkg the instance to compare with this.
- */
- public void check(PackageParser.Package pkg) {
- assertEquals("targetSdkVersion should not be changed",
- mTargetSdkVersion,
- pkg.applicationInfo.targetSdkVersion);
- assertEquals("usesLibraries not updated correctly",
- mRequiredLibraries,
- pkg.usesLibraries);
- assertEquals("usesOptionalLibraries not updated correctly",
- mOptionalLibraries,
- pkg.usesOptionalLibraries);
- }
-
- private static ArrayList<String> arrayListOrNull(String... strings) {
- if (strings == null || strings.length == 0) {
- return null;
- }
- ArrayList<String> list = new ArrayList<>();
- Collections.addAll(list, strings);
- return list;
- }
-
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 5c7f2af782b9..440219018b92 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -23,26 +23,26 @@ import static org.junit.Assert.assertTrue;
import android.apex.ApexInfo;
import android.content.Context;
-import android.content.pm.PackageParser.Component;
-import android.content.pm.PackageParser.Package;
-import android.content.pm.PackageParser.Permission;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ParsedPackage;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
-import android.os.SystemProperties;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
+import com.android.internal.util.ArrayUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.InputStream;
-import java.util.Arrays;
import java.util.function.Function;
@SmallTest
@@ -59,8 +59,8 @@ public class PackageParserTest {
private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint";
private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint";
- private static final String[] CODENAMES_RELEASED = { /* empty */ };
- private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE };
+ private static final String[] CODENAMES_RELEASED = { /* empty */};
+ private static final String[] CODENAMES_PRE_RELEASE = {PRE_RELEASE};
private static final int OLDER_VERSION = 10;
private static final int PLATFORM_VERSION = 20;
@@ -300,10 +300,6 @@ public class PackageParserTest {
assertEquals(0x0083, finalConfigChanges); // Should be 10000011.
}
- Package parsePackage(String apkFileName, int apkResourceId) throws Exception {
- return parsePackage(apkFileName, apkResourceId, p -> p);
- }
-
/**
* Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy
* succeeded, or {@code null} otherwise.
@@ -331,16 +327,17 @@ public class PackageParserTest {
*
* APKs are put into coretests/apks/packageparser_*.
*
- * @param apkFileName temporary file name to store apk extracted from resources
+ * @param apkFileName temporary file name to store apk extracted from resources
* @param apkResourceId identifier of the apk as a resource
*/
- Package parsePackage(String apkFileName, int apkResourceId,
- Function<Package, Package> converter) throws Exception {
+ ParsedPackage parsePackage(String apkFileName, int apkResourceId,
+ Function<ParsedPackage, ParsedPackage> converter) throws Exception {
// Copy the resource to a file.
File outFile = null;
try {
outFile = copyRawResourceToFile(apkFileName, apkResourceId);
- return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */));
+ return converter.apply(
+ new PackageParser().parseParsedPackage(outFile, 0 /* flags */, false));
} finally {
if (outFile != null) {
outFile.delete();
@@ -351,40 +348,35 @@ public class PackageParserTest {
/**
* Asserts basic properties about a component.
*/
- private void assertComponent(String className, String packageName, int numIntents,
- Component<?> component) {
+ private void assertComponent(String className, int numIntents, ParsedComponent<?> component) {
assertEquals(className, component.className);
- assertEquals(packageName, component.owner.packageName);
assertEquals(numIntents, component.intents.size());
}
/**
* Asserts four regularly-named components of each type: one Activity, one Service, one
* Provider, and one Receiver.
+ *
* @param template templated string with %s subbed with Activity, Service, Provider, Receiver
*/
- private void assertOneComponentOfEachType(String template, Package p) {
- String packageName = p.packageName;
-
- assertEquals(1, p.activities.size());
+ private void assertOneComponentOfEachType(String template, AndroidPackage p) {
+ assertEquals(1, p.getActivities().size());
assertComponent(String.format(template, "Activity"),
- packageName, 0 /* intents */, p.activities.get(0));
- assertEquals(1, p.services.size());
+ 0 /* intents */, p.getActivities().get(0));
+ assertEquals(1, p.getServices().size());
assertComponent(String.format(template, "Service"),
- packageName, 0 /* intents */, p.services.get(0));
- assertEquals(1, p.providers.size());
+ 0 /* intents */, p.getServices().get(0));
+ assertEquals(1, p.getProviders().size());
assertComponent(String.format(template, "Provider"),
- packageName, 0 /* intents */, p.providers.get(0));
- assertEquals(1, p.receivers.size());
+ 0 /* intents */, p.getProviders().get(0));
+ assertEquals(1, p.getReceivers().size());
assertComponent(String.format(template, "Receiver"),
- packageName, 0 /* intents */, p.receivers.get(0));
+ 0 /* intents */, p.getReceivers().get(0));
}
- private void assertPermission(String name, String packageName, int protectionLevel,
- Permission permission) {
- assertEquals(packageName, permission.owner.packageName);
- assertEquals(name, permission.info.name);
- assertEquals(protectionLevel, permission.info.protectionLevel);
+ private void assertPermission(String name, int protectionLevel, ParsedPermission permission) {
+ assertEquals(name, permission.getName());
+ assertEquals(protectionLevel, permission.getProtection());
}
private void assertMetadata(Bundle b, String... keysAndValues) {
@@ -416,25 +408,25 @@ public class PackageParserTest {
}
private void checkPackageWithComponents(
- Function<Package, Package> converter) throws Exception {
- Package p = parsePackage(
+ Function<ParsedPackage, ParsedPackage> converter) throws Exception {
+ ParsedPackage p = parsePackage(
"install_complete_package_info.apk", R.raw.install_complete_package_info,
converter);
String packageName = "com.android.frameworks.coretests.install_complete_package_info";
- assertEquals(packageName, p.packageName);
- assertEquals(1, p.permissions.size());
+ assertEquals(packageName, p.getPackageName());
+ assertEquals(1, p.getPermissions().size());
assertPermission(
"com.android.frameworks.coretests.install_complete_package_info.test_permission",
- packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0));
+ PermissionInfo.PROTECTION_NORMAL, p.getPermissions().get(0));
// Hidden "app details" activity is added to every package.
boolean foundAppDetailsActivity = false;
- for (int i = 0; i < p.activities.size(); i++) {
- if (p.activities.get(i).className.equals(
+ for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) {
+ if (p.getActivities().get(i).className.equals(
PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) {
foundAppDetailsActivity = true;
- p.activities.remove(i);
+ p.getActivities().remove(i);
break;
}
}
@@ -442,72 +434,23 @@ public class PackageParserTest {
assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
- assertMetadata(p.mAppMetaData,
+ assertMetadata(p.getAppMetaData(),
"key1", "value1",
"key2", "this_is_app");
- assertMetadata(p.activities.get(0).metaData,
+ assertMetadata(p.getActivities().get(0).getMetaData(),
"key1", "value1",
"key2", "this_is_activity");
- assertMetadata(p.services.get(0).metaData,
+ assertMetadata(p.getServices().get(0).getMetaData(),
"key1", "value1",
"key2", "this_is_service");
- assertMetadata(p.receivers.get(0).metaData,
+ assertMetadata(p.getReceivers().get(0).getMetaData(),
"key1", "value1",
"key2", "this_is_receiver");
- assertMetadata(p.providers.get(0).metaData,
+ assertMetadata(p.getProviders().get(0).getMetaData(),
"key1", "value1",
"key2", "this_is_provider");
}
- /**
- * Determines if the current device supports multi-package APKs.
- */
- private boolean supportsMultiPackageApk() {
- return SystemProperties.getBoolean("persist.sys.child_packages_enabled", false);
- }
-
- @Test
- public void testMultiPackageComponents() throws Exception {
- // TODO(gboyer): Remove once we decide to launch multi-package APKs.
- if (!supportsMultiPackageApk()) {
- return;
- }
- String parentName = "com.android.frameworks.coretests.install_multi_package";
- String firstChildName =
- "com.android.frameworks.coretests.install_multi_package.first_child";
- String secondChildName = // NOTE: intentionally inconsistent!
- "com.android.frameworks.coretests.blah.second_child";
-
- Package parent = parsePackage("install_multi_package.apk", R.raw.install_multi_package);
- assertEquals(parentName, parent.packageName);
- assertEquals(2, parent.childPackages.size());
- assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", parent);
- assertEquals(1, parent.permissions.size());
- assertPermission(parentName + ".test_permission", parentName,
- PermissionInfo.PROTECTION_NORMAL, parent.permissions.get(0));
- assertEquals(Arrays.asList("android.permission.INTERNET"),
- parent.requestedPermissions);
-
- Package firstChild = parent.childPackages.get(0);
- assertEquals(firstChildName, firstChild.packageName);
- assertOneComponentOfEachType(
- "com.android.frameworks.coretests.FirstChildTest%s", firstChild);
- assertEquals(0, firstChild.permissions.size()); // Child APKs cannot declare permissions.
- assertEquals(Arrays.asList("android.permission.NFC"),
- firstChild.requestedPermissions);
-
- Package secondChild = parent.childPackages.get(1);
- assertEquals(secondChildName, secondChild.packageName);
- assertOneComponentOfEachType(
- "com.android.frameworks.coretests.SecondChildTest%s", secondChild);
- assertEquals(0, secondChild.permissions.size()); // Child APKs cannot declare permissions.
- assertEquals(
- Arrays.asList(
- "android.permission.ACCESS_NETWORK_STATE",
- "android.permission.READ_CONTACTS"),
- secondChild.requestedPermissions);
- }
-
@Test
public void testApexPackageInfoGeneration() throws Exception {
String apexModuleName = "com.android.tzdata.apex";
@@ -522,7 +465,7 @@ public class PackageParserTest {
int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
PackageParser pp = new PackageParser();
- Package p = pp.parsePackage(apexFile, flags, false);
+ PackageParser.Package p = pp.parsePackage(apexFile, flags, false);
PackageParser.collectCertificates(p, false);
PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);
diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
deleted file mode 100644
index 71a0e5e51b71..000000000000
--- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import java.util.function.Supplier;
-
-/**
- * Helper for classes that test {@link PackageSharedLibraryUpdater}.
- */
-abstract class PackageSharedLibraryUpdaterTest {
-
- static void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after,
- Supplier<PackageSharedLibraryUpdater> updaterSupplier) {
- PackageParser.Package pkg = before.build();
- updaterSupplier.get().updatePackage(pkg);
- after.check(pkg);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
deleted file mode 100644
index 216b0c8950b7..000000000000
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class RemoveUnnecessaryAndroidTestBaseLibraryTest
- extends PackageSharedLibraryUpdaterTest {
-
- private static final String OTHER_LIBRARY = "other.library";
-
- @Test
- public void targeted_at_O() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
-
- // No change required.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_O_not_empty_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(OTHER_LIBRARY);
-
- // No change required.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_O_in_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(ANDROID_TEST_BASE);
-
- // android.test.base should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_O_in_usesOptionalLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .optionalLibraries(ANDROID_TEST_BASE);
-
- // android.test.base should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void in_usesLibraries() {
- PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE);
-
- // android.test.base should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void in_usesOptionalLibraries() {
- PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE);
-
- // android.test.base should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void in_bothLibraries() {
- PackageBuilder before = builder()
- .requiredLibraries(ANDROID_TEST_BASE)
- .optionalLibraries(ANDROID_TEST_BASE);
-
- // android.test.base should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
-
- checkBackwardsCompatibility(before, after);
- }
-
- private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
- // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
- // PackageBackwardCompatibility and that seems to create a package-private lambda in
- // android.content.pm which this then tries to reuse but fails because it cannot access
- // package-private classes/members because the test is loaded by a different ClassLoader
- // than the lambda.
- checkBackwardsCompatibility(before, after,
- () -> new RemoveUnnecessaryAndroidTestBaseLibrary());
- }
-
-}
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
deleted file mode 100644
index fc60980bb796..000000000000
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
- extends PackageSharedLibraryUpdaterTest {
-
- private static final String OTHER_LIBRARY = "other.library";
-
- @Test
- public void targeted_at_O() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
-
- // No change required.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_O_not_empty_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(OTHER_LIBRARY);
-
- // No change required.
- checkBackwardsCompatibility(before, before);
- }
-
- @Test
- public void targeted_at_O_in_usesLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // org.apache.http.legacy should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void targeted_at_O_in_usesOptionalLibraries() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // org.apache.http.legacy should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void in_usesLibraries() {
- PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // org.apache.http.legacy should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void in_usesOptionalLibraries() {
- PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // org.apache.http.legacy should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
-
- checkBackwardsCompatibility(before, after);
- }
-
- @Test
- public void in_bothLibraries() {
- PackageBuilder before = builder()
- .requiredLibraries(ORG_APACHE_HTTP_LEGACY)
- .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // org.apache.http.legacy should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
-
- checkBackwardsCompatibility(before, after);
- }
-
- private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
- // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
- // PackageBackwardCompatibility and that seems to create a package-private lambda in
- // android.content.pm which this then tries to reuse but fails because it cannot access
- // package-private classes/members because the test is loaded by a different ClassLoader
- // than the lambda.
- checkBackwardsCompatibility(before, after,
- () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary());
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 49849ee72a18..1e0bfb08693f 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -25,9 +25,9 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
-import android.content.pm.PackageParser.Package;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.ParsedPackage;
import android.os.FileUtils;
import androidx.test.InstrumentationRegistry;
@@ -36,7 +36,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
-import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -95,13 +94,13 @@ public class DexMetadataHelperTest {
public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk");
- Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+ ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
assertEquals(1, packageDexMetadata.size());
- String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+ String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
assertNotNull(baseDexMetadata);
- assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+ assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
}
@Test
@@ -111,17 +110,17 @@ public class DexMetadataHelperTest {
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_base.apk");
createDexMetadataFile("install_split_feature_a.apk");
- Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+ ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
assertEquals(2, packageDexMetadata.size());
- String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+ String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
assertNotNull(baseDexMetadata);
- assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+ assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
- String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+ String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
assertNotNull(splitDexMetadata);
- assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+ assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
}
@Test
@@ -130,14 +129,14 @@ public class DexMetadataHelperTest {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_feature_a.apk");
- Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+ ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
assertEquals(1, packageDexMetadata.size());
- String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+ String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
assertNotNull(splitDexMetadata);
- assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+ assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
}
@Test
@@ -146,7 +145,8 @@ public class DexMetadataHelperTest {
File invalidDmFile = new File(mTmpDir, "install_split_base.dm");
Files.createFile(invalidDmFile.toPath());
try {
- PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+ ParsedPackage pkg = new PackageParser()
+ .parseParsedPackage(mTmpDir, 0 /* flags */, false);
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
@@ -163,7 +163,8 @@ public class DexMetadataHelperTest {
Files.createFile(invalidDmFile.toPath());
try {
- PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+ ParsedPackage pkg = new PackageParser()
+ .parseParsedPackage(mTmpDir, 0 /* flags */, false);
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
new file mode 100644
index 000000000000..21479c096752
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidHidlUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+ private static final String OTHER_LIBRARY = "other.library";
+
+ @Test
+ public void targeted_at_P() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // no change, not system
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_P_system() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .hideAsParsed()
+ .setSystem(true);
+
+ // Should add both HIDL libraries
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(ANDROID_HIDL_MANAGER)
+ .addUsesLibrary(ANDROID_HIDL_BASE)
+ .hideAsParsed()
+ .setSystem(true)
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_P_not_empty_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // no change, not system
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_P_not_empty_usesLibraries_system() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed()
+ .setSystem(true);
+
+ // The hidl jars should be added at the start of the list because it
+ // is not on the bootclasspath and the package targets pre-P.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(ANDROID_HIDL_MANAGER)
+ .addUsesLibrary(ANDROID_HIDL_BASE)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed()
+ .setSystem(true)
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_P_in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(ANDROID_HIDL_MANAGER)
+ .addUsesLibrary(ANDROID_HIDL_BASE)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // Libraries are removed because they are not available for non-system apps
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_P_in_usesLibraries_system() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(ANDROID_HIDL_MANAGER)
+ .addUsesLibrary(ANDROID_HIDL_BASE)
+ .hideAsParsed()
+ .setSystem(true);
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.P)
+ .addUsesLibrary(ANDROID_HIDL_MANAGER)
+ .addUsesLibrary(ANDROID_HIDL_BASE)
+ .hideAsParsed()
+ .setSystem(true)
+ .hideAsFinal();
+
+ // No change is required because the package explicitly requests the HIDL libraries
+ // and is targeted at the current version so does not need backwards compatibility.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_HIDL_BASE)
+ .hideAsParsed();
+
+ // Dependency is removed, it is not available.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // Libraries are removed because they are not available for apps targeting Q+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ANDROID_HIDL_BASE)
+ .hideAsParsed();
+
+ // Dependency is removed, it is not available.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // Libraries are removed because they are not available for apps targeting Q+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+ checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
new file mode 100644
index 000000000000..65ae219058f4
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+
+import android.content.pm.OptionalClassRunner;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link AndroidTestBaseUpdater}
+ */
+@SmallTest
+@RunWith(OptionalClassRunner.class)
+@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.AndroidTestBaseUpdater")
+public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+ private static final String OTHER_LIBRARY = "other.library";
+
+ @Test
+ public void targeted_at_Q() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .hideAsParsed();
+
+ // Should add org.apache.http.legacy.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_Q_not_empty_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed();
+
+ // The org.apache.http.legacy jar should be added at the start of the list because it
+ // is not on the bootclasspath and the package targets pre-Q.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_Q_in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because although org.apache.http.legacy has been removed from
+ // the bootclasspath the package explicitly requests it.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_Q_in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.Q)
+ .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because although org.apache.http.legacy has been removed from
+ // the bootclasspath the package explicitly requests it.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because the package explicitly requests org.apache.http.legacy
+ // and is targeted at the current version so does not need backwards compatibility.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because the package explicitly requests org.apache.http.legacy
+ // and is targeted at the current version so does not need backwards compatibility.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+ checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
new file mode 100644
index 000000000000..38755b9aa965
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidTestRunnerSplitUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+ @Test
+ public void android_test_runner_in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+ .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_TEST_RUNNER)
+ .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_TEST_RUNNER)
+ .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+ checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
new file mode 100644
index 000000000000..4c7899b47164
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.OptionalClassRunner;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link OrgApacheHttpLegacyUpdater}
+ */
+@SmallTest
+@RunWith(OptionalClassRunner.class)
+@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater")
+public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+ private static final String OTHER_LIBRARY = "other.library";
+
+ @Test
+ public void targeted_at_O() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed();
+
+ // Should add org.apache.http.legacy.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_not_empty_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed();
+
+ // The org.apache.http.legacy jar should be added at the start of the list because it
+ // is not on the bootclasspath and the package targets pre-P.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because although org.apache.http.legacy has been removed from
+ // the bootclasspath the package explicitly requests it.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because although org.apache.http.legacy has been removed from
+ // the bootclasspath the package explicitly requests it.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because the package explicitly requests org.apache.http.legacy
+ // and is targeted at the current version so does not need backwards compatibility.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change is required because the package explicitly requests org.apache.http.legacy
+ // and is targeted at the current version so does not need backwards compatibility.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+ checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
index ad9814bd01b1..00d468de4ee4 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-package android.content.pm;
+package android.content.pm.parsing.library;
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
import android.os.Build;
import androidx.test.filters.SmallTest;
@@ -32,17 +35,20 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.ArrayList;
-import java.util.List;
-
@SmallTest
@RunWith(JUnit4.class)
public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest {
@Test
public void null_usesLibraries_and_usesOptionalLibraries() {
- PackageBuilder before = builder();
- PackageBuilder after = builder();
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed()
+ .hideAsFinal();
checkBackwardsCompatibility(before, after);
}
@@ -68,20 +74,21 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate
*/
@Test
public void targeted_at_O() {
- PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed();
+
+ ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .setTargetSdkVersion(Build.VERSION_CODES.O);
- List<String> expected = new ArrayList<>();
if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
- expected.add(ANDROID_TEST_BASE);
+ after.addUsesLibrary(ANDROID_TEST_BASE);
}
- expected.add(ORG_APACHE_HTTP_LEGACY);
-
- PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
- .requiredLibraries(expected);
+ after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY);
- checkBackwardsCompatibility(before, after);
+ checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
}
/**
@@ -98,12 +105,17 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate
+ ANDROID_TEST_BASE + " is on the bootclasspath",
PackageBackwardCompatibility.bootClassPathContainsATB());
- PackageBuilder before = builder()
- .requiredLibraries(ANDROID_TEST_BASE);
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
// android.test.base should be removed from the libraries because it is provided
// on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed()
+ .hideAsFinal();
checkBackwardsCompatibility(before, after);
}
@@ -117,22 +129,23 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate
*/
@Test
public void android_test_runner_in_usesLibraries() {
- PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_RUNNER);
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_TEST_RUNNER)
+ .hideAsParsed();
- List<String> expected = new ArrayList<>();
+ ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT);
if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
- expected.add(ANDROID_TEST_BASE);
+ after.addUsesLibrary(ANDROID_TEST_BASE);
}
- expected.add(ANDROID_TEST_MOCK);
- expected.add(ANDROID_TEST_RUNNER);
-
- PackageBuilder after = builder()
- .requiredLibraries(expected);
+ after.addUsesLibrary(ANDROID_TEST_MOCK);
+ after.addUsesLibrary(ANDROID_TEST_RUNNER);
- checkBackwardsCompatibility(before, after);
+ checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
}
- private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
}
}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
new file mode 100644
index 000000000000..e7a80e1a7618
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
+
+import java.util.function.Supplier;
+
+/**
+ * Helper for classes that test {@link PackageSharedLibraryUpdater}.
+ */
+abstract class PackageSharedLibraryUpdaterTest {
+
+ protected static final String PACKAGE_NAME = "org.package.name";
+
+ static void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after,
+ Supplier<PackageSharedLibraryUpdater> updaterSupplier) {
+ updaterSupplier.get().updatePackage(before);
+ check(before.hideAsFinal(), after);
+ }
+
+ private static void check(AndroidPackage before, AndroidPackage after) {
+ assertEquals("targetSdkVersion should not be changed",
+ after.getTargetSdkVersion(),
+ before.getTargetSdkVersion());
+ assertEquals("usesLibraries not updated correctly",
+ after.getUsesLibraries(),
+ before.getUsesLibraries());
+ assertEquals("usesOptionalLibraries not updated correctly",
+ after.getUsesOptionalLibraries(),
+ before.getUsesOptionalLibraries());
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
new file mode 100644
index 000000000000..fd3ba2bd0c68
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class RemoveUnnecessaryAndroidTestBaseLibraryTest
+ extends PackageSharedLibraryUpdaterTest {
+
+ private static final String OTHER_LIBRARY = "other.library";
+
+ @Test
+ public void targeted_at_O() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change required.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_not_empty_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change required.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ // android.test.base should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ // android.test.base should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ // android.test.base should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ // android.test.base should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_bothLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ANDROID_TEST_BASE)
+ .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+ .hideAsParsed();
+
+ // android.test.base should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+ // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
+ // PackageBackwardCompatibility and that seems to create a package-private lambda in
+ // android.content.pm which this then tries to reuse but fails because it cannot access
+ // package-private classes/members because the test is loaded by a different ClassLoader
+ // than the lambda.
+ checkBackwardsCompatibility(before, after,
+ () -> new RemoveUnnecessaryAndroidTestBaseLibrary());
+ }
+
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
new file mode 100644
index 000000000000..d3494d93ae52
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
+ extends PackageSharedLibraryUpdaterTest {
+
+ private static final String OTHER_LIBRARY = "other.library";
+
+ @Test
+ public void targeted_at_O() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change required.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_not_empty_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed();
+
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(OTHER_LIBRARY)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ // No change required.
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ // org.apache.http.legacy should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ // org.apache.http.legacy should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ // org.apache.http.legacy should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesOptionalLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ // org.apache.http.legacy should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_bothLibraries() {
+ ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+ .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+ .hideAsParsed();
+
+ // org.apache.http.legacy should be removed from the libraries because it is provided
+ // on the bootclasspath and providing both increases start up cost unnecessarily.
+ AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed()
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+ // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
+ // PackageBackwardCompatibility and that seems to create a package-private lambda in
+ // android.content.pm which this then tries to reuse but fails because it cannot access
+ // package-private classes/members because the test is loaded by a different ClassLoader
+ // than the lambda.
+ checkBackwardsCompatibility(before, after,
+ () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary());
+ }
+}
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
index 6cdcb5e542dc..d4861cd391a8 100644
--- a/core/tests/coretests/src/android/util/LocalLogTest.java
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -29,14 +29,24 @@ import java.util.List;
@LargeTest
public class LocalLogTest extends TestCase {
- public void testA() {
+ public void testA_localTimestamps() {
+ boolean localTimestamps = true;
+ doTestA(localTimestamps);
+ }
+
+ public void testA_nonLocalTimestamps() {
+ boolean localTimestamps = false;
+ doTestA(localTimestamps);
+ }
+
+ private void doTestA(boolean localTimestamps) {
String[] lines = {
- "foo",
- "bar",
- "baz"
+ "foo",
+ "bar",
+ "baz"
};
String[] want = lines;
- testcase(new LocalLog(10), lines, want);
+ testcase(new LocalLog(10, localTimestamps), lines, want);
}
public void testB() {
diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/core/tests/coretests/src/android/util/StatsEventTest.java
index 097badadcea9..ac25e2734ac9 100644
--- a/core/tests/coretests/src/android/util/StatsEventTest.java
+++ b/core/tests/coretests/src/android/util/StatsEventTest.java
@@ -44,7 +44,7 @@ public class StatsEventTest {
@Test
public void testNoFields() {
final long minTimestamp = SystemClock.elapsedRealtimeNanos();
- final StatsEvent statsEvent = StatsEvent.newBuilder().build();
+ final StatsEvent statsEvent = StatsEvent.newBuilder().usePooledBuffer().build();
final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
final int expectedAtomId = 0;
@@ -99,6 +99,7 @@ public class StatsEventTest {
.writeBoolean(field2)
.writeInt(field3)
.writeInt(field4)
+ .usePooledBuffer()
.build();
final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
@@ -167,6 +168,7 @@ public class StatsEventTest {
.writeString(field1)
.writeFloat(field2)
.writeByteArray(field3)
+ .usePooledBuffer()
.build();
final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
@@ -230,6 +232,7 @@ public class StatsEventTest {
.setAtomId(expectedAtomId)
.writeAttributionChain(uids, tags)
.writeLong(field2)
+ .usePooledBuffer()
.build();
final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
@@ -299,6 +302,7 @@ public class StatsEventTest {
final StatsEvent statsEvent = StatsEvent.newBuilder()
.setAtomId(expectedAtomId)
.writeKeyValuePairs(intMap, longMap, stringMap, floatMap)
+ .usePooledBuffer()
.build();
final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
@@ -392,6 +396,7 @@ public class StatsEventTest {
.addBooleanAnnotation(field1AnnotationId, field1AnnotationValue)
.writeBoolean(field2)
.addIntAnnotation(field2AnnotationId, field2AnnotationValue)
+ .usePooledBuffer()
.build();
final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
diff --git a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java b/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
deleted file mode 100644
index d54ce51c3c37..000000000000
--- a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.view.textclassifier;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.provider.DeviceConfig;
-import android.support.test.uiautomator.UiDevice;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.util.function.Supplier;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ConfigParserTest {
- private static final Supplier<String> SETTINGS =
- () -> "int=42,float=12.3,boolean=true,string=abc";
- private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
- "device_config delete " + DeviceConfig.NAMESPACE_TEXTCLASSIFIER;
- private static final String[] DEVICE_CONFIG_KEYS = new String[]{
- "boolean",
- "string",
- "int",
- "float"
- };
-
- private ConfigParser mConfigParser;
-
- @Before
- public void setup() throws IOException {
- mConfigParser = new ConfigParser(SETTINGS);
- clearDeviceConfig();
- }
-
- @After
- public void tearDown() throws IOException {
- clearDeviceConfig();
- }
-
- @Test
- public void getBoolean_deviceConfig() {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- "boolean",
- "false",
- false);
- boolean value = mConfigParser.getBoolean("boolean", true);
- assertThat(value).isFalse();
- }
-
- @Test
- public void getBoolean_settings() {
- boolean value = mConfigParser.getBoolean(
- "boolean",
- false);
- assertThat(value).isTrue();
- }
-
- @Test
- public void getInt_deviceConfig() {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- "int",
- "1",
- false);
- int value = mConfigParser.getInt("int", 0);
- assertThat(value).isEqualTo(1);
- }
-
- @Test
- public void getInt_settings() {
- int value = mConfigParser.getInt("int", 0);
- assertThat(value).isEqualTo(42);
- }
-
- @Test
- public void getFloat_deviceConfig() {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- "float",
- "3.14",
- false);
- float value = mConfigParser.getFloat("float", 0);
- assertThat(value).isWithin(0.0001f).of(3.14f);
- }
-
- @Test
- public void getFloat_settings() {
- float value = mConfigParser.getFloat("float", 0);
- assertThat(value).isWithin(0.0001f).of(12.3f);
- }
-
- @Test
- public void getString_deviceConfig() {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- "string",
- "hello",
- false);
- String value = mConfigParser.getString("string", "");
- assertThat(value).isEqualTo("hello");
- }
-
- @Test
- public void getString_settings() {
- String value = mConfigParser.getString("string", "");
- assertThat(value).isEqualTo("abc");
- }
-
- private static void clearDeviceConfig() throws IOException {
- UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- for (String key : DEVICE_CONFIG_KEYS) {
- uiDevice.executeShellCommand(CLEAR_DEVICE_CONFIG_KEY_CMD + " " + key);
- }
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 64fb14190ce2..82fa73f76207 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -16,230 +16,141 @@
package android.view.textclassifier;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import android.provider.DeviceConfig;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Assert;
+import com.google.common.primitives.Floats;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationConstantsTest {
-
private static final float EPSILON = 0.0001f;
@Test
- public void testLoadFromString() {
- final String s = "local_textclassifier_enabled=true,"
- + "system_textclassifier_enabled=true,"
- + "model_dark_launch_enabled=true,"
- + "smart_selection_enabled=true,"
- + "smart_text_share_enabled=true,"
- + "smart_linkify_enabled=true,"
- + "smart_select_animation_enabled=true,"
- + "suggest_selection_max_range_length=10,"
- + "classify_text_max_range_length=11,"
- + "generate_links_max_text_length=12,"
- + "generate_links_log_sample_rate=13,"
- + "entity_list_default=phone,"
- + "entity_list_not_editable=address:flight,"
- + "entity_list_editable=date:datetime,"
- + "in_app_conversation_action_types_default=text_reply,"
- + "notification_conversation_action_types_default=send_email:call_phone,"
- + "lang_id_threshold_override=0.3,"
- + "lang_id_context_settings=10:1:0.5,"
- + "detect_language_from_text_enabled=true,"
- + "template_intent_factory_enabled=true,"
- + "translate_in_classification_enabled=true";
- final TextClassificationConstants constants = new TextClassificationConstants(() -> s);
-
- assertWithMessage("local_textclassifier_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
- assertWithMessage("system_textclassifier_enabled")
- .that(constants.isSystemTextClassifierEnabled()).isTrue();
- assertWithMessage("model_dark_launch_enabled")
- .that(constants.isModelDarkLaunchEnabled()).isTrue();
- assertWithMessage("smart_selection_enabled")
- .that(constants.isSmartSelectionEnabled()).isTrue();
- assertWithMessage("smart_text_share_enabled")
- .that(constants.isSmartTextShareEnabled()).isTrue();
- assertWithMessage("smart_linkify_enabled")
- .that(constants.isSmartLinkifyEnabled()).isTrue();
- assertWithMessage("smart_select_animation_enabled")
- .that(constants.isSmartSelectionAnimationEnabled()).isTrue();
- assertWithMessage("suggest_selection_max_range_length")
- .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10);
- assertWithMessage("classify_text_max_range_length")
- .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(11);
- assertWithMessage("generate_links_max_text_length")
- .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(12);
- assertWithMessage("generate_links_log_sample_rate")
- .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(13);
- assertWithMessage("entity_list_default")
- .that(constants.getEntityListDefault())
- .containsExactly("phone");
- assertWithMessage("entity_list_not_editable")
- .that(constants.getEntityListNotEditable())
- .containsExactly("address", "flight");
- assertWithMessage("entity_list_editable")
- .that(constants.getEntityListEditable())
- .containsExactly("date", "datetime");
- assertWithMessage("in_app_conversation_action_types_default")
- .that(constants.getInAppConversationActionTypes())
- .containsExactly("text_reply");
- assertWithMessage("notification_conversation_action_types_default")
- .that(constants.getNotificationConversationActionTypes())
- .containsExactly("send_email", "call_phone");
- assertWithMessage("lang_id_threshold_override")
- .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f);
- Assert.assertArrayEquals("lang_id_context_settings",
- constants.getLangIdContextSettings(), new float[]{10, 1, 0.5f}, EPSILON);
- assertWithMessage("detect_language_from_text_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
- assertWithMessage("template_intent_factory_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
- assertWithMessage("translate_in_classification_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
+ public void testLoadFromDeviceConfig_booleanValue() throws Exception {
+ // Saves config original value.
+ final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ TextClassificationConstants.LOCAL_TEXT_CLASSIFIER_ENABLED);
+
+ final TextClassificationConstants constants = new TextClassificationConstants();
+ try {
+ // Sets and checks different value.
+ setDeviceConfig(TextClassificationConstants.LOCAL_TEXT_CLASSIFIER_ENABLED, "false");
+ assertWithMessage(TextClassificationConstants.LOCAL_TEXT_CLASSIFIER_ENABLED)
+ .that(constants.isLocalTextClassifierEnabled()).isFalse();
+ } finally {
+ // Restores config original value.
+ setDeviceConfig(TextClassificationConstants.LOCAL_TEXT_CLASSIFIER_ENABLED,
+ originalValue);
+ }
+ }
+
+ @Test
+ public void testLoadFromDeviceConfig_IntValue() throws Exception {
+ // Saves config original value.
+ final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH);
+
+ final TextClassificationConstants constants = new TextClassificationConstants();
+ try {
+ // Sets and checks different value.
+ setDeviceConfig(TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH, "8");
+ assertWithMessage(TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH)
+ .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(8);
+ } finally {
+ // Restores config original value.
+ setDeviceConfig(TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH,
+ originalValue);
+ }
+ }
+
+ @Test
+ public void testLoadFromDeviceConfig_StringValue() throws Exception {
+ // Saves config original value.
+ final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ TextClassificationConstants.TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE);
+
+ final TextClassificationConstants constants = new TextClassificationConstants();
+ try {
+ // Sets and checks different value.
+ final String testTextClassifier = "com.example.textclassifier";
+ setDeviceConfig(TextClassificationConstants.TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE,
+ testTextClassifier);
+ assertWithMessage(TextClassificationConstants.TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE)
+ .that(constants.getTextClassifierServicePackageOverride()).isEqualTo(
+ testTextClassifier);
+ } finally {
+ // Restores config original value.
+ setDeviceConfig(TextClassificationConstants.TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE,
+ originalValue);
+ }
+ }
+
+ @Test
+ public void testLoadFromDeviceConfig_FloatValue() throws Exception {
+ // Saves config original value.
+ final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE);
+
+ final TextClassificationConstants constants = new TextClassificationConstants();
+ try {
+ // Sets and checks different value.
+ setDeviceConfig(TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE, "2");
+ assertWithMessage(TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE)
+ .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
+ } finally {
+ // Restores config original value.
+ setDeviceConfig(TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE, originalValue);
+ }
}
@Test
- public void testLoadFromString_differentValues() {
- final String testTextClassifier = "com.example.textclassifier";
- final String s = "local_textclassifier_enabled=false,"
- + "system_textclassifier_enabled=false,"
- + "model_dark_launch_enabled=false,"
- + "smart_selection_enabled=false,"
- + "smart_text_share_enabled=false,"
- + "smart_linkify_enabled=false,"
- + "smart_select_animation_enabled=false,"
- + "suggest_selection_max_range_length=8,"
- + "classify_text_max_range_length=7,"
- + "generate_links_max_text_length=6,"
- + "generate_links_log_sample_rate=5,"
- + "entity_list_default=email:url,"
- + "entity_list_not_editable=date,"
- + "entity_list_editable=flight,"
- + "in_app_conversation_action_types_default=view_map:track_flight,"
- + "notification_conversation_action_types_default=share_location,"
- + "lang_id_threshold_override=2,"
- + "lang_id_context_settings=30:0.5:0.3,"
- + "detect_language_from_text_enabled=false,"
- + "template_intent_factory_enabled=false,"
- + "textclassifier_service_package_override=" + testTextClassifier + ","
- + "translate_in_classification_enabled=false";
- final TextClassificationConstants constants = new TextClassificationConstants(() -> s);
-
- assertWithMessage("local_textclassifier_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isFalse();
- assertWithMessage("system_textclassifier_enabled")
- .that(constants.isSystemTextClassifierEnabled()).isFalse();
- assertWithMessage("model_dark_launch_enabled")
- .that(constants.isModelDarkLaunchEnabled()).isFalse();
- assertWithMessage("smart_selection_enabled")
- .that(constants.isSmartSelectionEnabled()).isFalse();
- assertWithMessage("smart_text_share_enabled")
- .that(constants.isSmartTextShareEnabled()).isFalse();
- assertWithMessage("smart_linkify_enabled")
- .that(constants.isSmartLinkifyEnabled()).isFalse();
- assertWithMessage("smart_select_animation_enabled")
- .that(constants.isSmartSelectionAnimationEnabled()).isFalse();
- assertWithMessage("suggest_selection_max_range_length")
- .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(8);
- assertWithMessage("classify_text_max_range_length")
- .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(7);
- assertWithMessage("generate_links_max_text_length")
- .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(6);
- assertWithMessage("generate_links_log_sample_rate")
- .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(5);
- assertWithMessage("entity_list_default")
- .that(constants.getEntityListDefault())
- .containsExactly("email", "url");
- assertWithMessage("entity_list_not_editable")
- .that(constants.getEntityListNotEditable())
- .containsExactly("date");
- assertWithMessage("entity_list_editable")
- .that(constants.getEntityListEditable())
- .containsExactly("flight");
- assertWithMessage("in_app_conversation_action_types_default")
- .that(constants.getInAppConversationActionTypes())
- .containsExactly("view_map", "track_flight");
- assertWithMessage("notification_conversation_action_types_default")
- .that(constants.getNotificationConversationActionTypes())
- .containsExactly("share_location");
- assertWithMessage("lang_id_threshold_override")
- .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
- Assert.assertArrayEquals("lang_id_context_settings",
- constants.getLangIdContextSettings(), new float[]{30, 0.5f, 0.3f}, EPSILON);
- assertWithMessage("detect_language_from_text_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isFalse();
- assertWithMessage("template_intent_factory_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isFalse();
- assertWithMessage("translate_in_classification_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isFalse();
- assertWithMessage("textclassifier_service_package_override")
- .that(constants.getTextClassifierServiceName()).isEqualTo(
- testTextClassifier);
+ public void testLoadFromDeviceConfig_StringList() throws Exception {
+ // Saves config original value.
+ final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ TextClassificationConstants.ENTITY_LIST_DEFAULT);
+
+ final TextClassificationConstants constants = new TextClassificationConstants();
+ try {
+ // Sets and checks different value.
+ setDeviceConfig(TextClassificationConstants.ENTITY_LIST_DEFAULT, "email:url");
+ assertWithMessage(TextClassificationConstants.ENTITY_LIST_DEFAULT)
+ .that(constants.getEntityListDefault())
+ .containsExactly("email", "url");
+ } finally {
+ // Restores config original value.
+ setDeviceConfig(TextClassificationConstants.ENTITY_LIST_DEFAULT, originalValue);
+ }
}
@Test
- public void testLoadFromString_defaultValues() {
- final TextClassificationConstants constants = new TextClassificationConstants(() -> "");
-
- assertWithMessage("local_textclassifier_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
- assertWithMessage("system_textclassifier_enabled")
- .that(constants.isSystemTextClassifierEnabled()).isTrue();
- assertWithMessage("model_dark_launch_enabled")
- .that(constants.isModelDarkLaunchEnabled()).isFalse();
- assertWithMessage("smart_selection_enabled")
- .that(constants.isSmartSelectionEnabled()).isTrue();
- assertWithMessage("smart_text_share_enabled")
- .that(constants.isSmartTextShareEnabled()).isTrue();
- assertWithMessage("smart_linkify_enabled")
- .that(constants.isSmartLinkifyEnabled()).isTrue();
- assertWithMessage("smart_select_animation_enabled")
- .that(constants.isSmartSelectionAnimationEnabled()).isTrue();
- assertWithMessage("suggest_selection_max_range_length")
- .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10 * 1000);
- assertWithMessage("classify_text_max_range_length")
- .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(10 * 1000);
- assertWithMessage("generate_links_max_text_length")
- .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(100 * 1000);
- assertWithMessage("generate_links_log_sample_rate")
- .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(100);
- assertWithMessage("entity_list_default")
- .that(constants.getEntityListDefault())
- .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
- assertWithMessage("entity_list_not_editable")
- .that(constants.getEntityListNotEditable())
- .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
- assertWithMessage("entity_list_editable")
- .that(constants.getEntityListEditable())
- .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
- assertWithMessage("in_app_conversation_action_types_default")
- .that(constants.getInAppConversationActionTypes())
- .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
- "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
- "add_contact", "copy");
- assertWithMessage("notification_conversation_action_types_default")
- .that(constants.getNotificationConversationActionTypes())
- .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
- "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
- "add_contact", "copy");
- assertWithMessage("lang_id_threshold_override")
- .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
- Assert.assertArrayEquals("lang_id_context_settings",
- constants.getLangIdContextSettings(), new float[]{20, 1, 0.4f}, EPSILON);
- assertWithMessage("detect_language_from_text_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
- assertWithMessage("template_intent_factory_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
- assertWithMessage("translate_in_classification_enabled")
- .that(constants.isLocalTextClassifierEnabled()).isTrue();
- assertWithMessage("textclassifier_service_package_override")
- .that(constants.getTextClassifierServiceName()).isNull();
+ public void testLoadFromDeviceConfig_FloatList() throws Exception {
+ // Saves config original value.
+ final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ TextClassificationConstants.LANG_ID_CONTEXT_SETTINGS);
+
+ final TextClassificationConstants constants = new TextClassificationConstants();
+ try {
+ // Sets and checks different value.
+ setDeviceConfig(TextClassificationConstants.LANG_ID_CONTEXT_SETTINGS, "30:0.5:0.3");
+ assertThat(Floats.asList(constants.getLangIdContextSettings())).containsExactly(30f,
+ 0.5f, 0.3f).inOrder();
+ } finally {
+ // Restores config original value.
+ setDeviceConfig(TextClassificationConstants.LANG_ID_CONTEXT_SETTINGS, originalValue);
+ }
+ }
+
+ private void setDeviceConfig(String key, String value) {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key,
+ value, /* makeDefault */ false);
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index b3f2bbe92c07..8faf790549d5 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -78,7 +78,7 @@ public class TextClassificationManagerTest {
TextClassifier fallback = TextClassifier.NO_OP;
TextClassifier classifier = new TextClassifierImpl(
- fakeContext, new TextClassificationConstants(() -> null), fallback);
+ fakeContext, new TextClassificationConstants(), fallback);
String text = "Contact me at +12122537077";
String classifiedText = "+12122537077";
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index deb0f182156e..2304ba6f6da4 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -69,7 +69,7 @@ public class TextClassifierTest {
public String mTextClassifierType;
private static final TextClassificationConstants TC_CONSTANTS =
- new TextClassificationConstants(() -> "");
+ new TextClassificationConstants();
private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
private static final String NO_TYPE = null;
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 7b4054348642..82854e5b8a9d 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -20,6 +20,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHO
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -49,8 +50,10 @@ import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.media.Ringtone;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
@@ -157,9 +160,12 @@ public class AccessibilityShortcutControllerTest {
when(mFrameworkObjectProvider.getRingtone(eq(mContext), any())).thenReturn(mRingtone);
when(mResources.getString(anyInt())).thenReturn("Howdy %s");
+ when(mResources.getString(R.string.config_defaultAccessibilityService)).thenReturn(null);
when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT);
ResolveInfo resolveInfo = mock(ResolveInfo.class);
+ resolveInfo.serviceInfo = mock(ServiceInfo.class);
+ resolveInfo.serviceInfo.applicationInfo = mApplicationInfo;
when(resolveInfo.loadLabel(anyObject())).thenReturn("Service name");
when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
when(mServiceInfo.getComponentName())
@@ -200,42 +206,47 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_enabledButNoServiceWhenCreated_shouldReturnFalse() {
+ public void testShortcutAvailable_enabledButNoServiceWhenCreated_shouldReturnFalse()
+ throws Exception {
configureNoShortcutService();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
assertFalse(getController().isAccessibilityShortcutAvailable(false));
}
@Test
- public void testShortcutAvailable_enabledWithValidServiceWhenCreated_shouldReturnTrue() {
+ public void testShortcutAvailable_enabledWithValidServiceWhenCreated_shouldReturnTrue()
+ throws Exception {
configureValidShortcutService();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
assertTrue(getController().isAccessibilityShortcutAvailable(false));
}
@Test
- public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse() {
+ public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse()
+ throws Exception {
configureValidShortcutService();
configureShortcutEnabled(DISABLED_BUT_LOCK_SCREEN_ON);
assertFalse(getController().isAccessibilityShortcutAvailable(false));
}
@Test
- public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse() {
+ public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse()
+ throws Exception {
configureValidShortcutService();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
assertFalse(getController().isAccessibilityShortcutAvailable(true));
}
@Test
- public void testShortcutAvailable_onLockScreenAndEnabledThere_shouldReturnTrue() {
+ public void testShortcutAvailable_onLockScreenAndEnabledThere_shouldReturnTrue()
+ throws Exception {
configureValidShortcutService();
configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
assertTrue(getController().isAccessibilityShortcutAvailable(true));
}
@Test
- public void testShortcutAvailable_onLockScreenAndLockScreenPreferenceUnset() {
+ public void testShortcutAvailable_onLockScreenAndLockScreenPreferenceUnset() throws Exception {
// When the user hasn't specified a lock screen preference, we allow from the lock screen
// as long as the user has agreed to enable the shortcut
configureValidShortcutService();
@@ -249,17 +260,19 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse() {
+ public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse()
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
- Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
+ configureNoShortcutService();
accessibilityShortcutController.onSettingsChanged();
assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
}
@Test
- public void testShortcutAvailable_whenServiceIdBecomesNonNull_shouldReturnTrue() {
+ public void testShortcutAvailable_whenServiceIdBecomesNonNull_shouldReturnTrue()
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureNoShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
@@ -269,7 +282,8 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse() {
+ public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse()
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
@@ -279,7 +293,8 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue() {
+ public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue()
+ throws Exception {
configureShortcutEnabled(DISABLED);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
@@ -289,7 +304,8 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_whenLockscreenBecomesDisabled_shouldReturnFalse() {
+ public void testShortcutAvailable_whenLockscreenBecomesDisabled_shouldReturnFalse()
+ throws Exception {
configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
@@ -299,7 +315,8 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_whenLockscreenBecomesEnabled_shouldReturnTrue() {
+ public void testShortcutAvailable_whenLockscreenBecomesEnabled_shouldReturnTrue()
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
@@ -370,7 +387,7 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testClickingDisableButtonInDialog_shouldClearShortcutId() {
+ public void testClickingDisableButtonInDialog_shouldClearShortcutId() throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
@@ -458,7 +475,22 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testOnAccessibilityShortcut_showsWarningDialog_shouldTtsSpokenPrompt() {
+ public void testOnAccessibilityShortcut_sdkGreaterThanQ_reqA11yButton_callsServiceWithNoToast()
+ throws Exception {
+ configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+ configureValidShortcutService();
+ configureApplicationTargetSdkVersion(Build.VERSION_CODES.R);
+ configureRequestAccessibilityButton();
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ getController().performAccessibilityShortcut();
+
+ verifyZeroInteractions(mToast);
+ verify(mAccessibilityManagerService).performAccessibilityShortcut();
+ }
+
+ @Test
+ public void testOnAccessibilityShortcut_showsWarningDialog_shouldTtsSpokenPrompt()
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
configureTtsSpokenPromptEnabled();
@@ -482,7 +514,8 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testOnAccessibilityShortcut_showsWarningDialog_ttsInitFail_noSpokenPrompt() {
+ public void testOnAccessibilityShortcut_showsWarningDialog_ttsInitFail_noSpokenPrompt()
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
configureTtsSpokenPromptEnabled();
@@ -500,19 +533,28 @@ public class AccessibilityShortcutControllerTest {
verify(mRingtone).play();
}
- private void configureNoShortcutService() {
+ private void configureNoShortcutService() throws Exception {
+ when(mAccessibilityManagerService
+ .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .thenReturn(Collections.emptyList());
Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
}
- private void configureValidShortcutService() {
+ private void configureValidShortcutService() throws Exception {
+ when(mAccessibilityManagerService
+ .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .thenReturn(Collections.singletonList(SERVICE_NAME_STRING));
Settings.Secure.putString(
mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING);
}
- private void configureFirstFrameworkFeature() {
+ private void configureFirstFrameworkFeature() throws Exception {
ComponentName featureComponentName =
(ComponentName) AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
.keySet().toArray()[0];
+ when(mAccessibilityManagerService
+ .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .thenReturn(Collections.singletonList(featureComponentName.flattenToString()));
Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
featureComponentName.flattenToString());
}
@@ -552,6 +594,15 @@ public class AccessibilityShortcutControllerTest {
.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK;
}
+ private void configureRequestAccessibilityButton() {
+ mServiceInfo.flags |= AccessibilityServiceInfo
+ .FLAG_REQUEST_ACCESSIBILITY_BUTTON;
+ }
+
+ private void configureApplicationTargetSdkVersion(int versionCode) {
+ mApplicationInfo.targetSdkVersion = versionCode;
+ }
+
private void configureHandlerCallbackInvocation() {
doAnswer((InvocationOnMock invocation) -> {
Message m = (Message) invocation.getArguments()[0];
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index d427cbda7fb6..8622b7efeee7 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -313,7 +313,7 @@ public class ChooserActivityTest {
assertThat(activity.isFinishing(), is(false));
onView(withId(R.id.empty)).check(matches(isDisplayed()));
- onView(withId(R.id.resolver_list)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.profile_pager)).check(matches(not(isDisplayed())));
InstrumentationRegistry.getInstrumentation().runOnMainSync(
() -> activity.getAdapter().handlePackagesChanged()
);
@@ -674,12 +674,12 @@ public class ChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
+ // Second invocation is from onCreate
verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
- // First invocation is from onCreate
- assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
- is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
- assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+ assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(),
is(CONTENT_PREVIEW_TEXT));
+ assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
+ is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
}
@Test
@@ -706,10 +706,10 @@ public class ChooserActivityTest {
waitForIdle();
verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
// First invocation is from onCreate
- assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
- is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
- assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+ assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(),
is(CONTENT_PREVIEW_IMAGE));
+ assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
+ is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 03705d0599e5..a2e0095c2aee 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -29,6 +29,7 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.os.UserHandle;
import android.util.Size;
import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
@@ -47,7 +48,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
private UsageStatsManager mUsm;
ChooserListAdapter getAdapter() {
- return (ChooserListAdapter) mAdapter;
+ return mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
}
boolean getIsSelected() { return mIsSuccessfullySelected; }
@@ -77,7 +78,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
}
@Override
- protected ResolverListController createListController() {
+ protected ResolverListController createListController(UserHandle userHandle) {
return sOverrides.resolverListController;
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 344c28679568..923ce3e3935d 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -116,14 +116,14 @@ public class ResolverActivityTest {
waitForIdle();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- final View resolverList = activity.findViewById(R.id.resolver_list);
- final int initialResolverHeight = resolverList.getHeight();
+ final View viewPager = activity.findViewById(R.id.profile_pager);
+ final int initialResolverHeight = viewPager.getHeight();
activity.runOnUiThread(() -> {
ResolverDrawerLayout layout = (ResolverDrawerLayout)
activity.findViewById(
R.id.contentPanel);
- ((ResolverDrawerLayout.LayoutParams) resolverList.getLayoutParams()).maxHeight
+ ((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight
= initialResolverHeight - 1;
// Force a relayout
layout.invalidate();
@@ -131,13 +131,13 @@ public class ResolverActivityTest {
});
waitForIdle();
assertThat("Drawer should be capped at maxHeight",
- resolverList.getHeight() == (initialResolverHeight - 1));
+ viewPager.getHeight() == (initialResolverHeight - 1));
activity.runOnUiThread(() -> {
ResolverDrawerLayout layout = (ResolverDrawerLayout)
activity.findViewById(
R.id.contentPanel);
- ((ResolverDrawerLayout.LayoutParams) resolverList.getLayoutParams()).maxHeight
+ ((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight
= initialResolverHeight + 1;
// Force a relayout
layout.invalidate();
@@ -145,7 +145,7 @@ public class ResolverActivityTest {
});
waitForIdle();
assertThat("Drawer should not change height if its height is less than maxHeight",
- resolverList.getHeight() == initialResolverHeight);
+ viewPager.getHeight() == initialResolverHeight);
}
@Ignore // Failing - b/144929805
@@ -160,11 +160,13 @@ public class ResolverActivityTest {
waitForIdle();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- final View resolverList = activity.findViewById(R.id.resolver_list);
+ final View viewPager = activity.findViewById(R.id.profile_pager);
+ final View divider = activity.findViewById(R.id.divider);
final RelativeLayout profileView =
(RelativeLayout) activity.findViewById(R.id.profile_button).getParent();
assertThat("Drawer should show at bottom by default",
- profileView.getBottom() == resolverList.getTop() && profileView.getTop() > 0);
+ profileView.getBottom() + divider.getHeight() == viewPager.getTop()
+ && profileView.getTop() > 0);
activity.runOnUiThread(() -> {
ResolverDrawerLayout layout = (ResolverDrawerLayout)
@@ -174,7 +176,8 @@ public class ResolverActivityTest {
});
waitForIdle();
assertThat("Drawer should show at top with new attribute",
- profileView.getBottom() == resolverList.getTop() && profileView.getTop() == 0);
+ profileView.getBottom() + divider.getHeight() == viewPager.getTop()
+ && profileView.getTop() == 0);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
index 5ac1489bcfef..64906bb27ff0 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
@@ -115,7 +115,7 @@ public class ResolverListControllerTest {
mUsm = new UsageStatsManager(mMockContext, mMockService);
when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent,
- refererPackage, UserHandle.USER_CURRENT);
+ refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM);
mController.sort(new ArrayList<ResolvedComponentInfo>());
long beforeReport = getCount(mUsm, packageName, action, annotation);
mController.updateChooserCounts(packageName, UserHandle.USER_CURRENT, action);
@@ -132,7 +132,7 @@ public class ResolverListControllerTest {
mUsm = new UsageStatsManager(mMockContext, mMockService);
when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent,
- refererPackage, UserHandle.USER_CURRENT);
+ refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM);
List<ResolvedComponentInfo> topKList = new ArrayList<>(resolvedComponents);
mController.topK(topKList, 5);
List<ResolvedComponentInfo> sortList = new ArrayList<>(topKList);
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 39cc83c3bc43..93357af406e8 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
import com.android.internal.app.chooser.TargetInfo;
@@ -37,15 +38,15 @@ public class ResolverWrapperActivity extends ResolverActivity {
private UsageStatsManager mUsm;
@Override
- public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
- Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed,
- boolean useLayoutForBrowsables) {
+ public ResolverListAdapter createResolverListAdapter(Context context,
+ List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) {
return new ResolverWrapperAdapter(context, payloadIntents, initialIntents, rList,
- filterLastUsed, createListController(), useLayoutForBrowsables, this);
+ filterLastUsed, createListController(userHandle), useLayoutForBrowsables, this);
}
ResolverWrapperAdapter getAdapter() {
- return (ResolverWrapperAdapter) mAdapter;
+ return (ResolverWrapperAdapter) mMultiProfilePagerAdapter.getCurrentListAdapter();
}
@Override
@@ -66,7 +67,7 @@ public class ResolverWrapperActivity extends ResolverActivity {
}
@Override
- protected ResolverListController createListController() {
+ protected ResolverListController createListController(UserHandle userHandle) {
return sOverrides.resolverListController;
}
diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
new file mode 100644
index 000000000000..9002c2c6b184
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.infra;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Unit test for {@link AndroidFuture}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:com.android.internal.infra.AndroidFutureTest}
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class AndroidFutureTest {
+ @Test
+ public void testGet() throws Exception {
+ AndroidFuture<Integer> future = new AndroidFuture<>();
+ future.complete(5);
+ assertThat(future.get()).isEqualTo(5);
+ }
+
+ @Test
+ public void testWhenComplete_AlreadyComplete() throws Exception {
+ AndroidFuture<Integer> future = new AndroidFuture<>();
+ future.complete(5);
+ CountDownLatch latch = new CountDownLatch(1);
+ future.whenComplete((obj, err) -> {
+ assertThat(obj).isEqualTo(5);
+ assertThat(err).isNull();
+ latch.countDown();
+ });
+ latch.await();
+ }
+
+ @Test
+ public void testWhenComplete_NotYetComplete() throws Exception {
+ AndroidFuture<Integer> future = new AndroidFuture<>();
+ CountDownLatch latch = new CountDownLatch(1);
+ future.whenComplete((obj, err) -> {
+ assertThat(obj).isEqualTo(5);
+ assertThat(err).isNull();
+ latch.countDown();
+ });
+ assertThat(latch.getCount()).isEqualTo(1);
+ future.complete(5);
+ latch.await();
+ assertThat(latch.getCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testCompleteExceptionally() {
+ AndroidFuture<Integer> future = new AndroidFuture<>();
+ Exception origException = new UnsupportedOperationException();
+ future.completeExceptionally(origException);
+ ExecutionException executionException =
+ expectThrows(ExecutionException.class, future::get);
+ assertThat(executionException.getCause()).isSameAs(origException);
+ }
+
+ @Test
+ public void testCompleteExceptionally_Listener() throws Exception {
+ AndroidFuture<Integer> future = new AndroidFuture<>();
+ Exception origException = new UnsupportedOperationException();
+ future.completeExceptionally(origException);
+ CountDownLatch latch = new CountDownLatch(1);
+ future.whenComplete((obj, err) -> {
+ assertThat(obj).isNull();
+ assertThat(err).isSameAs(origException);
+ latch.countDown();
+ });
+ latch.await();
+ }
+
+ @Test
+ public void testWriteToParcel() throws Exception {
+ Parcel parcel = Parcel.obtain();
+ AndroidFuture<Integer> future1 = new AndroidFuture<>();
+ future1.complete(5);
+ future1.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+ AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
+ assertThat(future2.get()).isEqualTo(5);
+ }
+
+ @Test
+ public void testWriteToParcel_Exceptionally() throws Exception {
+ Parcel parcel = Parcel.obtain();
+ AndroidFuture<Integer> future1 = new AndroidFuture<>();
+ future1.completeExceptionally(new UnsupportedOperationException());
+ future1.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+ AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
+ ExecutionException executionException =
+ expectThrows(ExecutionException.class, future2::get);
+ assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
+ }
+}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index ff521be82599..43f65e368c10 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -88,7 +88,7 @@ prebuilt_etc {
prebuilt_etc {
name: "privapp_whitelist_com.android.launcher3",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.launcher3.xml",
filename_from_src: true,
diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk
index 3fe421e530cb..b76eb1575b86 100644
--- a/data/etc/CleanSpec.mk
+++ b/data/etc/CleanSpec.mk
@@ -51,6 +51,8 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.provision.xml)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.settings.xml)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.settings.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.launcher3.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.launcher3.xml)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
# ******************************************************************
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index ba877f8d0d02..ee989cca1787 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -51,5 +51,6 @@
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 440b885b4574..eff353c99388 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -79,12 +79,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1976550065": {
- "message": "commitVisibility: %s: visible=%b visibleRequested=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-1963461591": {
"message": "Removing %s from %s",
"level": "VERBOSE",
@@ -283,6 +277,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1521427940": {
+ "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1515151503": {
"message": ">>> OPEN TRANSACTION removeReplacedWindows",
"level": "INFO",
@@ -697,12 +697,6 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
- "-633961578": {
- "message": "applyAnimation: transition animation is disabled or skipped. container=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-622997754": {
"message": "postWindowRemoveCleanupLocked: %s",
"level": "VERBOSE",
@@ -1477,12 +1471,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "841702299": {
- "message": "Changing app %s visible=%b performLayout=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"845234215": {
"message": "App is requesting an orientation, return %d for display id=%d",
"level": "VERBOSE",
@@ -1993,6 +1981,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "1967975839": {
+ "message": "Changing app %s visible=%b performLayout=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/AppTransitionController.java"
+ },
"1984470582": {
"message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
"level": "DEBUG",
diff --git a/data/sounds/AudioPackageGo.mk b/data/sounds/AudioPackageGo.mk
index e3b27f2cd962..e3fb45f6f055 100644
--- a/data/sounds/AudioPackageGo.mk
+++ b/data/sounds/AudioPackageGo.mk
@@ -47,3 +47,7 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+ $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+ $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+ $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 6619dba159c2..8ebac667aca3 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -1675,6 +1675,9 @@ public final class ImageDecoder implements AutoCloseable {
if (r == null) {
return;
}
+ if (r.width() <= 0 || r.height() <= 0) {
+ throw new IllegalStateException("Subset " + r + " is empty/unsorted");
+ }
if (r.left < 0 || r.top < 0 || r.right > width || r.bottom > height) {
throw new IllegalStateException("Subset " + r + " not contained by "
+ "scaled image bounds: (" + width + " x " + height + ")");
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 9c8463417e0a..00ceb2d84f9e 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -41,7 +41,7 @@ RenderNodeDrawable::~RenderNodeDrawable() {
void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas,
const SkiaDisplayList& displayList,
- int nestLevel) {
+ int nestLevel) const {
LOG_ALWAYS_FATAL_IF(0 == nestLevel && !displayList.mProjectionReceiver);
for (auto& child : displayList.mChildNodes) {
const RenderProperties& childProperties = child.getNodeProperties();
@@ -132,7 +132,7 @@ private:
RenderNode& mNode;
};
-void RenderNodeDrawable::forceDraw(SkCanvas* canvas) {
+void RenderNodeDrawable::forceDraw(SkCanvas* canvas) const {
RenderNode* renderNode = mRenderNode.get();
MarkDraw _marker{*canvas, *renderNode};
@@ -230,7 +230,14 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
// we need to restrict the portion of the surface drawn to the size of the renderNode.
SkASSERT(renderNode->getLayerSurface()->width() >= bounds.width());
SkASSERT(renderNode->getLayerSurface()->height() >= bounds.height());
- canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(), bounds,
+
+ // If SKP recording is active save an annotation that indicates this drawImageRect
+ // could also be rendered with the commands saved at ID associated with this node.
+ if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
+ canvas->drawAnnotation(bounds, String8::format(
+ "SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
+ }
+ canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot(), bounds,
bounds, &paint);
if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index 6ba8e599818c..6c390c3fce24 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -58,7 +58,7 @@ public:
* projection receiver then all projected children (excluding direct children) will be drawn
* last. Any projected node not matching those requirements will not be drawn by this function.
*/
- void forceDraw(SkCanvas* canvas);
+ void forceDraw(SkCanvas* canvas) const;
/**
* Returns readonly render properties for this render node.
@@ -113,7 +113,7 @@ private:
* @param nestLevel should be always 0. Used to track how far we are from the receiver.
*/
void drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList,
- int nestLevel = 0);
+ int nestLevel = 0) const;
/**
* Applies the rendering properties of a view onto a SkCanvas.
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 06479776fc73..11dc013af6bc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -26,11 +26,11 @@
#include <SkPictureRecorder.h>
#include <SkSerialProcs.h>
#include "LightingInfo.h"
-#include "TreeInfo.h"
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
#include "utils/TraceUtils.h"
+#include "utils/String8.h"
#include <unistd.h>
@@ -90,58 +90,61 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque)
// only schedule repaint if node still on layer - possible it may have been
// removed during a dropped frame, but layers may still remain scheduled so
// as not to lose info on what portion is damaged
- if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) {
- SkASSERT(layerNode->getLayerSurface());
- SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
- if (!displayList || displayList->isEmpty()) {
- ALOGE("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName());
- return;
- }
+ if (CC_UNLIKELY(layerNode->getLayerSurface() == nullptr)) {
+ continue;
+ }
+ SkASSERT(layerNode->getLayerSurface());
+ SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
+ if (!displayList || displayList->isEmpty()) {
+ ALOGE("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName());
+ return;
+ }
- const Rect& layerDamage = layers.entries()[i].damage;
+ const Rect& layerDamage = layers.entries()[i].damage;
- SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
+ SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
- int saveCount = layerCanvas->save();
- SkASSERT(saveCount == 1);
+ int saveCount = layerCanvas->save();
+ SkASSERT(saveCount == 1);
- layerCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
+ layerCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
- // TODO: put localized light center calculation and storage to a drawable related code.
- // It does not seem right to store something localized in a global state
- const Vector3 savedLightCenter(LightingInfo::getLightCenterRaw());
- Vector3 transformedLightCenter(savedLightCenter);
- // map current light center into RenderNode's coordinate space
- layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(transformedLightCenter);
- LightingInfo::setLightCenterRaw(transformedLightCenter);
+ // TODO: put localized light center calculation and storage to a drawable related code.
+ // It does not seem right to store something localized in a global state
+ // fix here and in recordLayers
+ const Vector3 savedLightCenter(LightingInfo::getLightCenterRaw());
+ Vector3 transformedLightCenter(savedLightCenter);
+ // map current light center into RenderNode's coordinate space
+ layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(transformedLightCenter);
+ LightingInfo::setLightCenterRaw(transformedLightCenter);
- const RenderProperties& properties = layerNode->properties();
- const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
- if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
- return;
- }
+ const RenderProperties& properties = layerNode->properties();
+ const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
+ if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
+ return;
+ }
- ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(),
- bounds.height());
-
- layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
- layerCanvas->clear(SK_ColorTRANSPARENT);
-
- RenderNodeDrawable root(layerNode, layerCanvas, false);
- root.forceDraw(layerCanvas);
- layerCanvas->restoreToCount(saveCount);
- LightingInfo::setLightCenterRaw(savedLightCenter);
-
- // cache the current context so that we can defer flushing it until
- // either all the layers have been rendered or the context changes
- GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
- if (cachedContext.get() != currentContext) {
- if (cachedContext.get()) {
- ATRACE_NAME("flush layers (context changed)");
- cachedContext->flush();
- }
- cachedContext.reset(SkSafeRef(currentContext));
+ ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(),
+ bounds.height());
+
+ layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
+ layerCanvas->clear(SK_ColorTRANSPARENT);
+
+ RenderNodeDrawable root(layerNode, layerCanvas, false);
+ root.forceDraw(layerCanvas);
+ layerCanvas->restoreToCount(saveCount);
+
+ LightingInfo::setLightCenterRaw(savedLightCenter);
+
+ // cache the current context so that we can defer flushing it until
+ // either all the layers have been rendered or the context changes
+ GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
+ if (cachedContext.get() != currentContext) {
+ if (cachedContext.get()) {
+ ATRACE_NAME("flush layers (context changed)");
+ cachedContext->flush();
}
+ cachedContext.reset(SkSafeRef(currentContext));
}
}
@@ -275,12 +278,60 @@ bool SkiaPipeline::setupMultiFrameCapture() {
}
}
-SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
+// recurse through the rendernode's children, add any nodes which are layers to the queue.
+static void collectLayers(RenderNode* node, LayerUpdateQueue* layers) {
+ SkiaDisplayList* dl = (SkiaDisplayList*)node->getDisplayList();
+ if (dl) {
+ const auto& prop = node->properties();
+ if (node->hasLayer()) {
+ layers->enqueueLayerWithDamage(node, Rect(prop.getWidth(), prop.getHeight()));
+ }
+ // The way to recurse through rendernodes is to call this with a lambda.
+ dl->updateChildren([&](RenderNode* child) { collectLayers(child, layers); });
+ }
+}
+
+// record the provided layers to the provided canvas as self-contained skpictures.
+static void recordLayers(const LayerUpdateQueue& layers,
+ SkCanvas* mskpCanvas) {
+ const Vector3 savedLightCenter(LightingInfo::getLightCenterRaw());
+ // Record the commands to re-draw each dirty layer into an SkPicture
+ for (size_t i = 0; i < layers.entries().size(); i++) {
+ RenderNode* layerNode = layers.entries()[i].renderNode.get();
+ const Rect& layerDamage = layers.entries()[i].damage;
+ const RenderProperties& properties = layerNode->properties();
+
+ // Temporarily map current light center into RenderNode's coordinate space
+ Vector3 transformedLightCenter(savedLightCenter);
+ layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(transformedLightCenter);
+ LightingInfo::setLightCenterRaw(transformedLightCenter);
+
+ SkPictureRecorder layerRec;
+ auto* recCanvas = layerRec.beginRecording(properties.getWidth(),
+ properties.getHeight());
+ // This is not recorded but still causes clipping.
+ recCanvas->androidFramework_setDeviceClipRestriction(layerDamage.toSkIRect());
+ RenderNodeDrawable root(layerNode, recCanvas, false);
+ root.forceDraw(recCanvas);
+ // Now write this picture into the SKP canvas with an annotation indicating what it is
+ mskpCanvas->drawAnnotation(layerDamage.toSkRect(), String8::format(
+ "OffscreenLayerDraw|%" PRId64, layerNode->uniqueId()).c_str(), nullptr);
+ mskpCanvas->drawPicture(layerRec.finishRecordingAsPicture());
+ }
+ LightingInfo::setLightCenterRaw(savedLightCenter);
+}
+
+SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface, RenderNode* root,
+ const LayerUpdateQueue& dirtyLayers) {
if (CC_LIKELY(!Properties::skpCaptureEnabled)) {
return surface->getCanvas(); // Bail out early when capture is not turned on.
}
// Note that shouldStartNewFileCapture tells us if this is the *first* frame of a capture.
+ bool firstFrameOfAnim = false;
if (shouldStartNewFileCapture() && mCaptureMode == CaptureMode::MultiFrameSKP) {
+ // set a reminder to record every layer near the end of this method, after we have set up
+ // the nway canvas.
+ firstFrameOfAnim = true;
if (!setupMultiFrameCapture()) {
return surface->getCanvas();
}
@@ -309,6 +360,20 @@ SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
mNwayCanvas->addCanvas(surface->getCanvas());
mNwayCanvas->addCanvas(pictureCanvas);
+
+ if (firstFrameOfAnim) {
+ // On the first frame of any mskp capture we want to record any layers that are needed in
+ // frame but may have been rendered offscreen before recording began.
+ // We do not maintain a list of all layers, since it isn't needed outside this rare,
+ // recording use case. Traverse the tree to find them and put them in this LayerUpdateQueue.
+ LayerUpdateQueue luq;
+ collectLayers(root, &luq);
+ recordLayers(luq, mNwayCanvas.get());
+ } else {
+ // on non-first frames, we record any normal layer draws (dirty regions)
+ recordLayers(dirtyLayers, mNwayCanvas.get());
+ }
+
return mNwayCanvas.get();
}
@@ -359,13 +424,13 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
Properties::skpCaptureEnabled = true;
}
+ // Initialize the canvas for the current frame, that might be a recording canvas if SKP
+ // capture is enabled.
+ SkCanvas* canvas = tryCapture(surface.get(), nodes[0].get(), layers);
+
// draw all layers up front
renderLayersImpl(layers, opaque);
- // initialize the canvas for the current frame, that might be a recording canvas if SKP
- // capture is enabled.
- SkCanvas* canvas = tryCapture(surface.get());
-
renderFrameImpl(clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
endCapture(surface.get());
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 7d575ad01936..af8414de4bc1 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -45,6 +45,8 @@ public:
void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
bool opaque, const LightInfo& lightInfo) override;
+ // If the given node didn't have a layer surface, or had one of the wrong size, this method
+ // creates a new one and returns true. Otherwise does nothing and returns false.
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
@@ -92,7 +94,7 @@ private:
// Called every frame. Normally returns early with screen canvas.
// But when capture is enabled, returns an nwaycanvas where commands are also recorded.
- SkCanvas* tryCapture(SkSurface* surface);
+ SkCanvas* tryCapture(SkSurface* surface, RenderNode* root, const LayerUpdateQueue& dirtyLayers);
// Called at the end of every frame, closes the recording if necessary.
void endCapture(SkSurface* surface);
// Determine if a new file-based capture should be started.
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
index b0fad57dfd29..901ffaa59cd1 100644
--- a/libs/services/Android.bp
+++ b/libs/services/Android.bp
@@ -22,17 +22,16 @@ cc_library_shared {
"src/os/DropBoxManager.cpp",
"src/os/StatsDimensionsValue.cpp",
"src/os/StatsLogEventWrapper.cpp",
- "src/util/StatsEvent.cpp",
],
shared_libs: [
"libbinder",
- "liblog",
"libcutils",
+ "liblog",
"libutils",
],
header_libs: [
- "libbase_headers",
+ "libbase_headers",
],
aidl: {
include_dirs: ["frameworks/base/core/java/"],
diff --git a/libs/services/include/android/util/StatsEvent.h b/libs/services/include/android/util/StatsEvent.h
deleted file mode 100644
index 48631174f7dd..000000000000
--- a/libs/services/include/android/util/StatsEvent.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef STATS_EVENT_H
-#define STATS_EVENT_H
-
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-#include <binder/Status.h>
-#include <vector>
-
-namespace android {
-namespace util {
-class StatsEvent : public android::Parcelable {
- public:
- StatsEvent();
-
- StatsEvent(StatsEvent&& in) = default;
-
- android::status_t writeToParcel(android::Parcel* out) const;
-
- android::status_t readFromParcel(const android::Parcel* in);
-
- private:
- int mAtomTag;
- std::vector<uint8_t> mBuffer;
-};
-} // Namespace util
-} // Namespace android
-
-#endif // STATS_ EVENT_H \ No newline at end of file
diff --git a/libs/services/src/util/StatsEvent.cpp b/libs/services/src/util/StatsEvent.cpp
deleted file mode 100644
index 8b8579167b00..000000000000
--- a/libs/services/src/util/StatsEvent.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <android/util/StatsEvent.h>
-
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-#include <binder/Status.h>
-#include <vector>
-
-using android::Parcel;
-using android::Parcelable;
-using android::status_t;
-using std::vector;
-
-namespace android {
-namespace util {
-
-StatsEvent::StatsEvent(){};
-
-status_t StatsEvent::writeToParcel(Parcel* out) const {
- // Implement me if desired. We don't currently use this.
- ALOGE("Cannot do c++ StatsEvent.writeToParcel(); it is not implemented.");
- (void)out; // To prevent compile error of unused parameter 'out'
- return UNKNOWN_ERROR;
-};
-
-status_t StatsEvent::readFromParcel(const Parcel* in) {
- status_t res = OK;
- if (in == NULL) {
- ALOGE("statsd received parcel argument was NULL.");
- return BAD_VALUE;
- }
- if ((res = in->readInt32(&mAtomTag)) != OK) {
- ALOGE("statsd could not read atom tag from parcel");
- return res;
- }
- if ((res = in->readByteVector(&mBuffer)) != OK) {
- ALOGE("statsd could not read buffer from parcel");
- return res;
- }
- return NO_ERROR;
-};
-
-} // Namespace util
-} // Namespace android
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 1f8c1d5352b0..aa1484f21862 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -125,6 +125,7 @@ public class LocationManager {
*
* @hide
*/
+ @TestApi
public static final String FUSED_PROVIDER = "fused";
/**
@@ -1837,12 +1838,9 @@ public class LocationManager {
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
- UnsupportedOperationException ex = new UnsupportedOperationException(
- "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
- throw ex;
- } else {
- Log.w(TAG, ex);
+ throw new UnsupportedOperationException(
+ "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
}
GnssStatus gnssStatus = mGnssStatusListenerManager.getGnssStatus();
diff --git a/media/apex/java/android/media/MediaParser.java b/media/apex/java/android/media/MediaParser.java
index 8824269ea0c0..b83f44540955 100644
--- a/media/apex/java/android/media/MediaParser.java
+++ b/media/apex/java/android/media/MediaParser.java
@@ -156,19 +156,29 @@ public final class MediaParser {
* <p>A {@link SeekPoint} is a position in the stream from which a player may successfully start
* playing media samples.
*/
- public interface SeekMap {
+ public static final class SeekMap {
/** Returned by {@link #getDurationUs()} when the duration is unknown. */
- int UNKNOWN_DURATION = Integer.MIN_VALUE;
+ public static final int UNKNOWN_DURATION = Integer.MIN_VALUE;
+
+ private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
+
+ private SeekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
+ mExoPlayerSeekMap = exoplayerSeekMap;
+ }
/** Returns whether seeking is supported. */
- boolean isSeekable();
+ public boolean isSeekable() {
+ return mExoPlayerSeekMap.isSeekable();
+ }
/**
* Returns the duration of the stream in microseconds or {@link #UNKNOWN_DURATION} if the
* duration is unknown.
*/
- long getDurationUs();
+ public long getDurationUs() {
+ return mExoPlayerSeekMap.getDurationUs();
+ }
/**
* Obtains {@link SeekPoint SeekPoints} for the specified seek time in microseconds.
@@ -184,7 +194,10 @@ public final class MediaParser {
* @return The corresponding {@link SeekPoint SeekPoints}.
*/
@NonNull
- Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs);
+ public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) {
+ SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs);
+ return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second));
+ }
}
/** Defines a seek point in a media stream. */
@@ -647,7 +660,7 @@ public final class MediaParser {
@Override
public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
- mOutputConsumer.onSeekMap(new ExoToMediaParserSeekMapAdapter(exoplayerSeekMap));
+ mOutputConsumer.onSeekMap(new SeekMap(exoplayerSeekMap));
}
}
@@ -764,32 +777,6 @@ public final class MediaParser {
Extractor createInstance();
}
- private static class ExoToMediaParserSeekMapAdapter implements SeekMap {
-
- private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
-
- private ExoToMediaParserSeekMapAdapter(
- com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
- mExoPlayerSeekMap = exoplayerSeekMap;
- }
-
- @Override
- public boolean isSeekable() {
- return mExoPlayerSeekMap.isSeekable();
- }
-
- @Override
- public long getDurationUs() {
- return mExoPlayerSeekMap.getDurationUs();
- }
-
- @Override
- public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) {
- SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs);
- return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second));
- }
- }
-
// Private static methods.
private static MediaFormat toMediaFormat(Format format) {
diff --git a/media/java/android/media/AudioDeviceAddress.java b/media/java/android/media/AudioDeviceAddress.java
index 415e77dc4049..3d8fc373006e 100644
--- a/media/java/android/media/AudioDeviceAddress.java
+++ b/media/java/android/media/AudioDeviceAddress.java
@@ -72,10 +72,12 @@ public final class AudioDeviceAddress implements Parcelable {
private final @Role int mRole;
/**
+ * @hide
* Constructor from a valid {@link AudioDeviceInfo}
* @param deviceInfo the connected audio device from which to obtain the device-identifying
* type and address.
*/
+ @SystemApi
public AudioDeviceAddress(@NonNull AudioDeviceInfo deviceInfo) {
Objects.requireNonNull(deviceInfo);
mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
@@ -83,6 +85,14 @@ public final class AudioDeviceAddress implements Parcelable {
mAddress = deviceInfo.getAddress();
}
+ /**
+ * @hide
+ * Constructor from role, device type and address
+ * @param role indicates input or output role
+ * @param type the device type, as defined in {@link AudioDeviceInfo}
+ * @param address the address of the device, or an empty string for devices without one
+ */
+ @SystemApi
public AudioDeviceAddress(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
@NonNull String address) {
Objects.requireNonNull(address);
@@ -101,14 +111,38 @@ public final class AudioDeviceAddress implements Parcelable {
mAddress = address;
}
+ /*package*/ AudioDeviceAddress(int nativeType, @NonNull String address) {
+ mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
+ mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
+ mAddress = address;
+ }
+
+ /**
+ * @hide
+ * Returns the role of a device
+ * @return the role
+ */
+ @SystemApi
public @Role int getRole() {
return mRole;
}
+ /**
+ * @hide
+ * Returns the audio device type of a device
+ * @return the type, as defined in {@link AudioDeviceInfo}
+ */
+ @SystemApi
public @AudioDeviceInfo.AudioDeviceType int getType() {
return mType;
}
+ /**
+ * @hide
+ * Returns the address of the audio device, or an empty string for devices without one
+ * @return the device address
+ */
+ @SystemApi
public @NonNull String getAddress() {
return mAddress;
}
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index a39bc51acb24..8293b5f36c04 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -155,7 +155,9 @@ public final class AudioDeviceInfo {
TYPE_TV_TUNER }
)
@Retention(RetentionPolicy.SOURCE)
- public @interface AudioDeviceType {} /** @hide */
+ public @interface AudioDeviceType {}
+
+ /** @hide */
@IntDef(flag = false, prefix = "TYPE", value = {
TYPE_BUILTIN_MIC,
TYPE_BLUETOOTH_SCO,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d5524915f423..fac276cfb5d1 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -78,6 +78,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -1536,6 +1537,76 @@ public class AudioManager {
}
//====================================================================
+ // Audio Product Strategy routing
+
+ /**
+ * @hide
+ * Set the preferred device for a given strategy, i.e. the audio routing to be used by
+ * this audio strategy. Note that the device may not be available at the time the preferred
+ * device is set, but it will be used once made available.
+ * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
+ * this preference for this strategy.</p>
+ * @param strategy the audio strategy whose routing will be affected
+ * @param device the audio device to route to when available
+ * @return true if the operation was successful, false otherwise
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
+ @NonNull AudioDeviceAddress device) {
+ Objects.requireNonNull(strategy);
+ Objects.requireNonNull(device);
+ try {
+ final int status =
+ getService().setPreferredDeviceForStrategy(strategy.getId(), device);
+ return status == AudioSystem.SUCCESS;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Removes the preferred audio device previously set with
+ * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)}.
+ * @param strategy the audio strategy whose routing will be affected
+ * @return true if the operation was successful, false otherwise (invalid strategy, or no
+ * device set for example)
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
+ Objects.requireNonNull(strategy);
+ try {
+ final int status =
+ getService().removePreferredDeviceForStrategy(strategy.getId());
+ return status == AudioSystem.SUCCESS;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Return the preferred device for an audio strategy, previously set with
+ * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)}
+ * @param strategy the strategy to query
+ * @return the preferred device for that strategy, or null if none was ever set or if the
+ * strategy is invalid
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public @Nullable AudioDeviceAddress getPreferredDeviceForStrategy(
+ @NonNull AudioProductStrategy strategy) {
+ Objects.requireNonNull(strategy);
+ try {
+ return getService().getPreferredDeviceForStrategy(strategy.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ //====================================================================
// Offload query
/**
* Returns whether offloaded playback of an audio format is supported on the device.
@@ -4962,6 +5033,14 @@ public class AudioManager {
*/
public static final int GET_DEVICES_OUTPUTS = 0x0002;
+ /** @hide */
+ @IntDef(flag = true, prefix = "GET_DEVICES", value = {
+ GET_DEVICES_INPUTS,
+ GET_DEVICES_OUTPUTS }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AudioDeviceRole {}
+
/**
* Specifies to the {@link AudioManager#getDevices(int)} method to include both
* source and sink devices.
@@ -4994,7 +5073,7 @@ public class AudioManager {
* @see #GET_DEVICES_ALL
* @return A (possibly zero-length) array of AudioDeviceInfo objects.
*/
- public AudioDeviceInfo[] getDevices(int flags) {
+ public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
return getDevicesStatic(flags);
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index d64e4ef00164..066bf25179a6 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1173,6 +1173,48 @@ public class AudioSystem
*/
public static native boolean isCallScreeningModeSupported();
+ // use case routing by product strategy
+
+ /**
+ * Sets the preferred device to use for a given audio strategy in the audio policy engine
+ * @param strategy the id of the strategy to configure
+ * @param device the device type and address to route to when available
+ * @return {@link #SUCCESS} if successfully set
+ */
+ public static int setPreferredDeviceForStrategy(
+ int strategy, @NonNull AudioDeviceAddress device) {
+ return setPreferredDeviceForStrategy(strategy,
+ AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()),
+ device.getAddress());
+ }
+ /**
+ * Set device routing per product strategy.
+ * @param strategy the id of the strategy to configure
+ * @param deviceType the native device type, NOT AudioDeviceInfo types
+ * @param deviceAddress the address of the device
+ * @return {@link #SUCCESS} if successfully set
+ */
+ private static native int setPreferredDeviceForStrategy(
+ int strategy, int deviceType, String deviceAddress);
+
+ /**
+ * Remove preferred routing for the strategy
+ * @param strategy the id of the strategy to configure
+ * @return {@link #SUCCESS} if successfully removed
+ */
+ public static native int removePreferredDeviceForStrategy(int strategy);
+
+ /**
+ * Query previously set preferred device for a strategy
+ * @param strategy the id of the strategy to query for
+ * @param device an array of size 1 that will contain the preferred device, or null if
+ * none was set
+ * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved
+ * and written to the array
+ */
+ public static native int getPreferredDeviceForStrategy(int strategy,
+ AudioDeviceAddress[] device);
+
// Items shared with audio service
/**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ef451ce401e6..ad7335e5b683 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,6 +18,7 @@ package android.media;
import android.bluetooth.BluetoothDevice;
import android.media.AudioAttributes;
+import android.media.AudioDeviceAddress;
import android.media.AudioFocusInfo;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
@@ -265,6 +266,12 @@ interface IAudioService {
boolean isCallScreeningModeSupported();
+ int setPreferredDeviceForStrategy(in int strategy, in AudioDeviceAddress device);
+
+ int removePreferredDeviceForStrategy(in int strategy);
+
+ AudioDeviceAddress getPreferredDeviceForStrategy(in int strategy);
+
// WARNING: read warning at top of file, new methods that need to be used by native
// code via IAudioManager.h need to be added to the top section.
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 8080f45642dc..dead066dcdd0 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -46,6 +46,8 @@ import java.util.stream.Collectors;
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
* <tr><td>{@link #KEY_MIME}</td><td>String</td><td>The type of the format.</td></tr>
* <tr><td>{@link #KEY_MAX_INPUT_SIZE}</td><td>Integer</td><td>optional, maximum size of a buffer of input data</td></tr>
+ * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_WIDTH}</td><td>Integer</td><td>optional, the pixel aspect ratio width</td></tr>
+ * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_HEIGHT}</td><td>Integer</td><td>optional, the pixel aspect ratio height</td></tr>
* <tr><td>{@link #KEY_BIT_RATE}</td><td>Integer</td><td><b>encoder-only</b>, desired bitrate in bits/second</td></tr>
* </table>
*
@@ -99,6 +101,8 @@ import java.util.stream.Collectors;
* <tr><td>{@link #KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the maximum number of channels the decoder outputs.</td></tr>
* <tr><td>{@link #KEY_AAC_DRC_EFFECT_TYPE}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the MPEG-D DRC effect type to use.</td></tr>
* <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>optional, a mask of audio channel assignments</td></tr>
+ * <tr><td>{@link #KEY_ENCODER_DELAY}</td><td>Integer</td><td>optional, the number of frames to trim from the start of the decoded audio stream.</td></tr>
+ * <tr><td>{@link #KEY_ENCODER_PADDING}</td><td>Integer</td><td>optional, the number of frames to trim from the end of the decoded audio stream.</td></tr>
* <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr>
* </table>
*
@@ -270,6 +274,18 @@ public final class MediaFormat {
public static final String KEY_MAX_INPUT_SIZE = "max-input-size";
/**
+ * A key describing the pixel aspect ratio width.
+ * The associated value is an integer
+ */
+ public static final String KEY_PIXEL_ASPECT_RATIO_WIDTH = "sar-width";
+
+ /**
+ * A key describing the pixel aspect ratio height.
+ * The associated value is an integer
+ */
+ public static final String KEY_PIXEL_ASPECT_RATIO_HEIGHT = "sar-height";
+
+ /**
* A key describing the average bitrate in bits/sec.
* The associated value is an integer
*/
@@ -569,6 +585,18 @@ public final class MediaFormat {
public static final String KEY_CHANNEL_MASK = "channel-mask";
/**
+ * A key describing the number of frames to trim from the start of the decoded audio stream.
+ * The associated value is an integer.
+ */
+ public static final String KEY_ENCODER_DELAY = "encoder-delay";
+
+ /**
+ * A key describing the number of frames to trim from the end of the decoded audio stream.
+ * The associated value is an integer.
+ */
+ public static final String KEY_ENCODER_PADDING = "encoder-padding";
+
+ /**
* A key describing the AAC profile to be used (AAC audio formats only).
* Constants are declared in {@link android.media.MediaCodecInfo.CodecProfileLevel}.
*/
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 2799d46cbb47..612f83a14e12 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -19,6 +19,7 @@ package android.media.audiopolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.media.AudioAttributes;
import android.media.AudioSystem;
import android.media.MediaRecorder;
@@ -82,6 +83,18 @@ public final class AudioProductStrategy implements Parcelable {
/**
* @hide
+ * Create an invalid AudioProductStrategy instance for testing
+ * @param id the ID for the invalid strategy, always use a different one than in use
+ * @return an invalid instance that cannot successfully be used for volume groups or routing
+ */
+ @TestApi
+ @SystemApi
+ public static @NonNull AudioProductStrategy createInvalidAudioProductStrategy(int id) {
+ return new AudioProductStrategy("dummy strategy", id, new AudioAttributesGroup[0]);
+ }
+
+ /**
+ * @hide
* @param streamType to match against AudioProductStrategy
* @return the AudioAttributes for the first strategy found with the associated stream type
* If no match is found, returns AudioAttributes with unknown content_type and usage
@@ -222,6 +235,7 @@ public final class AudioProductStrategy implements Parcelable {
* @return true if the {@link AudioProductStrategy} supports the given {@link AudioAttributes},
* false otherwise.
*/
+ @SystemApi
public boolean supportsAudioAttributes(@NonNull AudioAttributes aa) {
Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
diff --git a/media/java/android/media/tv/tuner/DvrSettings.java b/media/java/android/media/tv/tuner/DvrSettings.java
new file mode 100644
index 000000000000..76160dc9fcf8
--- /dev/null
+++ b/media/java/android/media/tv/tuner/DvrSettings.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner;
+
+import android.media.tv.tuner.TunerConstants.DataFormat;
+import android.media.tv.tuner.TunerConstants.DvrSettingsType;
+
+/**
+ * DVR settings.
+ *
+ * @hide
+ */
+public class DvrSettings {
+ private int mStatusMask;
+ private int mLowThreshold;
+ private int mHighThreshold;
+ private int mPacketSize;
+
+ @DataFormat
+ private int mDataFormat;
+ @DvrSettingsType
+ private int mType;
+
+ private DvrSettings(int statusMask, int lowThreshold, int highThreshold, int packetSize,
+ @DataFormat int dataFormat, @DvrSettingsType int type) {
+ mStatusMask = statusMask;
+ mLowThreshold = lowThreshold;
+ mHighThreshold = highThreshold;
+ mPacketSize = packetSize;
+ mDataFormat = dataFormat;
+ mType = type;
+ }
+
+ /**
+ * Creates a new builder.
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for DvrSettings.
+ */
+ public static final class Builder {
+ private int mStatusMask;
+ private int mLowThreshold;
+ private int mHighThreshold;
+ private int mPacketSize;
+ @DataFormat
+ private int mDataFormat;
+ @DvrSettingsType
+ private int mType;
+
+ /**
+ * Sets status mask.
+ */
+ public Builder setStatusMask(int statusMask) {
+ this.mStatusMask = statusMask;
+ return this;
+ }
+
+ /**
+ * Sets low threshold.
+ */
+ public Builder setLowThreshold(int lowThreshold) {
+ this.mLowThreshold = lowThreshold;
+ return this;
+ }
+
+ /**
+ * Sets high threshold.
+ */
+ public Builder setHighThreshold(int highThreshold) {
+ this.mHighThreshold = highThreshold;
+ return this;
+ }
+
+ /**
+ * Sets packet size.
+ */
+ public Builder setPacketSize(int packetSize) {
+ this.mPacketSize = packetSize;
+ return this;
+ }
+
+ /**
+ * Sets data format.
+ */
+ public Builder setDataFormat(@DataFormat int dataFormat) {
+ this.mDataFormat = dataFormat;
+ return this;
+ }
+
+ /**
+ * Sets settings type.
+ */
+ public Builder setType(@DvrSettingsType int type) {
+ this.mType = type;
+ return this;
+ }
+
+ /**
+ * Builds a DvrSettings instance.
+ */
+ public DvrSettings build() {
+ return new DvrSettings(
+ mStatusMask, mLowThreshold, mHighThreshold, mPacketSize, mDataFormat, mType);
+ }
+ }
+}
diff --git a/media/java/android/media/tv/tuner/FilterSettings.java b/media/java/android/media/tv/tuner/FilterSettings.java
new file mode 100644
index 000000000000..d5f100341dc6
--- /dev/null
+++ b/media/java/android/media/tv/tuner/FilterSettings.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner;
+
+import android.annotation.Nullable;
+import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerConstants.FilterSettingsType;
+
+import java.util.List;
+
+/**
+ * Demux Filter settings.
+ *
+ * @hide
+ */
+public abstract class FilterSettings {
+ @Nullable
+ protected final Settings mSettings;
+
+ protected FilterSettings(Settings settings) {
+ mSettings = settings;
+ }
+
+ /**
+ * Gets filter settings type
+ */
+ @FilterSettingsType public abstract int getType();
+
+ // TODO: more builders and getters
+
+ /**
+ * Filter Settings for a TS filter.
+ */
+ public static class TsFilterSettings extends FilterSettings {
+ private int mTpid;
+
+ private TsFilterSettings(Settings settings, int tpid) {
+ super(settings);
+ mTpid = tpid;
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_SETTINGS_TS;
+ }
+
+ /**
+ * Creates a new builder.
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for TsFilterSettings.
+ */
+ public static class Builder {
+ private Settings mSettings;
+ private int mTpid;
+
+ /**
+ * Sets settings.
+ */
+ public Builder setSettings(Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
+ * Sets TPID.
+ */
+ public Builder setTpid(int tpid) {
+ mTpid = tpid;
+ return this;
+ }
+
+ /**
+ * Builds a TsFilterSettings instance.
+ */
+ public TsFilterSettings build() {
+ return new TsFilterSettings(mSettings, mTpid);
+ }
+ }
+ }
+
+ /**
+ * Filter Settings for a MMTP filter.
+ */
+ public static class MmtpFilterSettings extends FilterSettings {
+ private int mMmtpPid;
+
+ public MmtpFilterSettings(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_SETTINGS_MMTP;
+ }
+ }
+
+
+ /**
+ * Filter Settings for a IP filter.
+ */
+ public static class IpFilterSettings extends FilterSettings {
+ private byte[] mSrcIpAddress;
+ private byte[] mDstIpAddress;
+ private int mSrcPort;
+ private int mDstPort;
+ private boolean mPassthrough;
+
+ public IpFilterSettings(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_SETTINGS_IP;
+ }
+ }
+
+
+ /**
+ * Filter Settings for a TLV filter.
+ */
+ public static class TlvFilterSettings extends FilterSettings {
+ private int mPacketType;
+ private boolean mIsCompressedIpPacket;
+ private boolean mPassthrough;
+
+ public TlvFilterSettings(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_SETTINGS_TLV;
+ }
+ }
+
+
+ /**
+ * Filter Settings for a ALP filter.
+ */
+ public static class AlpFilterSettings extends FilterSettings {
+ private int mPacketType;
+ private int mLengthType;
+
+ public AlpFilterSettings(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_SETTINGS_ALP;
+ }
+ }
+
+
+ /**
+ * Settings for filters of different subtypes.
+ */
+ public abstract static class Settings {
+ protected final int mType;
+
+ protected Settings(int type) {
+ mType = type;
+ }
+
+ /**
+ * Gets filter settings type.
+ * @return
+ */
+ int getType() {
+ return mType;
+ }
+ }
+
+ /**
+ * Filter Settings for Section data according to ISO/IEC 13818-1.
+ */
+ public static class SectionSettings extends Settings {
+
+ private SectionSettings(int mainType) {
+ super(SectionSettings.findType(mainType));
+ }
+
+ private static int findType(int mainType) {
+ switch (mainType) {
+ case TunerConstants.FILTER_SETTINGS_TS:
+ return Constants.DemuxTsFilterType.SECTION;
+ case TunerConstants.FILTER_SETTINGS_MMTP:
+ return Constants.DemuxMmtpFilterType.SECTION;
+ case TunerConstants.FILTER_SETTINGS_IP:
+ return Constants.DemuxIpFilterType.SECTION;
+ case TunerConstants.FILTER_SETTINGS_TLV:
+ return Constants.DemuxTlvFilterType.SECTION;
+ case TunerConstants.FILTER_SETTINGS_ALP:
+ return Constants.DemuxAlpFilterType.SECTION;
+ }
+ // UNDEFINED
+ return 0;
+ }
+ }
+
+ /**
+ * Bits Settings for Section Filter.
+ */
+ public static class SectionSettingsWithSectionBits extends SectionSettings {
+ private List<Byte> mFilter;
+ private List<Byte> mMask;
+ private List<Byte> mMode;
+
+ private SectionSettingsWithSectionBits(int mainType) {
+ super(mainType);
+ }
+ }
+
+ /**
+ * Table information for Section Filter.
+ */
+ public static class SectionSettingsWithTableInfo extends SectionSettings {
+ private int mTableId;
+ private int mVersion;
+
+ private SectionSettingsWithTableInfo(int mainType) {
+ super(mainType);
+ }
+ }
+
+ /**
+ * Filter Settings for a PES Data.
+ */
+ public static class PesSettings extends Settings {
+ private int mStreamId;
+ private boolean mIsRaw;
+
+ private PesSettings(int mainType, int streamId, boolean isRaw) {
+ super(PesSettings.findType(mainType));
+ mStreamId = streamId;
+ mIsRaw = isRaw;
+ }
+
+ private static int findType(int mainType) {
+ switch (mainType) {
+ case TunerConstants.FILTER_SETTINGS_TS:
+ return Constants.DemuxTsFilterType.PES;
+ case TunerConstants.FILTER_SETTINGS_MMTP:
+ return Constants.DemuxMmtpFilterType.PES;
+ }
+ // UNDEFINED
+ return 0;
+ }
+
+ /**
+ * Creates a builder for PesSettings.
+ */
+ public static Builder newBuilder(int mainType) {
+ return new Builder(mainType);
+ }
+
+ /**
+ * Builder for PesSettings.
+ */
+ public static class Builder {
+ private final int mMainType;
+ private int mStreamId;
+ private boolean mIsRaw;
+
+ public Builder(int mainType) {
+ mMainType = mainType;
+ }
+
+ /**
+ * Sets stream ID.
+ */
+ public Builder setStreamId(int streamId) {
+ mStreamId = streamId;
+ return this;
+ }
+
+ /**
+ * Sets whether it's raw.
+ * true if the filter send onFilterStatus instead of onFilterEvent.
+ */
+ public Builder setIsRaw(boolean isRaw) {
+ mIsRaw = isRaw;
+ return this;
+ }
+
+ /**
+ * Builds a PesSettings instance.
+ */
+ public PesSettings build() {
+ return new PesSettings(mMainType, mStreamId, mIsRaw);
+ }
+ }
+ }
+
+ /**
+ * Filter Settings for a Video and Audio.
+ */
+ public static class AvSettings extends Settings {
+ private boolean mIsPassthrough;
+
+ private AvSettings(int mainType, boolean isAudio) {
+ super(AvSettings.findType(mainType, isAudio));
+ }
+
+ private static int findType(int mainType, boolean isAudio) {
+ switch (mainType) {
+ case TunerConstants.FILTER_SETTINGS_TS:
+ return isAudio
+ ? Constants.DemuxTsFilterType.AUDIO
+ : Constants.DemuxTsFilterType.VIDEO;
+ case TunerConstants.FILTER_SETTINGS_MMTP:
+ return isAudio
+ ? Constants.DemuxMmtpFilterType.AUDIO
+ : Constants.DemuxMmtpFilterType.VIDEO;
+ }
+ // UNDEFINED
+ return 0;
+ }
+ }
+
+ /**
+ * Filter Settings for a Download.
+ */
+ public static class DownloadSettings extends Settings {
+ private int mDownloadId;
+
+ public DownloadSettings(int mainType) {
+ super(DownloadSettings.findType(mainType));
+ }
+
+ private static int findType(int mainType) {
+ if (mainType == TunerConstants.FILTER_SETTINGS_MMTP) {
+ return Constants.DemuxMmtpFilterType.DOWNLOAD;
+ }
+ // UNDEFINED
+ return 0;
+ }
+ }
+
+ /**
+ * The Settings for the record in DVR.
+ */
+ public static class RecordSettings extends Settings {
+ private int mIndexType;
+ private int mIndexMask;
+
+ public RecordSettings(int mainType) {
+ super(RecordSettings.findType(mainType));
+ }
+
+ private static int findType(int mainType) {
+ switch (mainType) {
+ case TunerConstants.FILTER_SETTINGS_TS:
+ return Constants.DemuxTsFilterType.RECORD;
+ case TunerConstants.FILTER_SETTINGS_MMTP:
+ return Constants.DemuxMmtpFilterType.RECORD;
+ }
+ // UNDEFINED
+ return 0;
+ }
+ }
+
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 82cef2e43307..4c93101bc0b5 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -243,9 +243,11 @@ public final class Tuner implements AutoCloseable {
private FilterCallback mCallback;
int mId;
+ private native int nativeConfigureFilter(int type, int subType, FilterSettings settings);
private native boolean nativeStartFilter();
private native boolean nativeStopFilter();
private native boolean nativeFlushFilter();
+ private native int nativeRead(byte[] buffer, int offset, int size);
private Filter(int id) {
mId = id;
@@ -258,6 +260,14 @@ public final class Tuner implements AutoCloseable {
}
}
+ public int configure(FilterSettings settings) {
+ int subType = -1;
+ if (settings.mSettings != null) {
+ subType = settings.mSettings.getType();
+ }
+ return nativeConfigureFilter(settings.getType(), subType, settings);
+ }
+
public boolean start() {
return nativeStartFilter();
}
@@ -269,6 +279,11 @@ public final class Tuner implements AutoCloseable {
public boolean flush() {
return nativeFlushFilter();
}
+
+ public int read(@NonNull byte[] buffer, int offset, int size) {
+ size = Math.min(size, buffer.length - offset);
+ return nativeRead(buffer, offset, size);
+ }
}
private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) {
@@ -353,6 +368,7 @@ public final class Tuner implements AutoCloseable {
private native boolean nativeAttachFilter(Filter filter);
private native boolean nativeDetachFilter(Filter filter);
+ private native int nativeConfigureDvr(DvrSettings settings);
private native boolean nativeStartDvr();
private native boolean nativeStopDvr();
private native boolean nativeFlushDvr();
@@ -365,6 +381,9 @@ public final class Tuner implements AutoCloseable {
public boolean detachFilter(Filter filter) {
return nativeDetachFilter(filter);
}
+ public int configure(DvrSettings settings) {
+ return nativeConfigureDvr(settings);
+ }
public boolean start() {
return nativeStartDvr();
}
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index 458cb1678ded..261b2deebac9 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -90,6 +90,24 @@ final class TunerConstants {
public static final int FRONTEND_SETTINGS_ISDBS3 = 8;
public static final int FRONTEND_SETTINGS_ISDBT = 9;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV,
+ FILTER_SETTINGS_ALP})
+ public @interface FilterSettingsType {}
+
+ public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS;
+ public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP;
+ public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP;
+ public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV;
+ public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DVR_SETTINGS_RECORD, DVR_SETTINGS_PLAYBACK})
+ public @interface DvrSettingsType {}
+
+ public static final int DVR_SETTINGS_RECORD = Constants.DvrType.RECORD;
+ public static final int DVR_SETTINGS_PLAYBACK = Constants.DvrType.PLAYBACK;
+
private TunerConstants() {
}
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 12b3e6735d81..4ca23a1084a2 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -135,6 +135,8 @@ cc_library_shared {
shared_libs: [
"android.hardware.tv.tuner@1.0",
"libandroid_runtime",
+ "libcutils",
+ "libfmq",
"libhidlbase",
"liblog",
"libutils",
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5216906d5ec5..9304450dc271 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -27,14 +27,22 @@
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
+using ::android::hardware::tv::tuner::V1_0::DataFormat;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid;
+using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
using ::android::hardware::tv::tuner::V1_0::DemuxTpid;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using ::android::hardware::tv::tuner::V1_0::DvrSettings;
using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings;
using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
using ::android::hardware::tv::tuner::V1_0::FrontendAnalogType;
using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using ::android::hardware::tv::tuner::V1_0::RecordSettings;
using ::android::hardware::tv::tuner::V1_0::Result;
struct fields_t {
@@ -89,6 +97,14 @@ void DvrCallback::setDvr(const jobject dvr) {
mDvr = env->NewWeakGlobalRef(dvr);
}
+/////////////// Dvr ///////////////////////
+
+Dvr::Dvr(sp<IDvr> sp, jweak obj) : mDvrSp(sp), mDvrObj(obj) {}
+
+sp<IDvr> Dvr::getIDvr() {
+ return mDvrSp;
+}
+
/////////////// FilterCallback ///////////////////////
//TODO: implement filter callback
Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /*filterEvent*/) {
@@ -112,6 +128,26 @@ void FilterCallback::setFilter(const jobject filter) {
mFilter = env->NewWeakGlobalRef(filter);
}
+/////////////// Filter ///////////////////////
+
+Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {}
+
+Filter::~Filter() {
+ EventFlag::deleteEventFlag(&mFilterMQEventFlag);
+}
+
+int Filter::close() {
+ Result r = mFilterSp->close();
+ if (r == Result::SUCCESS) {
+ EventFlag::deleteEventFlag(&mFilterMQEventFlag);
+ }
+ return (int)r;
+}
+
+sp<IFilter> Filter::getIFilter() {
+ return mFilterSp;
+}
+
/////////////// FrontendCallback ///////////////////////
FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
@@ -211,6 +247,7 @@ jobject JTuner::openFrontendById(int id) {
fe->setCallback(feCb);
jint jId = (jint) id;
+
JNIEnv *env = AndroidRuntime::getJNIEnv();
// TODO: add more fields to frontend
return env->NewObject(
@@ -327,18 +364,18 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
}
}
- sp<IFilter> filterSp;
+ sp<IFilter> iFilterSp;
sp<FilterCallback> callback = new FilterCallback();
mDemux->openFilter(type, bufferSize, callback,
[&](Result, const sp<IFilter>& filter) {
- filterSp = filter;
+ iFilterSp = filter;
});
- if (filterSp == NULL) {
+ if (iFilterSp == NULL) {
ALOGD("Failed to open filter, type = %d", type.mainType);
return NULL;
}
int fId;
- filterSp->getId([&](Result, uint32_t filterId) {
+ iFilterSp->getId([&](Result, uint32_t filterId) {
fId = filterId;
});
@@ -350,6 +387,7 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
mObject,
(jint) fId);
+ sp<Filter> filterSp = new Filter(iFilterSp, filterObj);
filterSp->incStrong(filterObj);
env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
@@ -365,14 +403,14 @@ jobject JTuner::openDvr(DvrType type, int bufferSize) {
return NULL;
}
}
- sp<IDvr> dvrSp;
+ sp<IDvr> iDvrSp;
sp<DvrCallback> callback = new DvrCallback();
mDemux->openDvr(type, bufferSize, callback,
[&](Result, const sp<IDvr>& dvr) {
- dvrSp = dvr;
+ iDvrSp = dvr;
});
- if (dvrSp == NULL) {
+ if (iDvrSp == NULL) {
return NULL;
}
@@ -382,7 +420,7 @@ jobject JTuner::openDvr(DvrType type, int bufferSize) {
env->FindClass("android/media/tv/tuner/Tuner$Dvr"),
gFields.dvrInitID,
mObject);
-
+ sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
dvrSp->incStrong(dvrObj);
env->SetLongField(dvrObj, gFields.dvrContext, (jlong)dvrSp.get());
@@ -432,7 +470,7 @@ static DemuxPid getDemuxPid(int pidType, int pid) {
static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) {
FrontendSettings frontendSettings;
jclass clazz = env->FindClass("android/media/tv/tuner/FrontendSettings");
- jfieldID freqField = env->GetFieldID(clazz, "frequency", "I");
+ jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I");
uint32_t freq = static_cast<uint32_t>(env->GetIntField(clazz, freqField));
// TODO: handle the other 8 types of settings
@@ -455,12 +493,55 @@ static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject setti
return frontendSettings;
}
-static sp<IFilter> getFilter(JNIEnv *env, jobject filter) {
- return (IFilter *)env->GetLongField(filter, gFields.filterContext);
+static sp<Filter> getFilter(JNIEnv *env, jobject filter) {
+ return (Filter *)env->GetLongField(filter, gFields.filterContext);
+}
+
+static DvrSettings getDvrSettings(JNIEnv *env, jobject settings) {
+ DvrSettings dvrSettings;
+ jclass clazz = env->FindClass("android/media/tv/tuner/DvrSettings");
+ uint32_t statusMask =
+ static_cast<uint32_t>(env->GetIntField(
+ settings, env->GetFieldID(clazz, "mStatusMask", "I")));
+ uint32_t lowThreshold =
+ static_cast<uint32_t>(env->GetIntField(
+ settings, env->GetFieldID(clazz, "mLowThreshold", "I")));
+ uint32_t highThreshold =
+ static_cast<uint32_t>(env->GetIntField(
+ settings, env->GetFieldID(clazz, "mHighThreshold", "I")));
+ uint8_t packetSize =
+ static_cast<uint8_t>(env->GetIntField(
+ settings, env->GetFieldID(clazz, "mPacketSize", "I")));
+ DataFormat dataFormat =
+ static_cast<DataFormat>(env->GetIntField(
+ settings, env->GetFieldID(clazz, "mDataFormat", "I")));
+ DvrType type =
+ static_cast<DvrType>(env->GetIntField(
+ settings, env->GetFieldID(clazz, "mType", "I")));
+ if (type == DvrType::RECORD) {
+ RecordSettings recordSettings {
+ .statusMask = static_cast<unsigned char>(statusMask),
+ .lowThreshold = lowThreshold,
+ .highThreshold = highThreshold,
+ .dataFormat = dataFormat,
+ .packetSize = packetSize,
+ };
+ dvrSettings.record(recordSettings);
+ } else if (type == DvrType::PLAYBACK) {
+ PlaybackSettings PlaybackSettings {
+ .statusMask = statusMask,
+ .lowThreshold = lowThreshold,
+ .highThreshold = highThreshold,
+ .dataFormat = dataFormat,
+ .packetSize = packetSize,
+ };
+ dvrSettings.playback(PlaybackSettings);
+ }
+ return dvrSettings;
}
-static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) {
- return (IDvr *)env->GetLongField(dvr, gFields.dvrContext);
+static sp<Dvr> getDvr(JNIEnv *env, jobject dvr) {
+ return (Dvr *)env->GetLongField(dvr, gFields.dvrContext);
}
static void android_media_tv_Tuner_native_init(JNIEnv *env) {
@@ -542,8 +623,100 @@ static jobject android_media_tv_Tuner_open_filter(
return tuner->openFilter(filterType, bufferSize);
}
+static DemuxFilterSettings getFilterSettings(
+ JNIEnv *env, int type, int subtype, jobject filterSettingsObj) {
+ DemuxFilterSettings filterSettings;
+ // TODO: more setting types
+ jobject settingsObj =
+ env->GetObjectField(
+ filterSettingsObj,
+ env->GetFieldID(
+ env->FindClass("android/media/tv/tuner/FilterSettings"),
+ "mSettings",
+ "Landroid/media/tv/tuner/FilterSettings$Settings;"));
+ if (type == (int)DemuxFilterMainType::TS) {
+ // DemuxTsFilterSettings
+ jclass clazz = env->FindClass("android/media/tv/tuner/FilterSettings$TsFilterSettings");
+ int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I"));
+ if (subtype == (int)DemuxTsFilterType::PES) {
+ // DemuxFilterPesDataSettings
+ jclass settingClazz =
+ env->FindClass("android/media/tv/tuner/FilterSettings$PesSettings");
+ int streamId = env->GetIntField(
+ settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I"));
+ bool isRaw = (bool)env->GetBooleanField(
+ settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z"));
+ DemuxFilterPesDataSettings filterPesDataSettings {
+ .streamId = static_cast<uint16_t>(streamId),
+ .isRaw = isRaw,
+ };
+ DemuxTsFilterSettings tsFilterSettings {
+ .tpid = static_cast<uint16_t>(tpid),
+ };
+ tsFilterSettings.filterSettings.pesData(filterPesDataSettings);
+ filterSettings.ts(tsFilterSettings);
+ }
+ }
+ return filterSettings;
+}
+
+static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) {
+ ALOGD("copyData, size=%d, offset=%d", size, offset);
+
+ int available = filter->mFilterMQ->availableToRead();
+ ALOGD("copyData, available=%d", available);
+ size = std::min(size, available);
+
+ jboolean isCopy;
+ jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
+ ALOGD("copyData, isCopy=%d", isCopy);
+ if (dst == nullptr) {
+ ALOGD("Failed to GetByteArrayElements");
+ return 0;
+ }
+
+ if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) {
+ env->ReleaseByteArrayElements(buffer, dst, 0);
+ filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+ } else {
+ ALOGD("Failed to read FMQ");
+ env->ReleaseByteArrayElements(buffer, dst, 0);
+ return 0;
+ }
+ return size;
+}
+
+static int android_media_tv_Tuner_configure_filter(
+ JNIEnv *env, jobject filter, int type, int subtype, jobject settings) {
+ ALOGD("configure filter type=%d, subtype=%d", type, subtype);
+ sp<Filter> filterSp = getFilter(env, filter);
+ sp<IFilter> iFilterSp = filterSp->getIFilter();
+ if (iFilterSp == NULL) {
+ ALOGD("Failed to configure filter: filter not found");
+ return (int)Result::INVALID_STATE;
+ }
+ DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings);
+ Result res = iFilterSp->configure(filterSettings);
+ MQDescriptorSync<uint8_t> filterMQDesc;
+ if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) {
+ Result getQueueDescResult = Result::UNKNOWN_ERROR;
+ iFilterSp->getQueueDesc(
+ [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
+ filterMQDesc = desc;
+ getQueueDescResult = r;
+ ALOGD("getFilterQueueDesc");
+ });
+ if (getQueueDescResult == Result::SUCCESS) {
+ filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true);
+ EventFlag::createEventFlag(
+ filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag));
+ }
+ }
+ return (int)res;
+}
+
static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> filterSp = getFilter(env, filter);
+ sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
if (filterSp == NULL) {
ALOGD("Failed to start filter: filter not found");
return false;
@@ -552,7 +725,7 @@ static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
}
static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> filterSp = getFilter(env, filter);
+ sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
if (filterSp == NULL) {
ALOGD("Failed to stop filter: filter not found");
return false;
@@ -561,7 +734,7 @@ static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
}
static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> filterSp = getFilter(env, filter);
+ sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
if (filterSp == NULL) {
ALOGD("Failed to flush filter: filter not found");
return false;
@@ -569,6 +742,16 @@ static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
return filterSp->flush() == Result::SUCCESS;
}
+static int android_media_tv_Tuner_read_filter_fmq(
+ JNIEnv *env, jobject filter, jbyteArray buffer, jint offset, jint size) {
+ sp<Filter> filterSp = getFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed to read filter FMQ: filter not found");
+ return 0;
+ }
+ return copyData(env, filterSp, buffer, offset, size);
+}
+
static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->openDescrambler();
@@ -580,7 +763,7 @@ static bool android_media_tv_Tuner_add_pid(
if (descramblerSp == NULL) {
return false;
}
- sp<IFilter> filterSp = getFilter(env, filter);
+ sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp);
return result == Result::SUCCESS;
}
@@ -591,7 +774,7 @@ static bool android_media_tv_Tuner_remove_pid(
if (descramblerSp == NULL) {
return false;
}
- sp<IFilter> filterSp = getFilter(env, filter);
+ sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp);
return result == Result::SUCCESS;
}
@@ -602,8 +785,8 @@ static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint t
}
static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
- sp<IDvr> dvrSp = getDvr(env, dvr);
- sp<IFilter> filterSp = getFilter(env, filter);
+ sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
+ sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
if (dvrSp == NULL || filterSp == NULL) {
return false;
}
@@ -612,8 +795,8 @@ static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobje
}
static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
- sp<IDvr> dvrSp = getDvr(env, dvr);
- sp<IFilter> filterSp = getFilter(env, filter);
+ sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
+ sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
if (dvrSp == NULL || filterSp == NULL) {
return false;
}
@@ -621,8 +804,18 @@ static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobje
return result == Result::SUCCESS;
}
+static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
+ sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
+ if (dvrSp == NULL) {
+ ALOGD("Failed to configure dvr: dvr not found");
+ return (int)Result::INVALID_STATE;
+ }
+ Result result = dvrSp->configure(getDvrSettings(env, settings));
+ return (int)result;
+}
+
static bool android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
- sp<IDvr> dvrSp = getDvr(env, dvr);
+ sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
if (dvrSp == NULL) {
ALOGD("Failed to start dvr: dvr not found");
return false;
@@ -631,7 +824,7 @@ static bool android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
}
static bool android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
- sp<IDvr> dvrSp = getDvr(env, dvr);
+ sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
if (dvrSp == NULL) {
ALOGD("Failed to stop dvr: dvr not found");
return false;
@@ -640,7 +833,7 @@ static bool android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
}
static bool android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
- sp<IDvr> dvrSp = getDvr(env, dvr);
+ sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
if (dvrSp == NULL) {
ALOGD("Failed to flush dvr: dvr not found");
return false;
@@ -670,9 +863,12 @@ static const JNINativeMethod gTunerMethods[] = {
};
static const JNINativeMethod gFilterMethods[] = {
+ { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/FilterSettings;)I",
+ (void *)android_media_tv_Tuner_configure_filter },
{ "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter },
{ "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter },
{ "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter },
+ { "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq },
};
static const JNINativeMethod gDescramblerMethods[] = {
@@ -687,6 +883,8 @@ static const JNINativeMethod gDvrMethods[] = {
(void *)android_media_tv_Tuner_attach_filter },
{ "nativeDetachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z",
(void *)android_media_tv_Tuner_detach_filter },
+ { "nativeConfigureDvr", "(Landroid/media/tv/tuner/DvrSettings;)I",
+ (void *)android_media_tv_Tuner_configure_dvr },
{ "nativeStartDvr", "()Z", (void *)android_media_tv_Tuner_start_dvr },
{ "nativeStopDvr", "()Z", (void *)android_media_tv_Tuner_stop_dvr },
{ "nativeFlushDvr", "()Z", (void *)android_media_tv_Tuner_flush_dvr },
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index f856791e2618..9f9fb2748581 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -18,13 +18,18 @@
#define _ANDROID_MEDIA_TV_TUNER_H_
#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <fmq/MessageQueue.h>
#include <unordered_map>
#include <utils/RefBase.h>
#include "jni.h"
+using ::android::hardware::EventFlag;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::MessageQueue;
using ::android::hardware::Return;
using ::android::hardware::hidl_vec;
+using ::android::hardware::kSynchronizedReadWrite;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
@@ -51,6 +56,8 @@ using ::android::hardware::tv::tuner::V1_0::LnbId;
using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
using ::android::hardware::tv::tuner::V1_0::RecordStatus;
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
namespace android {
struct LnbCallback : public ILnbCallback {
@@ -70,6 +77,13 @@ private:
jweak mDvr;
};
+struct Dvr : public RefBase {
+ Dvr(sp<IDvr> sp, jweak obj);
+ sp<IDvr> getIDvr();
+ sp<IDvr> mDvrSp;
+ jweak mDvrObj;
+};
+
struct FilterCallback : public IFilterCallback {
virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
@@ -91,6 +105,17 @@ struct FrontendCallback : public IFrontendCallback {
FrontendId mId;
};
+struct Filter : public RefBase {
+ Filter(sp<IFilter> sp, jweak obj);
+ ~Filter();
+ int close();
+ sp<IFilter> getIFilter();
+ sp<IFilter> mFilterSp;
+ std::unique_ptr<FilterMQ> mFilterMQ;
+ EventFlag* mFilterMQEventFlag;
+ jweak mFilterObj;
+};
+
struct JTuner : public RefBase {
JTuner(JNIEnv *env, jobject thiz);
sp<ITuner> getTunerService();
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
index 41ab6703a579..5ba5c0159275 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/Android.bp
@@ -17,6 +17,7 @@ cc_library_shared {
"libnativehelper",
"libaudioclient",
"libaudioutils",
+ "libaudiofoundation",
],
version_script: "exports.lds",
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 45430197fdd8..291cdd5ea3d8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -35,6 +35,7 @@ import android.view.ViewStub;
import androidx.recyclerview.widget.GridLayoutManager;
+import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.dagger.qualifiers.MainResources;
@@ -135,8 +136,9 @@ public class FullscreenUserSwitcher {
/* isAddUser= */ false,
/* isForeground= */ true);
- // If the initial user has trusted device, display the unlock dialog on the keyguard.
- if (hasTrustedDevice(initialUser)) {
+ // If the initial user has screen lock and trusted device, display the unlock dialog on the
+ // keyguard.
+ if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) {
mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
mOnHideListener);
} else {
@@ -178,7 +180,7 @@ public class FullscreenUserSwitcher {
*/
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
mSelectedUser = record;
- if (hasTrustedDevice(record.mInfo.id)) {
+ if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) {
mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener);
return;
}
@@ -216,6 +218,12 @@ public class FullscreenUserSwitcher {
}
+ private boolean hasScreenLock(int uid) {
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+ return lockPatternUtils.getCredentialTypeForUser(uid)
+ != LockPatternUtils.CREDENTIAL_TYPE_NONE;
+ }
+
private boolean hasTrustedDevice(int uid) {
if (mEnrollmentManager == null) { // car service not ready, so it cannot be available.
return false;
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 80240affc1c1..ade292f2e411 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -40,6 +40,8 @@
<string name="wifi_security_short_sae" translatable="false">WPA3</string>
<!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 transition security -->
<string name="wifi_security_short_psk_sae" translatable="false">WPA2/WPA3</string>
+ <!-- Do not translate. Concise terminology for Wi-Fi with None/OWE transition mode security -->
+ <string name="wifi_security_short_none_owe" translatable="false">None/OWE</string>
<!-- Do not translate. Concise terminology for wifi with OWE security -->
<string name="wifi_security_short_owe" translatable="false">OWE</string>
<!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
@@ -70,6 +72,8 @@
<string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
<!-- Do not translate. Terminology for wifi with WPA2/WPA3 Transition mode security -->
<string name="wifi_security_psk_sae" translatable="false">WPA2/WPA3-Personal</string>
+ <!-- Do not translate. Terminology for Wi-Fi with None/OWE transition mode security -->
+ <string name="wifi_security_none_owe" translatable="false">None/Enhanced Open</string>
<!-- Do not translate. Terminology for wifi with OWE security -->
<string name="wifi_security_owe" translatable="false">Enhanced Open</string>
<!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
@@ -957,7 +961,7 @@
<!-- Title for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
<string name="accessibility_display_daltonizer_preference_title">Color correction</string>
<!-- Subtitle for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
- <string name="accessibility_display_daltonizer_preference_subtitle">This feature is experimental and may affect performance.</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps people with color blindness to see more accurate colors</string>
<!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
<string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 96aee512c090..a2bd210b67a6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -155,8 +155,8 @@ public class A2dpProfile implements LocalBluetoothProfile {
public boolean disconnect(BluetoothDevice device) {
if (mService == null) return false;
// Downgrade priority as user is disconnecting the headset.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -179,23 +179,29 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return false;
+ }
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
- return mService.getPriority(device);
+ if (mService == null) {
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
boolean isA2dpPlaying() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 55765dd40d36..9c896c80b409 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -124,8 +124,8 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
return false;
}
// Downgrade priority as user is disconnecting the headset.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -141,14 +141,14 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.PRIORITY_OFF;
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
- return mService.getPriority(device);
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
@@ -156,11 +156,11 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 9f7b7181b19f..560cb3b9b5b4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -120,8 +120,8 @@ public class HeadsetProfile implements LocalBluetoothProfile {
return false;
}
// Downgrade priority as user is disconnecting the headset.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -165,14 +165,14 @@ public class HeadsetProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.PRIORITY_OFF;
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
- return mService.getPriority(device);
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
@@ -180,11 +180,11 @@ public class HeadsetProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index ebaeb742b198..58655a2b930a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -153,8 +153,8 @@ public class HearingAidProfile implements LocalBluetoothProfile {
public boolean disconnect(BluetoothDevice device) {
if (mService == null) return false;
// Downgrade priority as user is disconnecting the hearing aid.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -177,23 +177,29 @@ public class HearingAidProfile implements LocalBluetoothProfile {
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return false;
+ }
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
- return mService.getPriority(device);
+ if (mService == null) {
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 860b77d1ebcd..a372e23654e0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -135,8 +135,8 @@ final class HfpClientProfile implements LocalBluetoothProfile {
return false;
}
// Downgrade priority as user is disconnecting the headset.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -154,15 +154,15 @@ final class HfpClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
@Override
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.PRIORITY_OFF;
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
- return mService.getPriority(device);
+ return mService.getConnectionPolicy(device);
}
@Override
@@ -171,11 +171,11 @@ final class HfpClientProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 6d874ab2be9b..975a1e67af5b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -116,23 +116,27 @@ public class HidProfile implements LocalBluetoothProfile {
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.getPriority(device) != BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return false;
+ }
+ return mService.getConnectionPolicy(device) != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
- return mService.getPriority(device);
+ if (mService == null) {
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
if (mService == null) return;
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index d4dda329fa63..95139a1bfab9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -123,8 +123,8 @@ public final class MapClientProfile implements LocalBluetoothProfile {
return false;
}
// Downgrade priority as user is disconnecting.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -140,14 +140,14 @@ public final class MapClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.PRIORITY_OFF;
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
- return mService.getPriority(device);
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
@@ -155,11 +155,11 @@ public final class MapClientProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index b2a9a6a28231..31a0eea56b42 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -119,8 +119,8 @@ public class MapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -136,14 +136,14 @@ public class MapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.PRIORITY_OFF;
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
- return mService.getPriority(device);
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
@@ -151,11 +151,11 @@ public class MapProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index e1e5dbe29a1a..8e3f3edcef10 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -57,7 +57,7 @@ final class OppProfile implements LocalBluetoothProfile {
}
public int getPreferred(BluetoothDevice device) {
- return BluetoothProfile.PRIORITY_OFF; // Settings app doesn't handle OPP
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; // Settings app doesn't handle OPP
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index a2da4fb30e39..4ea0df621bea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -151,14 +151,14 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.PRIORITY_OFF;
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
- return mService.getPriority(device);
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
@@ -166,11 +166,11 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 9b733f2e0e50..0ca4d6195a32 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -119,8 +119,8 @@ final class SapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
return mService.disconnect(device);
}
@@ -136,14 +136,14 @@ final class SapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.PRIORITY_OFF;
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
}
- return mService.getPriority(device);
+ return mService.getConnectionPolicy(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
@@ -151,11 +151,11 @@ final class SapProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index b0bdf1dd8594..49e214beaa1e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -188,6 +188,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
static final String KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS =
"key_subscription_expiration_time_in_millis";
static final String KEY_PASSPOINT_CONFIGURATION_VERSION = "key_passpoint_configuration_version";
+ static final String KEY_IS_PSK_SAE_TRANSITION_MODE = "key_is_psk_sae_transition_mode";
+ static final String KEY_IS_OWE_TRANSITION_MODE = "key_is_owe_transition_mode";
static final AtomicInteger sLastId = new AtomicInteger(0);
/*
@@ -202,15 +204,12 @@ public class AccessPoint implements Comparable<AccessPoint> {
public static final int SECURITY_OWE = 4;
public static final int SECURITY_SAE = 5;
public static final int SECURITY_EAP_SUITE_B = 6;
- public static final int SECURITY_PSK_SAE_TRANSITION = 7;
- public static final int SECURITY_OWE_TRANSITION = 8;
- public static final int SECURITY_MAX_VAL = 9; // Has to be the last
+ public static final int SECURITY_MAX_VAL = 7; // Has to be the last
private static final int PSK_UNKNOWN = 0;
private static final int PSK_WPA = 1;
private static final int PSK_WPA2 = 2;
private static final int PSK_WPA_WPA2 = 3;
- private static final int PSK_SAE = 4;
private static final int EAP_UNKNOWN = 0;
private static final int EAP_WPA = 1; // WPA-EAP
@@ -274,6 +273,9 @@ public class AccessPoint implements Comparable<AccessPoint> {
private String mOsuFailure;
private boolean mOsuProvisioningComplete = false;
+ private boolean mIsPskSaeTransitionMode = false;
+ private boolean mIsOweTransitionMode = false;
+
/**
* The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
*/
@@ -344,6 +346,13 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (savedState.containsKey(KEY_PASSPOINT_CONFIGURATION_VERSION)) {
mPasspointConfigurationVersion = savedState.getInt(KEY_PASSPOINT_CONFIGURATION_VERSION);
}
+ if (savedState.containsKey(KEY_IS_PSK_SAE_TRANSITION_MODE)) {
+ mIsPskSaeTransitionMode = savedState.getBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE);
+ }
+ if (savedState.containsKey(KEY_IS_OWE_TRANSITION_MODE)) {
+ mIsOweTransitionMode = savedState.getBoolean(KEY_IS_OWE_TRANSITION_MODE);
+ }
+
update(mConfig, mInfo, mNetworkInfo);
// Calculate required fields
@@ -675,8 +684,15 @@ public class AccessPoint implements Comparable<AccessPoint> {
return oldMetering == mIsScoredNetworkMetered;
}
- public static String getKey(ScanResult result) {
- return getKey(result.SSID, result.BSSID, getSecurity(result));
+ /**
+ * Generates an AccessPoint key for a given scan result
+ *
+ * @param context
+ * @param result Scan result
+ * @return AccessPoint key
+ */
+ public static String getKey(Context context, ScanResult result) {
+ return getKey(result.SSID, result.BSSID, getSecurity(context, result));
}
/**
@@ -734,7 +750,42 @@ public class AccessPoint implements Comparable<AccessPoint> {
* Determines if the other AccessPoint represents the same network as this AccessPoint
*/
public boolean matches(AccessPoint other) {
- return getKey().equals(other.getKey());
+ if (isPasspoint() || isPasspointConfig() || isOsuProvider()) {
+ return getKey().equals(other.getKey());
+ }
+
+ if (!isSameSsidOrBssid(other)) {
+ return false;
+ }
+
+ final int otherApSecurity = other.getSecurity();
+ if (mIsPskSaeTransitionMode) {
+ if (otherApSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) {
+ return true;
+ } else if (otherApSecurity == SECURITY_PSK) {
+ return true;
+ }
+ } else {
+ if ((security == SECURITY_SAE || security == SECURITY_PSK)
+ && other.isPskSaeTransitionMode()) {
+ return true;
+ }
+ }
+
+ if (mIsOweTransitionMode) {
+ if (otherApSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
+ return true;
+ } else if (otherApSecurity == SECURITY_NONE) {
+ return true;
+ }
+ } else {
+ if ((security == SECURITY_OWE || security == SECURITY_NONE)
+ && other.isOweTransitionMode()) {
+ return true;
+ }
+ }
+
+ return security == other.getSecurity();
}
public boolean matches(WifiConfiguration config) {
@@ -748,18 +799,77 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
final int configSecurity = getSecurity(config);
- final WifiManager wifiManager = getWifiManager();
- switch (security) {
- case SECURITY_PSK_SAE_TRANSITION:
- return configSecurity == SECURITY_PSK
- || (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE);
- case SECURITY_OWE_TRANSITION:
- return configSecurity == SECURITY_NONE
- || (wifiManager.isEnhancedOpenSupported()
- && configSecurity == SECURITY_OWE);
- default:
- return security == configSecurity;
+ if (mIsPskSaeTransitionMode) {
+ if (configSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) {
+ return true;
+ } else if (configSecurity == SECURITY_PSK) {
+ return true;
+ }
+ }
+
+ if (mIsOweTransitionMode) {
+ if (configSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
+ return true;
+ } else if (configSecurity == SECURITY_NONE) {
+ return true;
+ }
+ }
+
+ return security == getSecurity(config);
+ }
+
+ private boolean matches(WifiConfiguration config, WifiInfo wifiInfo) {
+ if (config == null || wifiInfo == null) {
+ return false;
+ }
+ if (!config.isPasspoint() && !isSameSsidOrBssid(wifiInfo)) {
+ return false;
+ }
+ return matches(config);
+ }
+
+ @VisibleForTesting
+ boolean matches(ScanResult scanResult) {
+ if (scanResult == null) {
+ return false;
+ }
+ if (isPasspoint() || isOsuProvider()) {
+ throw new IllegalStateException("Should not matches a Passpoint by ScanResult");
+ }
+
+ if (!isSameSsidOrBssid(scanResult)) {
+ return false;
+ }
+
+ if (mIsPskSaeTransitionMode) {
+ if (scanResult.capabilities.contains("SAE")
+ && getWifiManager().isWpa3SaeSupported()) {
+ return true;
+ } else if (scanResult.capabilities.contains("PSK")) {
+ return true;
+ }
+ } else {
+ if ((security == SECURITY_SAE || security == SECURITY_PSK)
+ && AccessPoint.isPskSaeTransitionMode(scanResult)) {
+ return true;
+ }
+ }
+
+ if (mIsOweTransitionMode) {
+ final int scanResultSccurity = getSecurity(mContext, scanResult);
+ if (scanResultSccurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
+ return true;
+ } else if (scanResultSccurity == SECURITY_NONE) {
+ return true;
+ }
+ } else {
+ if ((security == SECURITY_OWE || security == SECURITY_NONE)
+ && AccessPoint.isOweTransitionMode(scanResult)) {
+ return true;
+ }
}
+
+ return security == getSecurity(mContext, scanResult);
}
public WifiConfiguration getConfig() {
@@ -846,14 +956,17 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (bestResult != null) {
ssid = bestResult.SSID;
bssid = bestResult.BSSID;
- security = getSecurity(bestResult);
- if (security == SECURITY_PSK || security == SECURITY_SAE
- || security == SECURITY_PSK_SAE_TRANSITION) {
+ security = getSecurity(mContext, bestResult);
+ if (security == SECURITY_PSK || security == SECURITY_SAE) {
pskType = getPskType(bestResult);
}
if (security == SECURITY_EAP) {
mEapType = getEapType(bestResult);
}
+
+ mIsPskSaeTransitionMode = AccessPoint.isPskSaeTransitionMode(bestResult);
+ mIsOweTransitionMode = AccessPoint.isOweTransitionMode(bestResult);
+
mIsCarrierAp = bestResult.isCarrierAp;
mCarrierApEapType = bestResult.carrierApEapType;
mCarrierName = bestResult.carrierName;
@@ -886,6 +999,16 @@ public class AccessPoint implements Comparable<AccessPoint> {
return concise ? context.getString(R.string.wifi_security_short_eap) :
context.getString(R.string.wifi_security_eap);
}
+
+ if (mIsPskSaeTransitionMode) {
+ return concise ? context.getString(R.string.wifi_security_short_psk_sae) :
+ context.getString(R.string.wifi_security_psk_sae);
+ }
+ if (mIsOweTransitionMode) {
+ return concise ? context.getString(R.string.wifi_security_short_none_owe) :
+ context.getString(R.string.wifi_security_none_owe);
+ }
+
switch(security) {
case SECURITY_EAP:
switch (mEapType) {
@@ -925,20 +1048,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
return concise ? context.getString(R.string.wifi_security_short_wep) :
context.getString(R.string.wifi_security_wep);
case SECURITY_SAE:
- case SECURITY_PSK_SAE_TRANSITION:
- if (pskType == PSK_SAE) {
- return concise ? context.getString(R.string.wifi_security_short_psk_sae) :
- context.getString(R.string.wifi_security_psk_sae);
- } else {
- return concise ? context.getString(R.string.wifi_security_short_sae) :
- context.getString(R.string.wifi_security_sae);
- }
- case SECURITY_OWE_TRANSITION:
- if (mConfig != null && getSecurity(mConfig) == SECURITY_OWE) {
- return concise ? context.getString(R.string.wifi_security_short_owe) :
- context.getString(R.string.wifi_security_owe);
- }
- return concise ? "" : context.getString(R.string.wifi_security_none);
+ return concise ? context.getString(R.string.wifi_security_short_sae) :
+ context.getString(R.string.wifi_security_sae);
case SECURITY_OWE:
return concise ? context.getString(R.string.wifi_security_short_owe) :
context.getString(R.string.wifi_security_owe);
@@ -1250,7 +1361,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
return networkId == info.getNetworkId();
} else if (config != null) {
- return isKeyEqual(getKey(config));
+ return matches(config, info);
} else {
// Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
// (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
@@ -1322,43 +1433,14 @@ public class AccessPoint implements Comparable<AccessPoint> {
savedState.putLong(KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS,
mSubscriptionExpirationTimeInMillis);
savedState.putInt(KEY_PASSPOINT_CONFIGURATION_VERSION, mPasspointConfigurationVersion);
+ savedState.putBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE, mIsPskSaeTransitionMode);
+ savedState.putBoolean(KEY_IS_OWE_TRANSITION_MODE, mIsOweTransitionMode);
}
public void setListener(AccessPointListener listener) {
mAccessPointListener = listener;
}
- private static final String sPskSuffix = "," + String.valueOf(SECURITY_PSK);
- private static final String sSaeSuffix = "," + String.valueOf(SECURITY_SAE);
- private static final String sPskSaeSuffix = "," + String.valueOf(SECURITY_PSK_SAE_TRANSITION);
- private static final String sOweSuffix = "," + String.valueOf(SECURITY_OWE);
- private static final String sOpenSuffix = "," + String.valueOf(SECURITY_NONE);
- private static final String sOweTransSuffix = "," + String.valueOf(SECURITY_OWE_TRANSITION);
-
- private boolean isKeyEqual(String compareTo) {
- if (mKey == null) {
- return false;
- }
-
- if (compareTo.endsWith(sPskSuffix) || compareTo.endsWith(sSaeSuffix)) {
- if (mKey.endsWith(sPskSaeSuffix)) {
- // Special handling for PSK-SAE transition mode. If the AP has advertised both,
- // we compare the key with both PSK and SAE for a match.
- return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
- compareTo.substring(0, compareTo.lastIndexOf(',')));
- }
- }
- if (compareTo.endsWith(sOpenSuffix) || compareTo.endsWith(sOweSuffix)) {
- if (mKey.endsWith(sOweTransSuffix)) {
- // Special handling for OWE/Open networks. If AP advertises OWE in transition mode
- // and we have an Open network saved, allow this connection to be established.
- return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
- compareTo.substring(0, compareTo.lastIndexOf(',')));
- }
- }
- return mKey.equals(compareTo);
- }
-
/**
* Sets {@link #mScanResults} to the given collection and updates info based on the best RSSI
* scan result.
@@ -1375,11 +1457,10 @@ public class AccessPoint implements Comparable<AccessPoint> {
// Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
if (mKey != null && !isPasspoint() && !isOsuProvider()) {
for (ScanResult result : scanResults) {
- String scanResultKey = AccessPoint.getKey(result);
- if (!isKeyEqual(scanResultKey)) {
+ if (!matches(result)) {
Log.d(TAG, String.format(
- "ScanResult %s\nkey of %s did not match current AP key %s",
- result, scanResultKey, mKey));
+ "ScanResult %s\nkey of %s did not match current AP key %s",
+ result, getKey(mContext, result), mKey));
return;
}
}
@@ -1653,11 +1734,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
private static int getPskType(ScanResult result) {
boolean wpa = result.capabilities.contains("WPA-PSK");
boolean wpa2 = result.capabilities.contains("RSN-PSK");
- boolean wpa3TransitionMode = result.capabilities.contains("PSK+SAE");
boolean wpa3 = result.capabilities.contains("RSN-SAE");
- if (wpa3TransitionMode) {
- return PSK_SAE;
- } else if (wpa2 && wpa) {
+ if (wpa2 && wpa) {
return PSK_WPA_WPA2;
} else if (wpa2) {
return PSK_WPA2;
@@ -1684,22 +1762,37 @@ public class AccessPoint implements Comparable<AccessPoint> {
return EAP_UNKNOWN;
}
- private static int getSecurity(ScanResult result) {
- if (result.capabilities.contains("WEP")) {
+ private static int getSecurity(Context context, ScanResult result) {
+ final boolean isWep = result.capabilities.contains("WEP");
+ final boolean isSae = result.capabilities.contains("SAE");
+ final boolean isPsk = result.capabilities.contains("PSK");
+ final boolean isEapSuiteB192 = result.capabilities.contains("EAP_SUITE_B_192");
+ final boolean isEap = result.capabilities.contains("EAP");
+ final boolean isOwe = result.capabilities.contains("OWE");
+ final boolean isOweTransition = result.capabilities.contains("OWE_TRANSITION");
+
+ if (isSae && isPsk) {
+ final WifiManager wifiManager = (WifiManager)
+ context.getSystemService(Context.WIFI_SERVICE);
+ return wifiManager.isWpa3SaeSupported() ? SECURITY_SAE : SECURITY_PSK;
+ }
+ if (isOweTransition) {
+ final WifiManager wifiManager = (WifiManager)
+ context.getSystemService(Context.WIFI_SERVICE);
+ return wifiManager.isEnhancedOpenSupported() ? SECURITY_OWE : SECURITY_NONE;
+ }
+
+ if (isWep) {
return SECURITY_WEP;
- } else if (result.capabilities.contains("PSK+SAE")) {
- return SECURITY_PSK_SAE_TRANSITION;
- } else if (result.capabilities.contains("SAE")) {
+ } else if (isSae) {
return SECURITY_SAE;
- } else if (result.capabilities.contains("PSK")) {
+ } else if (isPsk) {
return SECURITY_PSK;
- } else if (result.capabilities.contains("EAP_SUITE_B_192")) {
+ } else if (isEapSuiteB192) {
return SECURITY_EAP_SUITE_B;
- } else if (result.capabilities.contains("EAP")) {
+ } else if (isEap) {
return SECURITY_EAP;
- } else if (result.capabilities.contains("OWE_TRANSITION")) {
- return SECURITY_OWE_TRANSITION;
- } else if (result.capabilities.contains("OWE")) {
+ } else if (isOwe) {
return SECURITY_OWE;
}
return SECURITY_NONE;
@@ -1745,10 +1838,6 @@ public class AccessPoint implements Comparable<AccessPoint> {
return "SUITE_B";
} else if (security == SECURITY_OWE) {
return "OWE";
- } else if (security == SECURITY_PSK_SAE_TRANSITION) {
- return "PSK+SAE";
- } else if (security == SECURITY_OWE_TRANSITION) {
- return "OWE_TRANSITION";
}
return "NONE";
}
@@ -1776,8 +1865,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
* Return true if this is an open network AccessPoint.
*/
public boolean isOpenNetwork() {
- return security == SECURITY_NONE || security == SECURITY_OWE
- || security == SECURITY_OWE_TRANSITION;
+ return security == SECURITY_NONE || security == SECURITY_OWE;
}
/**
@@ -1926,4 +2014,61 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
}
}
+
+ public boolean isPskSaeTransitionMode() {
+ return mIsPskSaeTransitionMode;
+ }
+
+ public boolean isOweTransitionMode() {
+ return mIsOweTransitionMode;
+ }
+
+ private static boolean isPskSaeTransitionMode(ScanResult scanResult) {
+ return scanResult.capabilities.contains("PSK")
+ && scanResult.capabilities.contains("SAE");
+ }
+
+ private static boolean isOweTransitionMode(ScanResult scanResult) {
+ return scanResult.capabilities.contains("OWE_TRANSITION");
+ }
+
+ private boolean isSameSsidOrBssid(ScanResult scanResult) {
+ if (scanResult == null) {
+ return false;
+ }
+
+ if (TextUtils.equals(ssid, scanResult.SSID)) {
+ return true;
+ } else if (scanResult.BSSID != null && TextUtils.equals(bssid, scanResult.BSSID)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isSameSsidOrBssid(WifiInfo wifiInfo) {
+ if (wifiInfo == null) {
+ return false;
+ }
+
+ if (TextUtils.equals(ssid, removeDoubleQuotes(wifiInfo.getSSID()))) {
+ return true;
+ } else if (wifiInfo.getBSSID() != null && TextUtils.equals(bssid, wifiInfo.getBSSID())) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isSameSsidOrBssid(AccessPoint accessPoint) {
+ if (accessPoint == null) {
+ return false;
+ }
+
+ if (TextUtils.equals(ssid, accessPoint.getSsid())) {
+ return true;
+ } else if (accessPoint.getBssid() != null
+ && TextUtils.equals(bssid, accessPoint.getBssid())) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index dae546497aba..6269a717b333 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -201,8 +201,7 @@ public class AccessPointPreference extends Preference {
return;
}
if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
- && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)
- && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE_TRANSITION)) {
+ && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
mFrictionSld.setState(STATE_SECURED);
} else if (mAccessPoint.isMetered()) {
mFrictionSld.setState(STATE_METERED);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 23b16e811606..ba6a8ea31987 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -70,8 +70,10 @@ import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
/**
* Tracks saved or available wifi networks and their state.
@@ -475,7 +477,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
continue;
}
- String apKey = AccessPoint.getKey(result);
+ String apKey = AccessPoint.getKey(mContext, result);
List<ScanResult> resultList;
if (scanResultsByApKey.containsKey(apKey)) {
resultList = scanResultsByApKey.get(apKey);
@@ -547,14 +549,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
private void updateAccessPoints(final List<ScanResult> newScanResults,
List<WifiConfiguration> configs) {
- // Map configs and scan results necessary to make AccessPoints
- final Map<String, WifiConfiguration> configsByKey = new ArrayMap(configs.size());
- if (configs != null) {
- for (WifiConfiguration config : configs) {
- configsByKey.put(AccessPoint.getKey(config), config);
- }
- }
-
WifiConfiguration connectionConfig = null;
if (mLastInfo != null) {
connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs);
@@ -586,7 +580,26 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
getCachedOrCreate(entry.getValue(), cachedAccessPoints);
// Update the matching config if there is one, to populate saved network info
- accessPoint.update(configsByKey.get(entry.getKey()));
+ final List<WifiConfiguration> matchedConfigs = configs.stream()
+ .filter(config -> accessPoint.matches(config))
+ .collect(Collectors.toList());
+
+ final int matchedConfigCount = matchedConfigs.size();
+ if (matchedConfigCount == 0) {
+ accessPoint.update(null);
+ } else if (matchedConfigCount == 1) {
+ accessPoint.update(matchedConfigs.get(0));
+ } else {
+ // We may have 2 matched configured WifiCongiguration if the AccessPoint is
+ // of PSK/SAE transition mode or open/OWE transition mode.
+ Optional<WifiConfiguration> preferredConfig = matchedConfigs.stream()
+ .filter(config -> isSaeOrOwe(config)).findFirst();
+ if (preferredConfig.isPresent()) {
+ accessPoint.update(preferredConfig.get());
+ } else {
+ accessPoint.update(matchedConfigs.get(0));
+ }
+ }
accessPoints.add(accessPoint);
}
@@ -652,6 +665,11 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
conditionallyNotifyListeners();
}
+ private static boolean isSaeOrOwe(WifiConfiguration config) {
+ final int security = AccessPoint.getSecurity(config);
+ return security == AccessPoint.SECURITY_SAE || security == AccessPoint.SECURITY_OWE;
+ }
+
@VisibleForTesting
List<AccessPoint> updatePasspointAccessPoints(
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans,
@@ -700,7 +718,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
private AccessPoint getCachedOrCreate(
List<ScanResult> scanResults,
List<AccessPoint> cache) {
- AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
+ AccessPoint accessPoint = getCachedByKey(cache,
+ AccessPoint.getKey(mContext, scanResults.get(0)));
if (accessPoint == null) {
accessPoint = new AccessPoint(mContext, scanResults);
} else {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 7b1c3825fcc6..2a7050651c6d 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -39,6 +39,7 @@ import android.net.ScoredNetwork;
import android.net.WifiKey;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
@@ -1273,7 +1274,7 @@ public class AccessPointTest {
@Test
public void testGetKey_matchesKeysCorrectly() {
AccessPoint ap = new AccessPoint(mContext, mScanResults);
- assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mScanResults.get(0)));
+ assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mContext, mScanResults.get(0)));
WifiConfiguration spyConfig = spy(new WifiConfiguration());
when(spyConfig.isPasspoint()).thenReturn(true);
@@ -1295,6 +1296,44 @@ public class AccessPointTest {
}
/**
+ * Test that getKey returns a key of SAE type for a PSK/SAE transition mode ScanResult.
+ */
+ @Test
+ public void testGetKey_supportSaeTransitionMode_shouldGetSaeKey() {
+ ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
+ scanResult.capabilities =
+ "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+ when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+ StringBuilder key = new StringBuilder();
+ key.append(AccessPoint.KEY_PREFIX_AP);
+ key.append(TEST_SSID);
+ key.append(',');
+ key.append(AccessPoint.SECURITY_SAE);
+
+ assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
+ }
+
+ /**
+ * Test that getKey returns a key of PSK type for a PSK/SAE transition mode ScanResult.
+ */
+ @Test
+ public void testGetKey_notSupportSaeTransitionMode_shouldGetPskKey() {
+ ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
+ scanResult.capabilities =
+ "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+ when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+ StringBuilder key = new StringBuilder();
+ key.append(AccessPoint.KEY_PREFIX_AP);
+ key.append(TEST_SSID);
+ key.append(',');
+ key.append(AccessPoint.SECURITY_PSK);
+
+ assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
+ }
+
+ /**
* Verifies that the Passpoint AccessPoint constructor creates AccessPoints whose isPasspoint()
* returns true.
*/
@@ -1537,12 +1576,141 @@ public class AccessPointTest {
bundle.putInt("key_security", i);
ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
- if (i == AccessPoint.SECURITY_NONE || i == AccessPoint.SECURITY_OWE
- || i == AccessPoint.SECURITY_OWE_TRANSITION) {
+ if (i == AccessPoint.SECURITY_NONE || i == AccessPoint.SECURITY_OWE) {
assertThat(ap.isOpenNetwork()).isTrue();
} else {
assertThat(ap.isOpenNetwork()).isFalse();
}
}
}
+
+ /**
+ * Verifies that matches(AccessPoint other) matches a PSK/SAE transition mode AP to a PSK or a
+ * SAE AP.
+ */
+ @Test
+ public void testMatches1_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
+ when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+ AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+ // Transition mode AP matches a SAE AP.
+ AccessPoint saeAccessPoint = new TestAccessPointBuilder(mContext)
+ .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
+ .setSecurity(AccessPoint.SECURITY_SAE)
+ .build();
+ assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isTrue();
+
+ // Transition mode AP matches a PSK AP.
+ AccessPoint pskAccessPoint = new TestAccessPointBuilder(mContext)
+ .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
+ .setSecurity(AccessPoint.SECURITY_PSK)
+ .build();
+
+ assertThat(pskSaeTransitionModeAp.matches(pskAccessPoint)).isTrue();
+
+ // Transition mode AP does not match a SAE AP if the device does not support SAE.
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+ pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+ saeAccessPoint = new TestAccessPointBuilder(mContext)
+ .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
+ .setSecurity(AccessPoint.SECURITY_SAE)
+ .build();
+
+ assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isFalse();
+ }
+
+ /**
+ * Verifies that matches(WifiConfiguration config) matches a PSK/SAE transition mode AP to a PSK
+ * or a SAE WifiConfiguration.
+ */
+ @Test
+ public void testMatches2_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
+ when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+ AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+ // Transition mode AP matches a SAE WifiConfiguration.
+ WifiConfiguration saeConfig = new WifiConfiguration();
+ saeConfig.SSID = TEST_SSID;
+ saeConfig.allowedKeyManagement.set(KeyMgmt.SAE);
+
+ assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isTrue();
+
+ // Transition mode AP matches a PSK WifiConfiguration.
+ WifiConfiguration pskConfig = new WifiConfiguration();
+ pskConfig.SSID = TEST_SSID;
+ pskConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+
+ assertThat(pskSaeTransitionModeAp.matches(pskConfig)).isTrue();
+
+ // Transition mode AP does not matches a SAE WifiConfiguration if the device does not
+ // support SAE.
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+ pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+ assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isFalse();
+ }
+
+ /**
+ * Verifies that matches(ScanResult scanResult) matches a PSK/SAE transition mode AP to a PSK
+ * or a SAE ScanResult.
+ */
+ @Test
+ public void testMatches3_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
+ when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+ AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+ // Transition mode AP matches a SAE ScanResult.
+ ScanResult saeScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
+ TEST_BSSID, DEFAULT_RSSI);
+ saeScanResult.capabilities = "[SAE-CCMP][ESS][WPS]";
+
+ assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isTrue();
+
+ // Transition mode AP matches a PSK ScanResult.
+ ScanResult pskScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
+ TEST_BSSID, DEFAULT_RSSI);
+ pskScanResult.capabilities = "[RSN-PSK-CCMP][ESS][WPS]";
+
+ assertThat(pskSaeTransitionModeAp.matches(pskScanResult)).isTrue();
+
+ // Transition mode AP does not matches a SAE ScanResult if the device does not support SAE.
+ when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+ pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+ assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isFalse();
+ }
+
+ @Test
+ public void testGetSecurityString_oweTransitionMode_shouldReturnCorrectly() {
+ when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+ when(mMockWifiManager.isEnhancedOpenSupported()).thenReturn(true);
+ AccessPoint oweTransitionModeAp = getOweTransitionModeAp();
+
+ assertThat(oweTransitionModeAp.getSecurityString(true /* concise */))
+ .isEqualTo(mContext.getString(R.string.wifi_security_short_none_owe));
+ assertThat(oweTransitionModeAp.getSecurityString(false /* concise */))
+ .isEqualTo(mContext.getString(R.string.wifi_security_none_owe));
+ }
+
+ private AccessPoint getPskSaeTransitionModeAp() {
+ ScanResult scanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
+ TEST_BSSID, DEFAULT_RSSI);
+ scanResult.capabilities =
+ "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
+ return new TestAccessPointBuilder(mMockContext)
+ .setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
+ .build();
+ }
+
+ private AccessPoint getOweTransitionModeAp() {
+ ScanResult scanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
+ TEST_BSSID, DEFAULT_RSSI);
+ scanResult.capabilities = "[OWE_TRANSITION]";
+ return new TestAccessPointBuilder(mContext)
+ .setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
+ .build();
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 4731e6894baf..086b20facb46 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -62,6 +62,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -766,6 +768,23 @@ final class SettingsState {
}
} catch (Throwable t) {
Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t);
+ if (t instanceof IOException) {
+ // we failed to create a directory, so log the permissions and existence
+ // state for the settings file and directory
+ logSettingsDirectoryInformation(destination.getBaseFile());
+ if (t.getMessage().contains("Couldn't create directory")) {
+ // attempt to create the directory with Files.createDirectories, which
+ // throws more informative errors than File.mkdirs.
+ Path parentPath = destination.getBaseFile().getParentFile().toPath();
+ try {
+ Files.createDirectories(parentPath);
+ Slog.i(LOG_TAG, "Successfully created " + parentPath);
+ } catch (Throwable t2) {
+ Slog.e(LOG_TAG, "Failed to write " + parentPath
+ + " with Files.writeDirectories", t2);
+ }
+ }
+ }
destination.failWrite(out);
} finally {
IoUtils.closeQuietly(out);
@@ -779,6 +798,33 @@ final class SettingsState {
}
}
+ private static void logSettingsDirectoryInformation(File settingsFile) {
+ File parent = settingsFile.getParentFile();
+ Slog.i(LOG_TAG, "directory info for directory/file " + settingsFile
+ + " with stacktrace ", new Exception());
+ File ancestorDir = parent;
+ while (ancestorDir != null) {
+ if (!ancestorDir.exists()) {
+ Slog.i(LOG_TAG, "ancestor directory " + ancestorDir
+ + " does not exist");
+ ancestorDir = ancestorDir.getParentFile();
+ } else {
+ Slog.i(LOG_TAG, "ancestor directory " + ancestorDir
+ + " exists");
+ Slog.i(LOG_TAG, "ancestor directory " + ancestorDir
+ + " permissions: r: " + ancestorDir.canRead() + " w: "
+ + ancestorDir.canWrite() + " x: " + ancestorDir.canExecute());
+ File ancestorParent = ancestorDir.getParentFile();
+ if (ancestorParent != null) {
+ Slog.i(LOG_TAG, "ancestor's parent directory " + ancestorParent
+ + " permissions: r: " + ancestorParent.canRead() + " w: "
+ + ancestorParent.canWrite() + " x: " + ancestorParent.canExecute());
+ }
+ break;
+ }
+ }
+ }
+
static void writeSingleSetting(int version, XmlSerializer serializer, String id,
String name, String value, String defaultValue, String packageName,
String tag, boolean defaultSysSet) throws IOException {
@@ -853,6 +899,7 @@ final class SettingsState {
in = new AtomicFile(mStatePersistFile).openRead();
} catch (FileNotFoundException fnfe) {
Slog.i(LOG_TAG, "No settings state " + mStatePersistFile);
+ logSettingsDirectoryInformation(mStatePersistFile);
addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null);
return;
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6f6803817138..35147049e43e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -325,6 +325,14 @@
android:permission="android.permission.BIND_WALLPAPER"
android:exported="true" />
+ <activity
+ android:name=".bubbles.BubbleOverflowActivity"
+ android:theme="@style/BubbleOverflow"
+ android:excludeFromRecents="true"
+ android:documentLaunchMode="always"
+ android:resizeableActivity="true">
+ </activity>
+
<activity android:name=".tuner.TunerActivity"
android:enabled="false"
android:icon="@drawable/tuner"
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 26ec5726a4a2..9f13a7b861a0 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -9,12 +9,6 @@
"include-filter": "android.platform.test.scenario.sysui"
},
{
- "include-filter": "android.platform.test.scenario.quicksettings"
- },
- {
- "include-filter": "android.platform.test.scenario.notification"
- },
- {
"include-annotation": "android.platform.test.scenario.annotation.Scenario"
},
{
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index b21a9f7c4d05..6c4cbdf27fa5 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -34,7 +34,8 @@ public interface StatusBarStateController {
int getState();
/**
- * Is device dozing
+ * Is device dozing. Dozing is when the screen is in AOD or asleep given that
+ * {@link com.android.systemui.doze.DozeService} is configured.
*/
boolean isDozing();
diff --git a/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png b/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png
deleted file mode 100644
index 135dabb63069..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml b/packages/SystemUI/res/drawable/tv_circle_dark.xml
index 1bbb8c3e8ef0..d1ba8e71ec31 100644
--- a/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml
+++ b/packages/SystemUI/res/drawable/tv_circle_dark.xml
@@ -16,7 +16,9 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners android:radius="24dp"/>
- <solid android:color="@color/tv_audio_recording_bar_chip_background"/>
-</shape>
+ android:shape="oval">
+
+ <solid
+ android:color="@color/tv_audio_recording_indicator_background" />
+
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/circle_red.xml b/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml
index fd3c125e5ab8..55d21de00ca3 100644
--- a/packages/SystemUI/res/drawable/circle_red.xml
+++ b/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml
@@ -16,6 +16,9 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <solid android:color="@color/red"/>
+ android:shape="oval">
+
+ <solid
+ android:color="@color/tv_audio_recording_indicator_pulse" />
+
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
index 1bea8a19c8b9..d887113c7717 100644
--- a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
+++ b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
@@ -1,25 +1,27 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
+Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z"
- android:fillColor="@android:color/white" />
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/>
</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml
new file mode 100644
index 000000000000..9b48a70d9439
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+
+ <corners
+ android:bottomLeftRadius="8dp"
+ android:topLeftRadius="8dp" />
+ <solid android:color="@color/tv_audio_recording_indicator_background" />
+
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml
new file mode 100644
index 000000000000..03348756231b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+
+ <corners
+ android:bottomRightRadius="8dp"
+ android:topRightRadius="8dp" />
+ <solid android:color="@color/tv_audio_recording_indicator_background" />
+
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_gradient_protection.xml b/packages/SystemUI/res/drawable/tv_ring_white.xml
index ee5cbc7e6ba0..0f7cc1082f71 100644
--- a/packages/SystemUI/res/drawable/tv_gradient_protection.xml
+++ b/packages/SystemUI/res/drawable/tv_ring_white.xml
@@ -15,8 +15,11 @@
~ limitations under the License.
-->
-<!-- gradient protection for cards -->
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/tv_card_gradient_protection"
- android:tileMode="repeat"
-/>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+
+ <stroke
+ android:width="1dp"
+ android:color="@android:color/white" />
+
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bubble_overflow_activity.xml b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
new file mode 100644
index 000000000000..4cee74615bd2
--- /dev/null
+++ b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/bubble_overflow_recycler"
+ android:scrollbars="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
diff --git a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
new file mode 100644
index 000000000000..f04226e7ceaf
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="32dp">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:id="@+id/icon_texts_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:layout_width="90dp"
+ android:layout_height="94dp">
+
+ <View
+ android:id="@+id/icon_container_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/tv_rect_dark_left_rounded"/>
+
+ <FrameLayout
+ android:id="@+id/icon_mic"
+ android:layout_width="70dp"
+ android:layout_height="70dp"
+ android:layout_marginLeft="12dp"
+ android:layout_marginTop="12dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginBottom="12dp">
+
+ <View
+ android:layout_width="54dp"
+ android:layout_height="54dp"
+ android:layout_gravity="center"
+ android:background="@drawable/tv_circle_dark"/>
+
+ <ImageView
+ android:id="@+id/pulsating_circle"
+ android:layout_width="54dp"
+ android:layout_height="54dp"
+ android:layout_gravity="center"
+ android:background="@drawable/tv_circle_white_translucent"/>
+
+ <ImageView
+ android:layout_width="54dp"
+ android:layout_height="54dp"
+ android:layout_gravity="center"
+ android:src="@drawable/tv_ring_white"/>
+
+ <ImageView
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="center"
+ android:background="@drawable/tv_ic_mic_white"/>
+ </FrameLayout>
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:id="@+id/texts_container"
+ android:layout_width="wrap_content"
+ android:layout_height="94dp"
+ android:background="@color/tv_audio_recording_indicator_background"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:visibility="visible">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/mic_active"
+ android:textColor="@android:color/white"
+ android:fontFamily="sans-serif"
+ android:textSize="20dp"/>
+
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:text="SomeApplication accessed your microphone"
+ android:textColor="@android:color/white"
+ android:fontFamily="sans-serif"
+ android:textSize="16dp"/>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <View
+ android:id="@+id/bg_right"
+ android:layout_width="24dp"
+ android:layout_height="94dp"
+ android:background="@drawable/tv_rect_dark_right_rounded"
+ android:visibility="visible"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_item_app_info.xml b/packages/SystemUI/res/layout/tv_item_app_info.xml
deleted file mode 100644
index b40589ec80c6..000000000000
--- a/packages/SystemUI/res/layout/tv_item_app_info.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginLeft="8dp"
- android:paddingHorizontal="12dp"
- android:gravity="center_vertical"
- android:background="@drawable/tv_bg_item_app_info">
-
- <ImageView
- android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginRight="8dp"/>
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/tv_audio_recording_bar_text"
- android:fontFamily="sans-serif"
- android:textSize="14sp"/>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml b/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml
deleted file mode 100644
index b9dffbb4de20..000000000000
--- a/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:orientation="vertical">
-
- <!-- Gradient Protector -->
- <View
- android:layout_width="match_parent"
- android:layout_height="102.5dp"
- android:background="@drawable/tv_gradient_protection"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="72dp"
- android:background="@color/tv_audio_recording_bar_background"
- android:gravity="center_vertical"
- android:orientation="horizontal">
-
- <ImageView
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginLeft="42dp"
- android:layout_marginVertical="12dp"
- android:padding="8dp"
- android:background="@drawable/circle_red"
- android:scaleType="centerInside"
- android:src="@drawable/tv_ic_mic_white"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="24dp"
- android:text="Audio recording by"
- android:textColor="@color/tv_audio_recording_bar_text"
- android:fontFamily="sans-serif"
- android:textSize="14sp"/>
-
- <LinearLayout
- android:id="@+id/container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- </LinearLayout>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 6becd21984b9..79629e4c6d7e 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -154,12 +154,5 @@
<declare-styleable name="CaptionsToggleImageButton">
<attr name="optedOut" format="boolean" />
</declare-styleable>
-
- <!-- Theme attributes used to style the appearance of expanded Bubbles -->
- <declare-styleable name="BubbleExpandedView">
- <attr name="android:colorBackgroundFloating" />
- <attr name="android:dialogCornerRadius" />
- </declare-styleable>
-
</resources>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index db225428a348..53cd9716c98e 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -22,13 +22,9 @@
<color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
<color name="recents_tv_text_shadow_color">#7F000000</color>
-
- <!-- Text color used in audio recording bar: G50 -->
- <color name="tv_audio_recording_bar_text">#FFF8F9FA</color>
- <!-- Background color for a chip in audio recording bar: G800 -->
- <color name="tv_audio_recording_bar_chip_background">#FF3C4043</color>
- <!-- Audio recording bar background color: G900 -->
- <color name="tv_audio_recording_bar_background">#FF202124</color>
+ <!-- Background color for audio recording indicator (G800) -->
+ <color name="tv_audio_recording_indicator_background">#FF3C4043</color>
+ <color name="tv_audio_recording_indicator_pulse">#4DFFFFFF</color>
<color name="red">#FFCC0000</color>
</resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index a9bdb71de039..6d61ff989cb1 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -31,4 +31,8 @@
<string name="pip_close">Close PIP</string>
<!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
<string name="pip_fullscreen">Full screen</string>
+
+ <!-- Title and subtitle for AudioRecordingIndicator -->
+ <string name="mic_active">Microphone Active</string>
+ <string name="app_accessed_mic">%1$s accessed your microphone</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 926d01685075..3ff824374aac 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -15,6 +15,7 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="BubbleOverflow" parent="@android:style/Theme.NoTitleBar"></style>
<style name="ClearAllButtonDefaultMargins">
<item name="android:layout_marginStart">0dp</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
index eaf8d9b57398..35952f55ec1e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
@@ -17,6 +17,7 @@
package com.android.systemui.shared.system;
import android.app.ActivityManager;
+import android.graphics.Bitmap;
public class TaskDescriptionCompat {
@@ -37,4 +38,12 @@ public class TaskDescriptionCompat {
? mTaskDescription.getBackgroundColor()
: 0;
}
+
+ public static Bitmap getIcon(ActivityManager.TaskDescription desc, int userId) {
+ if (desc.getInMemoryIcon() != null) {
+ return desc.getInMemoryIcon();
+ }
+ return ActivityManager.TaskDescription.loadTaskDescriptionIcon(
+ desc.getIconFilename(), userId);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
index 72a403035294..4749addc7139 100644
--- a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
@@ -280,6 +280,7 @@ public class SizeCompatModeActivityController extends SystemUI implements Comman
R.layout.size_compat_mode_hint, null /* root */);
PopupWindow popupWindow = new PopupWindow(popupView,
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ popupWindow.setWindowLayoutType(mWinParams.type);
popupWindow.setElevation(getResources().getDimension(R.dimen.bubble_elevation));
popupWindow.setAnimationStyle(android.R.style.Animation_InputMethod);
popupWindow.setClippingEnabled(false);
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index adb288a9ce82..5cc70bc27c2a 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -46,7 +46,7 @@ private const val MSG_ADD_RECEIVER = 0
private const val MSG_REMOVE_RECEIVER = 1
private const val MSG_REMOVE_RECEIVER_FOR_USER = 2
private const val TAG = "BroadcastDispatcher"
-private const val DEBUG = false
+private const val DEBUG = true
/**
* SystemUI master Broadcast Dispatcher.
@@ -147,7 +147,13 @@ open class BroadcastDispatcher @Inject constructor (
when (msg.what) {
MSG_ADD_RECEIVER -> {
val data = msg.obj as ReceiverData
- val userId = data.user.identifier
+ // If the receiver asked to be registered under the current user, we register
+ // under the actual current user.
+ val userId = if (data.user.identifier == UserHandle.USER_CURRENT) {
+ context.userId
+ } else {
+ data.user.identifier
+ }
if (userId < UserHandle.USER_ALL) {
if (DEBUG) Log.w(TAG, "Register receiver for invalid user: $userId")
return
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index f3a7ca9c0a75..7934e10c8605 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -297,7 +297,9 @@ class Bubble {
* Whether the bubble for this notification should show a dot indicating updated content.
*/
boolean showDot() {
- return mShowBubbleUpdateDot && !mEntry.shouldSuppressNotificationDot();
+ return mShowBubbleUpdateDot
+ && !mEntry.shouldSuppressNotificationDot()
+ && !shouldSuppressNotification();
}
/**
@@ -305,6 +307,7 @@ class Bubble {
*/
boolean showFlyout() {
return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
+ && !shouldSuppressNotification()
&& !mEntry.shouldSuppressNotificationList();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 19381940543e..b5622432f919 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -878,12 +878,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (DEBUG_BUBBLE_CONTROLLER) {
Log.d(TAG, "[BubbleData]");
- Log.d(TAG, formatBubblesString(mBubbleData.getBubbles(),
+ Log.d(TAG, BubbleDebugConfig.formatBubblesString(mBubbleData.getBubbles(),
mBubbleData.getSelectedBubble()));
if (mStackView != null) {
Log.d(TAG, "[BubbleStackView]");
- Log.d(TAG, formatBubblesString(mStackView.getBubblesOnScreen(),
+ Log.d(TAG, BubbleDebugConfig.formatBubblesString(mStackView.getBubblesOnScreen(),
mStackView.getExpandedBubble()));
}
}
@@ -972,23 +972,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
pw.println();
}
- static String formatBubblesString(List<Bubble> bubbles, Bubble selected) {
- StringBuilder sb = new StringBuilder();
- for (Bubble bubble : bubbles) {
- if (bubble == null) {
- sb.append(" <null> !!!!!\n");
- } else {
- boolean isSelected = (bubble == selected);
- sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n",
- ((isSelected) ? "->" : " "),
- bubble.getLastActivity(),
- (bubble.isOngoing() ? 1 : 0),
- bubble.getKey()));
- }
- }
- return sb.toString();
- }
-
/**
* This task stack listener is responsible for responding to tasks moved to the front
* which are on the default (main) display. When this happens, expanded bubbles must be
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 034bff345d71..b7df5baa4cf1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -48,6 +48,7 @@ import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
+import com.android.systemui.R;
/**
* Keeps track of active bubbles.
@@ -57,8 +58,6 @@ public class BubbleData {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleData" : TAG_BUBBLES;
- private static final int MAX_BUBBLES = 5;
-
private static final Comparator<Bubble> BUBBLES_BY_SORT_KEY_DESCENDING =
Comparator.comparing(BubbleData::sortKey).reversed();
@@ -115,6 +114,7 @@ public class BubbleData {
private final List<Bubble> mBubbles;
private Bubble mSelectedBubble;
private boolean mExpanded;
+ private final int mMaxBubbles;
// State tracked during an operation -- keeps track of what listener events to dispatch.
private Update mStateChange;
@@ -144,6 +144,7 @@ public class BubbleData {
mContext = context;
mBubbles = new ArrayList<>();
mStateChange = new Update(mBubbles);
+ mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered);
}
public boolean hasBubbles() {
@@ -329,7 +330,7 @@ public class BubbleData {
}
private void trim() {
- if (mBubbles.size() > MAX_BUBBLES) {
+ if (mBubbles.size() > mMaxBubbles) {
mBubbles.stream()
// sort oldest first (ascending lastActivity)
.sorted(Comparator.comparingLong(Bubble::getLastActivity))
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
index a912eccd4d5e..319066221600 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
@@ -16,6 +16,8 @@
package com.android.systemui.bubbles;
+import java.util.List;
+
/**
* Common class for the various debug {@link android.util.Log} output configuration in the Bubbles
* package.
@@ -38,5 +40,23 @@ public class BubbleDebugConfig {
static final boolean DEBUG_BUBBLE_STACK_VIEW = false;
static final boolean DEBUG_BUBBLE_EXPANDED_VIEW = false;
static final boolean DEBUG_EXPERIMENTS = true;
+ static final boolean DEBUG_OVERFLOW = false;
+ static String formatBubblesString(List<Bubble> bubbles, Bubble selected) {
+ StringBuilder sb = new StringBuilder();
+ for (Bubble bubble : bubbles) {
+ if (bubble == null) {
+ sb.append(" <null> !!!!!\n");
+ } else {
+ boolean isSelected = (selected != null && bubble == selected);
+ String arrow = isSelected ? "=>" : " ";
+ sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n",
+ arrow,
+ bubble.getLastActivity(),
+ (bubble.isOngoing() ? 1 : 0),
+ bubble.getKey()));
+ }
+ }
+ return sb.toString();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index efc955d9bca4..63d036d6362d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -275,17 +275,15 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
}
void applyThemeAttrs() {
- TypedArray ta = getContext().obtainStyledAttributes(R.styleable.BubbleExpandedView);
- int bgColor = ta.getColor(
- R.styleable.BubbleExpandedView_android_colorBackgroundFloating, Color.WHITE);
- float cornerRadius = ta.getDimension(
- R.styleable.BubbleExpandedView_android_dialogCornerRadius, 0);
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ new int[] {
+ android.R.attr.colorBackgroundFloating,
+ android.R.attr.dialogCornerRadius});
+ int bgColor = ta.getColor(0, Color.WHITE);
+ float cornerRadius = ta.getDimensionPixelSize(1, 0);
ta.recycle();
- // Update triangle color.
mPointerDrawable.setTint(bgColor);
-
- // Update ActivityView cornerRadius
if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(mContext.getResources())) {
mActivityView.setCornerRadius(cornerRadius);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 8299f2261b8e..41879855275f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -224,7 +224,11 @@ public class BubbleExperimentConfig {
// Use the icon of the person if available
List<Person> personList = getPeopleFromNotification(entry);
if (personList.size() > 0) {
- icon = personList.get(0).getIcon();
+ final Person person = personList.get(0);
+
+ if (person != null) {
+ icon = person.getIcon();
+ }
}
if (icon == null) {
icon = notification.getLargeIcon() != null
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
new file mode 100644
index 000000000000..018b6318575a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -0,0 +1,69 @@
+package com.android.systemui.bubbles;
+
+import android.app.Activity;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.os.Bundle;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.systemui.R;
+
+/**
+ * Activity for showing aged out bubbles.
+ * Must be public to be accessible to androidx...AppComponentFactory
+ */
+public class BubbleOverflowActivity extends Activity {
+ private RecyclerView mRecyclerView;
+ private int mMaxBubbles;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.bubble_overflow_activity);
+ setBackgroundColor();
+
+ mMaxBubbles = getResources().getInteger(R.integer.bubbles_max_rendered);
+ mRecyclerView = findViewById(R.id.bubble_overflow_recycler);
+ mRecyclerView.setLayoutManager(
+ new GridLayoutManager(getApplicationContext(), /* numberOfColumns */ mMaxBubbles));
+ }
+
+ void setBackgroundColor() {
+ final TypedArray ta = getApplicationContext().obtainStyledAttributes(
+ new int[] {android.R.attr.colorBackgroundFloating});
+ int bgColor = ta.getColor(0, Color.WHITE);
+ ta.recycle();
+ findViewById(android.R.id.content).setBackgroundColor(bgColor);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ public void onRestart() {
+ super.onRestart();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ }
+
+ public void onDestroy() {
+ super.onStop();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
index f094cb909cf2..0f71d22b218f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
@@ -47,7 +47,8 @@ public class SysuiLog implements Dumpable {
private final Object mDataLock = new Object();
private final String mId;
private final int mMaxLogs;
- private boolean mEnabled;
+ protected boolean mEnabled;
+ protected boolean mLogToLogcatEnabled;
@VisibleForTesting protected ArrayDeque<Event> mTimeline;
@@ -62,14 +63,18 @@ public class SysuiLog implements Dumpable {
*/
public SysuiLog(DumpController dumpController, String id, int maxDebugLogs, int maxLogs) {
this(dumpController, id, sDebuggable ? maxDebugLogs : maxLogs,
- SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED));
+ SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED),
+ SystemProperties.getBoolean(SYSPROP_LOGCAT_ENABLED_PREFIX + id,
+ DEFAULT_LOGCAT_ENABLED));
}
@VisibleForTesting
- protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled) {
+ protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled,
+ boolean logcatEnabled) {
mId = id;
mMaxLogs = maxLogs;
mEnabled = enabled;
+ mLogToLogcatEnabled = logcatEnabled;
mTimeline = mEnabled ? new ArrayDeque<>(mMaxLogs) : null;
dumpController.registerDumpable(mId, this);
}
@@ -96,7 +101,7 @@ public class SysuiLog implements Dumpable {
mTimeline.add(event);
}
- if (LOG_TO_LOGCAT_ENABLED) {
+ if (mLogToLogcatEnabled) {
final String strEvent = eventToString(event);
switch (event.getLogLevel()) {
case Event.VERBOSE:
@@ -162,9 +167,10 @@ public class SysuiLog implements Dumpable {
}
private static boolean sDebuggable = Build.IS_DEBUGGABLE;
- private static final String SYSPROP_ENABLED_PREFIX = "sysui.log.enabled.";
- private static final boolean LOG_TO_LOGCAT_ENABLED = sDebuggable;
+ private static final String SYSPROP_ENABLED_PREFIX = "persist.sysui.log.enabled.";
+ private static final String SYSPROP_LOGCAT_ENABLED_PREFIX = "persist.sysui.log.enabled.logcat.";
private static final boolean DEFAULT_ENABLED = sDebuggable;
+ private static final boolean DEFAULT_LOGCAT_ENABLED = false;
private static final int DEFAULT_MAX_DEBUG_LOGS = 100;
private static final int DEFAULT_MAX_LOGS = 50;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index 5bb882e2355f..d40e25064352 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -250,6 +250,14 @@ public class QuickQSMediaPlayer {
return (state.getState() == PlaybackState.STATE_PLAYING);
}
+ /**
+ * Check whether this player has an attached media session.
+ * @return whether there is a controller with a current media session.
+ */
+ public boolean hasMediaSession() {
+ return mController != null && mController.getPlaybackState() != null;
+ }
+
private void addAlbumArtBackground(MediaMetadata metadata, int bgColor) {
Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index d377f1c793a9..feb10a2e9a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -57,6 +57,12 @@ public class QuickQSPanel extends QSPanel {
private int mMaxTiles;
protected QSPanel mFullPanel;
private QuickQSMediaPlayer mMediaPlayer;
+ private boolean mUsingMediaPlayer;
+ private LinearLayout mHorizontalLinearLayout;
+
+ // Only used with media
+ private QSTileLayout mMediaTileLayout;
+ private QSTileLayout mRegularTileLayout;
@Inject
public QuickQSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -72,8 +78,9 @@ public class QuickQSPanel extends QSPanel {
removeView((View) mTileLayout);
}
- if (Utils.useQsMediaPlayer(context)) {
- LinearLayout mHorizontalLinearLayout = new LinearLayout(mContext);
+ mUsingMediaPlayer = Utils.useQsMediaPlayer(context);
+ if (mUsingMediaPlayer) {
+ mHorizontalLinearLayout = new LinearLayout(mContext);
mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
mHorizontalLinearLayout.setClipChildren(false);
mHorizontalLinearLayout.setClipToPadding(false);
@@ -81,6 +88,8 @@ public class QuickQSPanel extends QSPanel {
LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
mTileLayout = new DoubleLineTileLayout(context);
+ mMediaTileLayout = mTileLayout;
+ mRegularTileLayout = new HeaderTileLayout(context);
lp.setMarginEnd(10);
lp.setMarginStart(0);
mHorizontalLinearLayout.addView((View) mTileLayout, lp);
@@ -95,6 +104,8 @@ public class QuickQSPanel extends QSPanel {
mTileLayout.setListening(mListening);
addView(mHorizontalLinearLayout, 0 /* Between brightness and footer */);
+ ((View) mRegularTileLayout).setVisibility(View.GONE);
+ addView((View) mRegularTileLayout, 0);
super.setPadding(0, 0, 0, 0);
} else {
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
@@ -130,6 +141,8 @@ public class QuickQSPanel extends QSPanel {
Dependency.get(TunerService.class).removeTunable(mNumTiles);
}
+
+
@Override
protected String getDumpableTag() {
return TAG;
@@ -152,6 +165,42 @@ public class QuickQSPanel extends QSPanel {
super.drawTile(r, state);
}
+ boolean switchTileLayout() {
+ if (!mUsingMediaPlayer) return false;
+ if (mMediaPlayer.hasMediaSession()
+ && mHorizontalLinearLayout.getVisibility() == View.GONE) {
+ mHorizontalLinearLayout.setVisibility(View.VISIBLE);
+ ((View) mRegularTileLayout).setVisibility(View.GONE);
+ mTileLayout.setListening(false);
+ for (TileRecord record : mRecords) {
+ mTileLayout.removeTile(record);
+ record.tile.removeCallback(record.callback);
+ }
+ mTileLayout = mMediaTileLayout;
+ setTiles(mHost.getTiles());
+ mTileLayout.setListening(mListening);
+ return true;
+ } else if (!mMediaPlayer.hasMediaSession()
+ && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
+ mHorizontalLinearLayout.setVisibility(View.GONE);
+ ((View) mRegularTileLayout).setVisibility(View.VISIBLE);
+ mTileLayout.setListening(false);
+ for (TileRecord record : mRecords) {
+ mTileLayout.removeTile(record);
+ record.tile.removeCallback(record.callback);
+ }
+ mTileLayout = mRegularTileLayout;
+ setTiles(mHost.getTiles());
+ mTileLayout.setListening(mListening);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hasMediaPlayerSession() {
+ return mMediaPlayer.hasMediaSession();
+ }
+
@Override
public void setHost(QSTileHost host, QSCustomizer customizer) {
super.setHost(host, customizer);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index e5cec878b63d..d4af1548af41 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -339,7 +339,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
if (mQsDisabled) {
lp.height = resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
- } else if (useQsMediaPlayer(mContext)) {
+ } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayerSession()) {
lp.height = Math.max(getMinimumHeight(),
resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_total_height_with_media));
@@ -405,6 +405,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mHeaderTextContainerView.setVisibility(INVISIBLE);
}
}
+ if (expansionFraction < 1 && expansionFraction > 0.99) {
+ if (mHeaderQsPanel.switchTileLayout()) {
+ updateResources();
+ }
+ }
}
public void disable(int state1, int state2, boolean animate) {
@@ -453,6 +458,9 @@ public class QuickStatusBarHeader extends RelativeLayout implements
return;
}
mHeaderQsPanel.setListening(listening);
+ if (mHeaderQsPanel.switchTileLayout()) {
+ updateResources();
+ }
mListening = listening;
if (listening) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index 9fe9703e4181..d79e38332af5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -92,7 +92,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements
boolean nightMode = (mContext.getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
- if (isAuto) {
+ if (isAuto && !powerSave) {
state.secondaryLabel = mContext.getResources().getString(nightMode
? R.string.quick_settings_dark_mode_secondary_label_until_sunrise
: R.string.quick_settings_dark_mode_secondary_label_on_at_sunset);
@@ -123,7 +123,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements
@Override
public Intent getLongClickIntent() {
- return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+ return new Intent(Settings.ACTION_DARK_THEME_SETTINGS);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index d3a9c2c3c87d..246b0f0e19ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -61,7 +61,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ScrimState;
-import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -105,9 +104,6 @@ public class NotificationMediaManager implements Dumpable {
private final NotificationEntryManager mEntryManager;
- // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
- @Nullable
- private Lazy<ShadeController> mShadeController;
@Nullable
private Lazy<StatusBarWindowController> mStatusBarWindowController;
@@ -183,7 +179,6 @@ public class NotificationMediaManager implements Dumpable {
@Inject
public NotificationMediaManager(
Context context,
- Lazy<ShadeController> shadeController,
Lazy<StatusBar> statusBarLazy,
Lazy<StatusBarWindowController> statusBarWindowController,
NotificationEntryManager notificationEntryManager,
@@ -193,11 +188,10 @@ public class NotificationMediaManager implements Dumpable {
mMediaArtworkProcessor = mediaArtworkProcessor;
mKeyguardBypassController = keyguardBypassController;
mMediaListeners = new ArrayList<>();
- mMediaSessionManager
- = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
// TODO: use MediaSessionManager.SessionListener to hook us up to future updates
// in session state
- mShadeController = shadeController;
+ mMediaSessionManager = (MediaSessionManager) mContext.getSystemService(
+ Context.MEDIA_SESSION_SERVICE);
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mStatusBarLazy = statusBarLazy;
mStatusBarWindowController = statusBarWindowController;
@@ -603,9 +597,7 @@ public class NotificationMediaManager implements Dumpable {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
}
- ShadeController shadeController = mShadeController.get();
- boolean cannotAnimateDoze = shadeController != null
- && shadeController.isDozing()
+ boolean cannotAnimateDoze = mStatusBarStateController.isDozing()
&& !ScrimState.AOD.getAnimateChange();
boolean needsBypassFading = mKeyguardStateController.isBypassFadingAnimation();
if (((mBiometricUnlockController != null && mBiometricUnlockController.getMode()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index c556bc0b39d1..f6f3ac1b5aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -58,7 +58,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -116,7 +116,7 @@ public class NotificationRemoteInputManager implements Dumpable {
private final NotificationEntryManager mEntryManager;
private final Handler mMainHandler;
- private final Lazy<ShadeController> mShadeController;
+ private final Lazy<StatusBar> mStatusBarLazy;
protected final Context mContext;
private final UserManager mUserManager;
@@ -136,7 +136,7 @@ public class NotificationRemoteInputManager implements Dumpable {
@Override
public boolean onClickHandler(
View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
- mShadeController.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view,
+ mStatusBarLazy.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view,
"NOTIFICATION_CLICK");
if (handleRemoteInput(view, pendingIntent)) {
@@ -261,7 +261,7 @@ public class NotificationRemoteInputManager implements Dumpable {
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
- Lazy<ShadeController> shadeController,
+ Lazy<StatusBar> statusBarLazy,
StatusBarStateController statusBarStateController,
@MainHandler Handler mainHandler,
RemoteInputUriController remoteInputUriController) {
@@ -269,7 +269,7 @@ public class NotificationRemoteInputManager implements Dumpable {
mLockscreenUserManager = lockscreenUserManager;
mSmartReplyController = smartReplyController;
mEntryManager = notificationEntryManager;
- mShadeController = shadeController;
+ mStatusBarLazy = statusBarLazy;
mMainHandler = mainHandler;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index e516af590e34..88f148b00cdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -211,7 +211,7 @@ constructor(
setUserLocked(mStartingChild!!, false)
mStartingChild = null
}
- if (shadeController.isDozing) {
+ if (statusBarStateController.isDozing) {
isWakingToShadeLocked = true
wakeUpCoordinator.willWakeUp = true
mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 65f3fa94374b..31b7cb0fb5a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -24,18 +24,16 @@ import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
-import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import javax.inject.Inject;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/** Handles heads-up and pulsing behavior driven by notification changes. */
@Singleton
public class NotificationAlertingManager {
@@ -44,7 +42,7 @@ public class NotificationAlertingManager {
private final NotificationRemoteInputManager mRemoteInputManager;
private final VisualStabilityManager mVisualStabilityManager;
- private final Lazy<ShadeController> mShadeController;
+ private final StatusBarStateController mStatusBarStateController;
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationListener mNotificationListener;
@@ -55,12 +53,12 @@ public class NotificationAlertingManager {
NotificationEntryManager notificationEntryManager,
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
- Lazy<ShadeController> shadeController,
+ StatusBarStateController statusBarStateController,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationListener notificationListener) {
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
- mShadeController = shadeController;
+ mStatusBarStateController = statusBarStateController;
mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mNotificationListener = notificationListener;
@@ -102,7 +100,7 @@ public class NotificationAlertingManager {
// If it does and we no longer need to heads up, we should free the view.
if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
mHeadsUpManager.showNotification(entry);
- if (!mShadeController.get().isDozing()) {
+ if (!mStatusBarStateController.isDozing()) {
// Mark as seen immediately
setNotificationShown(entry.getSbn());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index b5c664116944..c8b34f1f5b27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -24,7 +24,9 @@ import android.view.View;
import com.android.systemui.DejankUtils;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import java.util.Optional;
/**
* Click handler for generic clicks on notifications. Clicks on specific areas (expansion caret,
@@ -33,14 +35,14 @@ import com.android.systemui.statusbar.phone.ShadeController;
public final class NotificationClicker implements View.OnClickListener {
private static final String TAG = "NotificationClicker";
- private final ShadeController mShadeController;
+ private final Optional<StatusBar> mStatusBar;
private final BubbleController mBubbleController;
private final NotificationActivityStarter mNotificationActivityStarter;
- public NotificationClicker(ShadeController shadeController,
+ public NotificationClicker(Optional<StatusBar> statusBar,
BubbleController bubbleController,
NotificationActivityStarter notificationActivityStarter) {
- mShadeController = shadeController;
+ mStatusBar = statusBar;
mBubbleController = bubbleController;
mNotificationActivityStarter = notificationActivityStarter;
}
@@ -52,7 +54,8 @@ public final class NotificationClicker implements View.OnClickListener {
return;
}
- mShadeController.wakeUpIfDozing(SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK");
+ mStatusBar.ifPresent(statusBar -> statusBar.wakeUpIfDozing(
+ SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK"));
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
final StatusBarNotification sbn = row.getEntry().getSbn();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index b61c1ef50cae..6c61923332ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -27,6 +27,7 @@ import android.service.notification.StatusBarNotification;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -45,6 +46,7 @@ public class NotificationFilter {
private final NotificationGroupManager mGroupManager = Dependency.get(
NotificationGroupManager.class);
+ private final StatusBarStateController mStatusBarStateController;
private NotificationEntryManager.KeyguardEnvironment mEnvironment;
private ShadeController mShadeController;
@@ -52,7 +54,9 @@ public class NotificationFilter {
private NotificationLockscreenUserManager mUserManager;
@Inject
- public NotificationFilter() {}
+ public NotificationFilter(StatusBarStateController statusBarStateController) {
+ mStatusBarStateController = statusBarStateController;
+ }
private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
if (mEnvironment == null) {
@@ -104,11 +108,11 @@ public class NotificationFilter {
return true;
}
- if (getShadeController().isDozing() && entry.shouldSuppressAmbient()) {
+ if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) {
return true;
}
- if (!getShadeController().isDozing() && entry.shouldSuppressNotificationList()) {
+ if (!mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 35407c6df690..ed2fb0fdcb1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2989,7 +2989,7 @@ public class NotificationPanelView extends PanelView implements
return true;
case StatusBarState.SHADE_LOCKED:
if (!mQsExpanded) {
- mShadeController.goToKeyguard();
+ mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
return true;
case StatusBarState.SHADE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index b31ce6afc281..deea3f17aad0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -14,11 +14,9 @@
package com.android.systemui.statusbar.phone;
-import android.annotation.NonNull;
import android.view.View;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
/**
* {@link ShadeController} is an abstraction of the work that used to be hard-coded in
@@ -30,14 +28,6 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi
public interface ShadeController {
/**
- * Shows the keyguard bouncer - the password challenge on the lock screen
- *
- * @param scrimmed true when the bouncer should show scrimmed, false when the user will be
- * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
- */
- void showBouncer(boolean scrimmed);
-
- /**
* Make our window larger and the panel expanded
*/
void instantExpandNotificationsPanel();
@@ -71,12 +61,6 @@ public interface ShadeController {
void addPostCollapseAction(Runnable action);
/**
- * Ask shade controller to set the state to {@link StatusBarState#KEYGUARD}, but only from
- * {@link StatusBarState#SHADE_LOCKED}
- */
- void goToKeyguard();
-
- /**
* Notify the shade controller that the current user changed
*
* @param newUserId userId of the new user
@@ -84,22 +68,6 @@ public interface ShadeController {
void setLockscreenUser(int newUserId);
/**
- * Dozing is when the screen is in AOD or asleep
- *
- * @return true if we are dozing
- */
- boolean isDozing();
-
- /**
- * Ask the display to wake up if currently dozing, else do nothing
- *
- * @param time when to wake up
- * @param view the view requesting the wakeup
- * @param why the reason for the wake up
- */
- void wakeUpIfDozing(long time, View view, @NonNull String why);
-
- /**
* If secure with redaction: Show bouncer, go to unlocked shade.
*
* <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
@@ -109,11 +77,6 @@ public interface ShadeController {
void goToLockedShade(View startingChild);
/**
- * Adds a {@param runnable} to be executed after Keyguard is gone.
- */
- void addAfterKeyguardGoneRunnable(Runnable runnable);
-
- /**
* Close the shade if it was open
*
* @return true if the shade was open, else false
@@ -127,16 +90,4 @@ public interface ShadeController {
* @param animate
*/
void collapsePanel(boolean animate);
-
- /**
- * Callback to tell the shade controller that an activity launch animation was canceled
- */
- void onLaunchAnimationCancelled();
-
- /**
- * Callback to notify the shade controller that a {@link ActivatableNotificationView} has become
- * inactive
- */
- void onActivationReset();
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 5575d10c7fe1..e31ad9fd4262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1239,6 +1239,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
mNotificationAlertingManager, rowBinder, mKeyguardStateController,
+ mKeyguardIndicationController,
this /* statusBar */, mCommandQueue);
mNotificationListController =
@@ -1263,7 +1264,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mRemoteInputUriController.attach(mEntryManager);
rowBinder.setNotificationClicker(new NotificationClicker(
- this, mBubbleController, mNotificationActivityStarter));
+ Optional.of(this), mBubbleController, mNotificationActivityStarter));
mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
mNotificationListController.bind();
@@ -1282,17 +1283,13 @@ public class StatusBar extends SystemUI implements DemoMode,
mCommandQueue.disable(mDisplayId, state1, state2, false /* animate */);
}
- @Override
- public void addAfterKeyguardGoneRunnable(Runnable runnable) {
- mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
- }
-
- @Override
- public boolean isDozing() {
- return mDozing;
- }
-
- @Override
+ /**
+ * Ask the display to wake up if currently dozing, else do nothing
+ *
+ * @param time when to wake up
+ * @param where the view requesting the wakeup
+ * @param why the reason for the wake up
+ */
public void wakeUpIfDozing(long time, View where, String why) {
if (mDozing) {
mPowerManager.wakeUp(
@@ -1708,7 +1705,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
mEntryManager.updateNotifications("onHeadsUpStateChanged");
- if (isDozing() && isHeadsUp) {
+ if (mStatusBarStateController.isDozing() && isHeadsUp) {
entry.setPulseSuppressed(false);
mDozeServiceHost.fireNotificationPulse(entry);
if (mDozeServiceHost.isPulsing()) {
@@ -3453,16 +3450,11 @@ public class StatusBar extends SystemUI implements DemoMode,
private void showBouncerIfKeyguard() {
if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
&& !mKeyguardViewMediator.isHiding()) {
- showBouncer(true /* scrimmed */);
+ mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
}
}
@Override
- public void showBouncer(boolean scrimmed) {
- mStatusBarKeyguardViewManager.showBouncer(scrimmed);
- }
-
- @Override
public void instantExpandNotificationsPanel() {
// Make our window larger and the panel expanded.
makeExpandedVisible(true);
@@ -3583,10 +3575,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarKeyguardViewManager.isOccluded());
}
- public void onActivationReset() {
- mKeyguardIndicationController.hideTransientIndication();
- }
-
public void onTrackingStarted() {
runPostCollapseRunnables();
}
@@ -3628,7 +3616,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public void onTrackingStopped(boolean expand) {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
if (!expand && !mKeyguardStateController.canDismissLockScreen()) {
- showBouncer(false /* scrimmed */);
+ mStatusBarKeyguardViewManager.showBouncer(false /* scrimmed */);
}
}
}
@@ -3688,15 +3676,6 @@ public class StatusBar extends SystemUI implements DemoMode,
}
/**
- * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
- */
- public void goToKeyguard() {
- if (mState == StatusBarState.SHADE_LOCKED) {
- mStatusBarStateController.setState(StatusBarState.KEYGUARD);
- }
- }
-
- /**
* Propagation of the bouncer state, indicating that it's fully visible.
*/
public void setBouncerShowing(boolean bouncerShowing) {
@@ -4019,7 +3998,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public boolean shouldIgnoreTouch() {
- return isDozing() && mDozeServiceHost.getIgnoreTouchWhilePulsing();
+ return mStatusBarStateController.isDozing()
+ && mDozeServiceHost.getIgnoreTouchWhilePulsing();
}
// Begin Extra BaseStatusBar methods.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 31d03621d23b..dac4e585c1ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -365,6 +365,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
cancelPendingWakeupAction();
}
+ /**
+ * Shows the keyguard bouncer - the password challenge on the lock screen
+ *
+ * @param scrimmed true when the bouncer should show scrimmed, false when the user will be
+ * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
+ */
public void showBouncer(boolean scrimmed) {
if (mShowing && !mBouncer.isShowing()) {
mBouncer.show(false /* resetSecuritySelection */, scrimmed);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index e2832587e2ea..1988b42be14f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -105,6 +105,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final NotificationPresenter mPresenter;
private final LockPatternUtils mLockPatternUtils;
private final HeadsUpManagerPhone mHeadsUpManager;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final KeyguardManager mKeyguardManager;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private final IStatusBarService mBarService;
@@ -122,7 +123,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
NotificationPresenter presenter, NotificationEntryManager entryManager,
HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter,
ActivityLaunchAnimator activityLaunchAnimator, IStatusBarService statusBarService,
- StatusBarStateController statusBarStateController, KeyguardManager keyguardManager,
+ StatusBarStateController statusBarStateController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ KeyguardManager keyguardManager,
IDreamManager dreamManager, NotificationRemoteInputManager remoteInputManager,
StatusBarRemoteInputCallback remoteInputCallback, NotificationGroupManager groupManager,
NotificationLockscreenUserManager lockscreenUserManager,
@@ -139,6 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mActivityLaunchAnimator = activityLaunchAnimator;
mBarService = statusBarService;
mCommandQueue = commandQueue;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardManager = keyguardManager;
mDreamManager = dreamManager;
mRemoteInputManager = remoteInputManager;
@@ -258,7 +262,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mShadeController.collapsePanel(true /* animate */);
} else if (mKeyguardStateController.isShowing()
&& mStatusBar.isOccluded()) {
- mShadeController.addAfterKeyguardGoneRunnable(runnable);
+ mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
mShadeController.collapsePanel();
} else {
mBackgroundHandler.postAtFrontOfQueue(runnable);
@@ -504,6 +508,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final ActivityStarter mActivityStarter;
private final IStatusBarService mStatusBarService;
private final StatusBarStateController mStatusBarStateController;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final KeyguardManager mKeyguardManager;
private final IDreamManager mDreamManager;
private final NotificationRemoteInputManager mRemoteInputManager;
@@ -533,6 +538,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
ActivityStarter activityStarter,
IStatusBarService statusBarService,
StatusBarStateController statusBarStateController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
KeyguardManager keyguardManager,
IDreamManager dreamManager,
NotificationRemoteInputManager remoteInputManager,
@@ -556,6 +562,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mActivityStarter = activityStarter;
mStatusBarService = statusBarService;
mStatusBarStateController = statusBarStateController;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardManager = keyguardManager;
mDreamManager = dreamManager;
mRemoteInputManager = remoteInputManager;
@@ -601,6 +608,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mActivityLaunchAnimator,
mStatusBarService,
mStatusBarStateController,
+ mStatusBarKeyguardViewManager,
mKeyguardManager,
mDreamManager,
mRemoteInputManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 6650cf6a5af6..2649166bfcbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -49,6 +49,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -113,6 +114,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final DozeScrimController mDozeScrimController;
private final ScrimController mScrimController;
private final Context mContext;
+ private final KeyguardIndicationController mKeyguardIndicationController;
private final StatusBar mStatusBar;
private final CommandQueue mCommandQueue;
@@ -141,6 +143,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
NotificationAlertingManager notificationAlertingManager,
NotificationRowBinderImpl notificationRowBinder,
KeyguardStateController keyguardStateController,
+ KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
CommandQueue commandQueue) {
mContext = context;
@@ -148,6 +151,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mNotificationPanel = panel;
mHeadsUpManager = headsUp;
mDynamicPrivacyController = dynamicPrivacyController;
+ mKeyguardIndicationController = keyguardIndicationController;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mStatusBar = statusBar;
mCommandQueue = commandQueue;
@@ -323,7 +327,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mCommandQueue.animateCollapsePanels();
} else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
&& !isCollapsing()) {
- mShadeController.goToKeyguard();
+ mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
}
}
@@ -420,7 +424,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
public void onActivationReset(ActivatableNotificationView view) {
if (view == mNotificationPanel.getActivatedChild()) {
mNotificationPanel.setActivatedChild(null);
- mShadeController.onActivationReset();
+ mKeyguardIndicationController.hideTransientIndication();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 3e6ba4dacb71..2012b5703504 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -64,6 +64,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
private final ActivityStarter mActivityStarter;
private final Lazy<ShadeController> mShadeControllerLazy;
private final Context mContext;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final ActivityIntentHelper mActivityIntentHelper;
private final NotificationGroupManager mGroupManager;
private View mPendingWorkRemoteInputView;
@@ -81,9 +82,11 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
NotificationLockscreenUserManager notificationLockscreenUserManager,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ActivityStarter activityStarter, Lazy<ShadeController> shadeControllerLazy,
CommandQueue commandQueue) {
mContext = context;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
mLockscreenUserManager = notificationLockscreenUserManager;
@@ -118,7 +121,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
if (!row.isPinned()) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
}
- mShadeControllerLazy.get().showBouncer(true /* scrimmed */);
+ mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
mPendingRemoteInputView = clicked;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index 3935df02fd91..f8929e01adb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -263,7 +263,7 @@ public class StatusBarWindowViewController {
if (isDown) {
mStackScrollLayout.closeControlsIfOutsideTouch(ev);
}
- if (mService.isDozing()) {
+ if (mStatusBarStateController.isDozing()) {
mService.mDozeScrimController.extendPulse();
}
// In case we start outside of the view bounds (below the status bar), we need to
@@ -284,7 +284,8 @@ public class StatusBarWindowViewController {
@Override
public boolean shouldInterceptTouchEvent(MotionEvent ev) {
- if (mService.isDozing() && !mService.isPulsing() && !mDockManager.isDocked()) {
+ if (mStatusBarStateController.isDozing() && !mService.isPulsing()
+ && !mDockManager.isDocked()) {
// Capture all touch events in always-on.
return true;
}
@@ -292,7 +293,7 @@ public class StatusBarWindowViewController {
if (notificationPanelView.isFullyExpanded()
&& mDragDownHelper.isDragDownEnabled()
&& !mService.isBouncerShowing()
- && !mService.isDozing()) {
+ && !mStatusBarStateController.isDozing()) {
intercept = mDragDownHelper.onInterceptTouchEvent(ev);
}
@@ -312,7 +313,7 @@ public class StatusBarWindowViewController {
@Override
public boolean handleTouchEvent(MotionEvent ev) {
boolean handled = false;
- if (mService.isDozing()) {
+ if (mStatusBarStateController.isDozing()) {
handled = !mService.isPulsing();
}
if ((mDragDownHelper.isDragDownEnabled() && !handled)
@@ -358,7 +359,7 @@ public class StatusBarWindowViewController {
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
- if (mService.isDozing()) {
+ if (mStatusBarStateController.isDozing()) {
MediaSessionLegacyHelper.getHelper(mView.getContext())
.sendVolumeKeyEvent(
event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
index 9b685f0ad0f6..74739e19ede9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
@@ -16,32 +16,44 @@
package com.android.systemui.statusbar.tv;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.IntDef;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
-import android.graphics.drawable.Drawable;
+import android.util.ArraySet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
-import android.widget.ImageView;
import android.widget.TextView;
import com.android.systemui.R;
-import java.util.ArrayList;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
-import java.util.List;
-
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * A component of {@link TvStatusBar} responsible for notifying the user whenever an application is
+ * recording audio.
+ *
+ * @see TvStatusBar
+ */
class AudioRecordingDisclosureBar {
private static final String TAG = "AudioRecordingDisclosureBar";
private static final boolean DEBUG = false;
@@ -50,121 +62,310 @@ class AudioRecordingDisclosureBar {
// CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest
private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator";
- private static final int ANIM_DURATION_MS = 150;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STATE_"}, value = {
+ STATE_NOT_SHOWN,
+ STATE_APPEARING,
+ STATE_SHOWN,
+ STATE_MINIMIZING,
+ STATE_MINIMIZED,
+ STATE_MAXIMIZING,
+ STATE_DISAPPEARING
+ })
+ public @interface State {}
+
+ private static final int STATE_NOT_SHOWN = 0;
+ private static final int STATE_APPEARING = 1;
+ private static final int STATE_SHOWN = 2;
+ private static final int STATE_MINIMIZING = 3;
+ private static final int STATE_MINIMIZED = 4;
+ private static final int STATE_MAXIMIZING = 5;
+ private static final int STATE_DISAPPEARING = 6;
+
+ private static final int ANIMATION_DURATION = 600;
+ private static final int MAXIMIZED_DURATION = 3000;
+ private static final int PULSE_BIT_DURATION = 1000;
+ private static final float PULSE_SCALE = 1.25f;
private final Context mContext;
- private final List<String> mAudioRecordingApps = new ArrayList<>();
- private View mView;
- private ViewGroup mAppsInfoContainer;
+
+ private View mIndicatorView;
+ private View mIconTextsContainer;
+ private View mIconContainerBg;
+ private View mIcon;
+ private View mBgRight;
+ private View mTextsContainers;
+ private TextView mTextView;
+
+ @State private int mState = STATE_NOT_SHOWN;
+ private final Set<String> mAudioRecordingApps = new HashSet<>();
+ private final Queue<String> mPendingNotifications = new LinkedList<>();
AudioRecordingDisclosureBar(Context context) {
mContext = context;
}
void start() {
- // Inflate and add audio recording disclosure bar
- createView();
-
// Register AppOpsManager callback
final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(
Context.APP_OPS_SERVICE);
appOpsManager.startWatchingActive(
- new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, mContext.getMainExecutor(),
+ new String[]{AppOpsManager.OPSTR_RECORD_AUDIO},
+ mContext.getMainExecutor(),
new OnActiveRecordingListener());
}
- private void createView() {
- //TODO(b/142228704): this is to be re-implemented once proper design is completed
- mView = View.inflate(mContext,
- R.layout.tv_status_bar_audio_recording, null);
- mAppsInfoContainer = mView.findViewById(R.id.container);
+ private void onStartedRecording(String packageName) {
+ if (!mAudioRecordingApps.add(packageName)) {
+ // This app is already known to perform recording
+ return;
+ }
+
+ switch (mState) {
+ case STATE_NOT_SHOWN:
+ show(packageName);
+ break;
+
+ case STATE_MINIMIZED:
+ expand(packageName);
+ break;
+
+ case STATE_DISAPPEARING:
+ case STATE_APPEARING:
+ case STATE_MAXIMIZING:
+ case STATE_SHOWN:
+ case STATE_MINIMIZING:
+ // Currently animating or expanded. Thus add to the pending notifications, and it
+ // will be picked up once the indicator comes to the STATE_MINIMIZED.
+ mPendingNotifications.add(packageName);
+ break;
+ }
+ }
+
+ private void onDoneRecording(String packageName) {
+ if (!mAudioRecordingApps.remove(packageName)) {
+ // Was not marked as an active recorder, do nothing
+ return;
+ }
+
+ // If not MINIMIZED, will check whether the indicator should be hidden when the indicator
+ // comes to the STATE_MINIMIZED eventually. If is in the STATE_MINIMIZED, but there are
+ // other active recorders - simply ignore.
+ if (mState == STATE_MINIMIZED && mAudioRecordingApps.isEmpty()) {
+ hide();
+ }
+ }
+
+ private void show(String packageName) {
+ // Inflate the indicator view
+ mIndicatorView = LayoutInflater.from(mContext).inflate(
+ R.layout.tv_audio_recording_indicator,
+ null);
+ mIconTextsContainer = mIndicatorView.findViewById(R.id.icon_texts_container);
+ mIconContainerBg = mIconTextsContainer.findViewById(R.id.icon_container_bg);
+ mIcon = mIconTextsContainer.findViewById(R.id.icon_mic);
+ mTextsContainers = mIconTextsContainer.findViewById(R.id.texts_container);
+ mTextView = mTextsContainers.findViewById(R.id.text);
+ mBgRight = mIndicatorView.findViewById(R.id.bg_right);
+
+ // Set up the notification text
+ final String label = getApplicationLabel(packageName);
+ mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
+
+ // Initially change the visibility to INVISIBLE, wait until and receives the size and
+ // then animate it moving from "off" the screen correctly
+ mIndicatorView.setVisibility(View.INVISIBLE);
+ mIndicatorView
+ .getViewTreeObserver()
+ .addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ // Remove the observer
+ mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener(
+ this);
+
+ // Now that the width of the indicator has been assigned, we can
+ // move it in from off the screen.
+ final int initialOffset = mIndicatorView.getWidth();
+ final AnimatorSet set = new AnimatorSet();
+ set.setDuration(ANIMATION_DURATION);
+ set.playTogether(
+ ObjectAnimator.ofFloat(mIndicatorView,
+ View.TRANSLATION_X, initialOffset, 0),
+ ObjectAnimator.ofFloat(mIndicatorView, View.ALPHA, 0f,
+ 1f));
+ set.addListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation,
+ boolean isReverse) {
+ // Indicator is INVISIBLE at the moment, change it.
+ mIndicatorView.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ startPulsatingAnimation();
+ onExpanded();
+ }
+ });
+ set.start();
+ }
+ });
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
- MATCH_PARENT,
+ WRAP_CONTENT,
WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
- layoutParams.gravity = Gravity.BOTTOM;
+ layoutParams.gravity = Gravity.TOP | Gravity.RIGHT;
layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
layoutParams.packageName = mContext.getPackageName();
-
final WindowManager windowManager = (WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE);
- windowManager.addView(mView, layoutParams);
+ windowManager.addView(mIndicatorView, layoutParams);
+
+ mState = STATE_APPEARING;
+ }
- // Set invisible first until it gains its actual size and we are able to hide it by moving
- // off the screen
- mView.setVisibility(View.INVISIBLE);
- mView.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
+ private void expand(String packageName) {
+ final String label = getApplicationLabel(packageName);
+ mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
+
+ final AnimatorSet set = new AnimatorSet();
+ set.playTogether(
+ ObjectAnimator.ofFloat(mIconTextsContainer, View.TRANSLATION_X, 0),
+ ObjectAnimator.ofFloat(mIconContainerBg, View.ALPHA, 1f),
+ ObjectAnimator.ofFloat(mTextsContainers, View.ALPHA, 1f),
+ ObjectAnimator.ofFloat(mBgRight, View.ALPHA, 1f));
+ set.setDuration(ANIMATION_DURATION);
+ set.addListener(
+ new AnimatorListenerAdapter() {
@Override
- public void onGlobalLayout() {
- // Now that we get the height, we can move the bar off ("below") the screen
- final int height = mView.getHeight();
- mView.setTranslationY(height);
- // Remove the observer
- mView.getViewTreeObserver()
- .removeOnGlobalLayoutListener(this);
- // Now, that the view has been measured, and the translation was set to
- // move it off the screen, we change the visibility to GONE
- mView.setVisibility(View.GONE);
+ public void onAnimationEnd(Animator animation) {
+ onExpanded();
}
});
+ set.start();
+
+ mState = STATE_MAXIMIZING;
}
- private void showAudioRecordingDisclosureBar() {
- mView.setVisibility(View.VISIBLE);
- mView.animate()
- .translationY(0f)
- .setDuration(ANIM_DURATION_MS)
- .start();
+ private void minimize() {
+ final int targetOffset = mTextsContainers.getWidth();
+ final AnimatorSet set = new AnimatorSet();
+ set.playTogether(
+ ObjectAnimator.ofFloat(mIconTextsContainer, View.TRANSLATION_X, targetOffset),
+ ObjectAnimator.ofFloat(mIconContainerBg, View.ALPHA, 0f),
+ ObjectAnimator.ofFloat(mTextsContainers, View.ALPHA, 0f),
+ ObjectAnimator.ofFloat(mBgRight, View.ALPHA, 0f));
+ set.setDuration(ANIMATION_DURATION);
+ set.addListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ onMinimized();
+ }
+ });
+ set.start();
+
+ mState = STATE_MINIMIZING;
}
- private void addToAudioRecordingDisclosureBar(String packageName) {
- final PackageManager pm = mContext.getPackageManager();
- final ApplicationInfo appInfo;
- try {
- appInfo = pm.getApplicationInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- return;
+ private void hide() {
+ final int targetOffset =
+ mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX();
+ final AnimatorSet set = new AnimatorSet();
+ set.playTogether(
+ ObjectAnimator.ofFloat(mIndicatorView, View.TRANSLATION_X, targetOffset),
+ ObjectAnimator.ofFloat(mIcon, View.ALPHA, 0f));
+ set.setDuration(ANIMATION_DURATION);
+ set.addListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ onHidden();
+ }
+ });
+ set.start();
+
+ mState = STATE_DISAPPEARING;
+ }
+
+ private void onExpanded() {
+ mState = STATE_SHOWN;
+
+ mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION);
+ }
+
+ private void onMinimized() {
+ mState = STATE_MINIMIZED;
+
+ if (!mPendingNotifications.isEmpty()) {
+ // There is a new application that started recording, tell the user about it.
+ expand(mPendingNotifications.poll());
+ } else if (mAudioRecordingApps.isEmpty()) {
+ // Nobody is recording anymore, remove the indicator.
+ hide();
}
- final CharSequence label = pm.getApplicationLabel(appInfo);
- final Drawable icon = pm.getApplicationIcon(appInfo);
+ }
+
+ private void onHidden() {
+ final WindowManager windowManager = (WindowManager) mContext.getSystemService(
+ Context.WINDOW_SERVICE);
+ windowManager.removeView(mIndicatorView);
- final View view = LayoutInflater.from(mContext).inflate(R.layout.tv_item_app_info,
- mAppsInfoContainer, false);
- ((TextView) view.findViewById(R.id.title)).setText(label);
- ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(icon);
+ mIndicatorView = null;
+ mIconTextsContainer = null;
+ mIconContainerBg = null;
+ mIcon = null;
+ mTextsContainers = null;
+ mTextView = null;
+ mBgRight = null;
- mAppsInfoContainer.addView(view);
+ mState = STATE_NOT_SHOWN;
}
- private void removeFromAudioRecordingDisclosureBar(int index) {
- mAppsInfoContainer.removeViewAt(index);
+ private void startPulsatingAnimation() {
+ final View pulsatingView = mIconTextsContainer.findViewById(R.id.pulsating_circle);
+ final ObjectAnimator animator =
+ ObjectAnimator.ofPropertyValuesHolder(
+ pulsatingView,
+ PropertyValuesHolder.ofFloat(View.SCALE_X, PULSE_SCALE),
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, PULSE_SCALE));
+ animator.setDuration(PULSE_BIT_DURATION);
+ animator.setRepeatCount(ObjectAnimator.INFINITE);
+ animator.setRepeatMode(ObjectAnimator.REVERSE);
+ animator.start();
}
- private void hideAudioRecordingDisclosureBar() {
- final ViewPropertyAnimator animator = mView.animate();
- animator.translationY(mView.getHeight())
- .setDuration(ANIM_DURATION_MS)
- .withEndAction(() -> mView.setVisibility(View.GONE))
- .start();
+ private String getApplicationLabel(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ final ApplicationInfo appInfo;
+ try {
+ appInfo = pm.getApplicationInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return packageName;
+ }
+ return pm.getApplicationLabel(appInfo).toString();
}
private class OnActiveRecordingListener implements AppOpsManager.OnOpActiveChangedListener {
- private final List<String> mExemptApps;
+ private final Set<String> mExemptApps;
private OnActiveRecordingListener() {
- mExemptApps = Arrays.asList(mContext.getResources().getStringArray(
- R.array.audio_recording_disclosure_exempt_apps));
+ mExemptApps = new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(
+ R.array.audio_recording_disclosure_exempt_apps)));
}
@Override
public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
if (DEBUG) {
Log.d(TAG,
- "OP_RECORD_AUDIO active change, active=" + active + ", app=" + packageName);
+ "OP_RECORD_AUDIO active change, active=" + active + ", app="
+ + packageName);
}
if (mExemptApps.contains(packageName)) {
@@ -174,37 +375,10 @@ class AudioRecordingDisclosureBar {
return;
}
- final boolean alreadyTracking = mAudioRecordingApps.contains(packageName);
- if ((active && alreadyTracking) || (!active && !alreadyTracking)) {
- if (DEBUG) {
- Log.d(TAG, "\t- nothing changed");
- }
- return;
- }
-
if (active) {
- if (DEBUG) {
- Log.d(TAG, "\t- new recording app");
- }
-
- if (mAudioRecordingApps.isEmpty()) {
- showAudioRecordingDisclosureBar();
- }
-
- mAudioRecordingApps.add(packageName);
- addToAudioRecordingDisclosureBar(packageName);
+ onStartedRecording(packageName);
} else {
- if (DEBUG) {
- Log.d(TAG, "\t- not recording any more");
- }
-
- final int index = mAudioRecordingApps.indexOf(packageName);
- removeFromAudioRecordingDisclosureBar(index);
- mAudioRecordingApps.remove(index);
-
- if (mAudioRecordingApps.isEmpty()) {
- hideAudioRecordingDisclosureBar();
- }
+ onDoneRecording(packageName);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 5ed8b8f9e362..e1210011c7a4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -21,7 +21,11 @@ import android.media.AudioSystem;
import android.provider.Settings.Global;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.plugins.VolumeDialogController.State;
@@ -37,7 +41,7 @@ public class Events {
public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int)
public static final int EVENT_ACTIVE_STREAM_CHANGED = 2; // (stream|int)
public static final int EVENT_EXPAND = 3; // (expand|bool)
- public static final int EVENT_KEY = 4;
+ public static final int EVENT_KEY = 4; // (stream|int) (lastAudibleStreamVolume)
public static final int EVENT_COLLECTION_STARTED = 5;
public static final int EVENT_COLLECTION_STOPPED = 6;
public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int)
@@ -49,7 +53,7 @@ public class Events {
public static final int EVENT_ZEN_MODE_CHANGED = 13; // (mode|int)
public static final int EVENT_SUPPRESSOR_CHANGED = 14; // (component|string) (name|string)
public static final int EVENT_MUTE_CHANGED = 15; // (stream|int) (muted|bool)
- public static final int EVENT_TOUCH_LEVEL_DONE = 16; // (stream|int) (level|bool)
+ public static final int EVENT_TOUCH_LEVEL_DONE = 16; // (stream|int) (level|int)
public static final int EVENT_ZEN_CONFIG_CHANGED = 17; // (allow/disallow|string)
public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode)
public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
@@ -122,103 +126,363 @@ public class Events {
public static final int ICON_STATE_MUTE = 2;
public static final int ICON_STATE_VIBRATE = 3;
+ @VisibleForTesting
+ public enum VolumeDialogOpenEvent implements UiEventLogger.UiEventEnum {
+ //TODO zap the lock/unlock distinction
+ INVALID(0),
+ @UiEvent(doc = "The volume dialog was shown because the volume changed")
+ VOLUME_DIALOG_SHOW_VOLUME_CHANGED(128),
+ @UiEvent(doc = "The volume dialog was shown because the volume changed remotely")
+ VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED(129),
+ @UiEvent(doc = "The volume dialog was shown because the usb high temperature alarm changed")
+ VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED(130);
+
+ private final int mId;
+ VolumeDialogOpenEvent(int id) {
+ mId = id;
+ }
+ public int getId() {
+ return mId;
+ }
+ static VolumeDialogOpenEvent fromReasons(int reason) {
+ switch (reason) {
+ case SHOW_REASON_VOLUME_CHANGED:
+ return VOLUME_DIALOG_SHOW_VOLUME_CHANGED;
+ case SHOW_REASON_REMOTE_VOLUME_CHANGED:
+ return VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED;
+ case SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED:
+ return VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED;
+ }
+ return INVALID;
+ }
+ }
+
+ @VisibleForTesting
+ public enum VolumeDialogCloseEvent implements UiEventLogger.UiEventEnum {
+ INVALID(0),
+ @UiEvent(doc = "The volume dialog was dismissed because of a touch outside the dialog")
+ VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE(134),
+ @UiEvent(doc = "The system asked the volume dialog to close, e.g. for a navigation bar "
+ + "touch, or ActivityManager ACTION_CLOSE_SYSTEM_DIALOGS broadcast.")
+ VOLUME_DIALOG_DISMISS_SYSTEM(135),
+ @UiEvent(doc = "The volume dialog was dismissed because it timed out")
+ VOLUME_DIALOG_DISMISS_TIMEOUT(136),
+ @UiEvent(doc = "The volume dialog was dismissed because the screen turned off")
+ VOLUME_DIALOG_DISMISS_SCREEN_OFF(137),
+ @UiEvent(doc = "The volume dialog was dismissed because the settings icon was clicked")
+ VOLUME_DIALOG_DISMISS_SETTINGS(138),
+ // reserving 139 for DISMISS_REASON_DONE_CLICKED which is currently unused
+ @UiEvent(doc = "The volume dialog was dismissed because the stream no longer exists")
+ VOLUME_DIALOG_DISMISS_STREAM_GONE(140),
+ // reserving 141 for DISMISS_REASON_OUTPUT_CHOOSER which is currently unused
+ @UiEvent(doc = "The volume dialog was dismissed because the usb high temperature alarm "
+ + "changed")
+ VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED(142);
+
+ private final int mId;
+ VolumeDialogCloseEvent(int id) {
+ mId = id;
+ }
+ public int getId() {
+ return mId;
+ }
+
+ static VolumeDialogCloseEvent fromReason(int reason) {
+ switch (reason) {
+ case DISMISS_REASON_TOUCH_OUTSIDE:
+ return VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE;
+ case DISMISS_REASON_VOLUME_CONTROLLER:
+ return VOLUME_DIALOG_DISMISS_SYSTEM;
+ case DISMISS_REASON_TIMEOUT:
+ return VOLUME_DIALOG_DISMISS_TIMEOUT;
+ case DISMISS_REASON_SCREEN_OFF:
+ return VOLUME_DIALOG_DISMISS_SCREEN_OFF;
+ case DISMISS_REASON_SETTINGS_CLICKED:
+ return VOLUME_DIALOG_DISMISS_SETTINGS;
+ case DISMISS_STREAM_GONE:
+ return VOLUME_DIALOG_DISMISS_STREAM_GONE;
+ case DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED:
+ return VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED;
+ }
+ return INVALID;
+ }
+ }
+
+ @VisibleForTesting
+ public enum VolumeDialogEvent implements UiEventLogger.UiEventEnum {
+ INVALID(0),
+ @UiEvent(doc = "The volume dialog settings icon was clicked")
+ VOLUME_DIALOG_SETTINGS_CLICK(143),
+ @UiEvent(doc = "The volume dialog details were expanded")
+ VOLUME_DIALOG_EXPAND_DETAILS(144),
+ @UiEvent(doc = "The volume dialog details were collapsed")
+ VOLUME_DIALOG_COLLAPSE_DETAILS(145),
+ @UiEvent(doc = "The active audio stream changed")
+ VOLUME_DIALOG_ACTIVE_STREAM_CHANGED(146),
+ @UiEvent(doc = "The audio stream was muted via icon")
+ VOLUME_DIALOG_MUTE_STREAM(147),
+ @UiEvent(doc = "The audio stream was unmuted via icon")
+ VOLUME_DIALOG_UNMUTE_STREAM(148),
+ @UiEvent(doc = "The audio stream was set to vibrate via icon")
+ VOLUME_DIALOG_TO_VIBRATE_STREAM(149),
+ @UiEvent(doc = "The audio stream was set to non-silent via slider")
+ VOLUME_DIALOG_SLIDER(150),
+ @UiEvent(doc = "The audio stream was set to silent via slider")
+ VOLUME_DIALOG_SLIDER_TO_ZERO(151),
+ @UiEvent(doc = "The audio volume was adjusted to silent via key")
+ VOLUME_KEY_TO_ZERO(152),
+ @UiEvent(doc = "The audio volume was adjusted to non-silent via key")
+ VOLUME_KEY(153),
+ @UiEvent(doc = "The ringer mode was toggled to silent")
+ RINGER_MODE_SILENT(154),
+ @UiEvent(doc = "The ringer mode was toggled to vibrate")
+ RINGER_MODE_VIBRATE(155),
+ @UiEvent(doc = "The ringer mode was toggled to normal")
+ RINGER_MODE_NORMAL(156),
+ @UiEvent(doc = "USB Overheat alarm was raised")
+ USB_OVERHEAT_ALARM(160),
+ @UiEvent(doc = "USB Overheat alarm was dismissed")
+ USB_OVERHEAT_ALARM_DISMISSED(161);
+
+ private final int mId;
+
+ VolumeDialogEvent(int id) {
+ mId = id;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ static VolumeDialogEvent fromIconState(int iconState) {
+ switch (iconState) {
+ case ICON_STATE_UNMUTE:
+ return VOLUME_DIALOG_UNMUTE_STREAM;
+ case ICON_STATE_MUTE:
+ return VOLUME_DIALOG_MUTE_STREAM;
+ case ICON_STATE_VIBRATE:
+ return VOLUME_DIALOG_TO_VIBRATE_STREAM;
+ default:
+ return INVALID;
+ }
+ }
+
+ static VolumeDialogEvent fromSliderLevel(int level) {
+ return level == 0 ? VOLUME_DIALOG_SLIDER_TO_ZERO : VOLUME_DIALOG_SLIDER;
+ }
+
+ static VolumeDialogEvent fromKeyLevel(int level) {
+ return level == 0 ? VOLUME_KEY_TO_ZERO : VOLUME_KEY;
+ }
+
+ static VolumeDialogEvent fromRingerMode(int ringerMode) {
+ switch (ringerMode) {
+ case AudioManager.RINGER_MODE_SILENT:
+ return RINGER_MODE_SILENT;
+ case AudioManager.RINGER_MODE_VIBRATE:
+ return RINGER_MODE_VIBRATE;
+ case AudioManager.RINGER_MODE_NORMAL:
+ return RINGER_MODE_NORMAL;
+ default:
+ return INVALID;
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public enum ZenModeEvent implements UiEventLogger.UiEventEnum {
+ INVALID(0),
+ @UiEvent(doc = "Zen (do not disturb) mode was toggled to off")
+ ZEN_MODE_OFF(156),
+ @UiEvent(doc = "Zen (do not disturb) mode was toggled to important interruptions only")
+ ZEN_MODE_IMPORTANT_ONLY(157),
+ @UiEvent(doc = "Zen (do not disturb) mode was toggled to alarms only")
+ ZEN_MODE_ALARMS_ONLY(158),
+ @UiEvent(doc = "Zen (do not disturb) mode was toggled to block all interruptions")
+ ZEN_MODE_NO_INTERRUPTIONS(159);
+
+ private final int mId;
+ ZenModeEvent(int id) {
+ mId = id;
+ }
+ public int getId() {
+ return mId;
+ }
+
+ static ZenModeEvent fromZenMode(int zenMode) {
+ switch (zenMode) {
+ case Global.ZEN_MODE_OFF: return ZEN_MODE_OFF;
+ case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return ZEN_MODE_IMPORTANT_ONLY;
+ case Global.ZEN_MODE_ALARMS: return ZEN_MODE_ALARMS_ONLY;
+ case Global.ZEN_MODE_NO_INTERRUPTIONS: return ZEN_MODE_NO_INTERRUPTIONS;
+ default: return INVALID;
+ }
+ }
+ }
+
public static Callback sCallback;
+ @VisibleForTesting
+ static MetricsLogger sLegacyLogger = new MetricsLogger();
+ @VisibleForTesting
+ static UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
/**
- * Logs an event to the system log and the event log.
+ * Logs an event to the system log, to sCallback if present, and to the logEvent destinations.
* @param tag One of the EVENT_* codes above.
* @param list Any additional event-specific arguments, documented above.
*/
public static void writeEvent(int tag, Object... list) {
- MetricsLogger logger = new MetricsLogger();
final long time = System.currentTimeMillis();
+ Log.i(TAG, logEvent(tag, list));
+ if (sCallback != null) {
+ sCallback.writeEvent(time, tag, list);
+ }
+ }
+
+ /**
+ * Logs an event to the event log and UiEvent (Westworld) logging. Compare writeEvent, which
+ * adds more log destinations.
+ * @param tag One of the EVENT_* codes above.
+ * @param list Any additional event-specific arguments, documented above.
+ * @return String a readable description of the event. Begins "writeEvent <tag_description>"
+ * if the tag is valid.
+ */
+ public static String logEvent(int tag, Object... list) {
+ if (tag >= EVENT_TAGS.length) {
+ return "";
+ }
final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]);
- if (list != null && list.length > 0) {
- sb.append(" ");
- switch (tag) {
- case EVENT_SHOW_DIALOG:
- logger.visible(MetricsEvent.VOLUME_DIALOG);
- logger.histogram("volume_from_keyguard",
- (Boolean) list[1] ? 1 : 0);
- sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
- break;
- case EVENT_EXPAND:
- logger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS,
- (Boolean) list[0]);
- sb.append(list[0]);
- break;
- case EVENT_DISMISS_DIALOG:
- logger.hidden(MetricsEvent.VOLUME_DIALOG);
- sb.append(DISMISS_REASONS[(Integer) list[0]]);
- break;
- case EVENT_ACTIVE_STREAM_CHANGED:
- logger.action(MetricsEvent.ACTION_VOLUME_STREAM,
- (Integer) list[0]);
- sb.append(AudioSystem.streamToString((Integer) list[0]));
- break;
- case EVENT_ICON_CLICK:
- logger.action(MetricsEvent.ACTION_VOLUME_ICON,
- (Integer) list[0]);
- sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
- .append(iconStateToString((Integer) list[1]));
- break;
- case EVENT_TOUCH_LEVEL_DONE:
- logger.action(MetricsEvent.ACTION_VOLUME_SLIDER,
- (Integer) list[1]);
- // fall through
- case EVENT_TOUCH_LEVEL_CHANGED:
- case EVENT_LEVEL_CHANGED:
- case EVENT_MUTE_CHANGED:
- sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
- .append(list[1]);
- break;
- case EVENT_KEY:
- logger.action(MetricsEvent.ACTION_VOLUME_KEY,
- (Integer) list[0]);
+ // Handle events without extra data
+ if (list == null || list.length == 0) {
+ if (tag == EVENT_SETTINGS_CLICK) {
+ sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SETTINGS);
+ sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_SETTINGS_CLICK);
+ }
+ return sb.toString();
+ }
+ // Handle events with extra data. We've established list[0] exists.
+ sb.append(" ");
+ switch (tag) {
+ case EVENT_SHOW_DIALOG:
+ sLegacyLogger.visible(MetricsEvent.VOLUME_DIALOG);
+ if (list.length > 1) {
+ final Integer reason = (Integer) list[0];
+ final Boolean keyguard = (Boolean) list[1];
+ sLegacyLogger.histogram("volume_from_keyguard", keyguard ? 1 : 0);
+ sUiEventLogger.log(VolumeDialogOpenEvent.fromReasons(reason));
+ sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard);
+ }
+ break;
+ case EVENT_EXPAND: {
+ final Boolean expand = (Boolean) list[0];
+ sLegacyLogger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS, expand);
+ sUiEventLogger.log(expand ? VolumeDialogEvent.VOLUME_DIALOG_EXPAND_DETAILS
+ : VolumeDialogEvent.VOLUME_DIALOG_COLLAPSE_DETAILS);
+ sb.append(expand);
+ break;
+ }
+ case EVENT_DISMISS_DIALOG: {
+ sLegacyLogger.hidden(MetricsEvent.VOLUME_DIALOG);
+ final Integer reason = (Integer) list[0];
+ sUiEventLogger.log(VolumeDialogCloseEvent.fromReason(reason));
+ sb.append(DISMISS_REASONS[reason]);
+ break;
+ }
+ case EVENT_ACTIVE_STREAM_CHANGED: {
+ final Integer stream = (Integer) list[0];
+ sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_STREAM, stream);
+ sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_ACTIVE_STREAM_CHANGED);
+ sb.append(AudioSystem.streamToString(stream));
+ break;
+ }
+ case EVENT_ICON_CLICK:
+ if (list.length > 1) {
+ final Integer stream = (Integer) list[0];
+ sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_ICON, stream);
+ final Integer iconState = (Integer) list[1];
+ sUiEventLogger.log(VolumeDialogEvent.fromIconState(iconState));
+ sb.append(AudioSystem.streamToString(stream)).append(' ')
+ .append(iconStateToString(iconState));
+ }
+ break;
+ case EVENT_TOUCH_LEVEL_DONE: // (stream|int) (level|int)
+ if (list.length > 1) {
+ final Integer level = (Integer) list[1];
+ sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SLIDER, level);
+ sUiEventLogger.log(VolumeDialogEvent.fromSliderLevel(level));
+ }
+ // fall through
+ case EVENT_TOUCH_LEVEL_CHANGED:
+ case EVENT_LEVEL_CHANGED:
+ case EVENT_MUTE_CHANGED: // (stream|int) (level|int)
+ if (list.length > 1) {
sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
.append(list[1]);
- break;
- case EVENT_RINGER_TOGGLE:
- logger.action(MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE, (Integer) list[0]);
- break;
- case EVENT_SETTINGS_CLICK:
- logger.action(MetricsEvent.ACTION_VOLUME_SETTINGS);
- break;
- case EVENT_EXTERNAL_RINGER_MODE_CHANGED:
- logger.action(MetricsEvent.ACTION_RINGER_MODE,
- (Integer) list[0]);
- // fall through
- case EVENT_INTERNAL_RINGER_MODE_CHANGED:
- sb.append(ringerModeToString((Integer) list[0]));
- break;
- case EVENT_ZEN_MODE_CHANGED:
- sb.append(zenModeToString((Integer) list[0]));
- break;
- case EVENT_SUPPRESSOR_CHANGED:
- sb.append(list[0]).append(' ').append(list[1]);
- break;
- case EVENT_SHOW_USB_OVERHEAT_ALARM:
- logger.visible(MetricsEvent.POWER_OVERHEAT_ALARM);
- logger.histogram("show_usb_overheat_alarm",
- (Boolean) list[1] ? 1 : 0);
- sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
- break;
- case EVENT_DISMISS_USB_OVERHEAT_ALARM:
- logger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM);
- logger.histogram("dismiss_usb_overheat_alarm",
- (Boolean) list[1] ? 1 : 0);
- sb.append(DISMISS_REASONS[(Integer) list[0]])
- .append(" keyguard=").append(list[1]);
- break;
- default:
- sb.append(Arrays.asList(list));
- break;
+ }
+ break;
+ case EVENT_KEY: // (stream|int) (lastAudibleStreamVolume)
+ if (list.length > 1) {
+ final Integer stream = (Integer) list[0];
+ sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_KEY, stream);
+ final Integer level = (Integer) list[1];
+ sUiEventLogger.log(VolumeDialogEvent.fromKeyLevel(level));
+ sb.append(AudioSystem.streamToString(stream)).append(' ').append(level);
+ }
+ break;
+ case EVENT_RINGER_TOGGLE: {
+ final Integer ringerMode = (Integer) list[0];
+ sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE, ringerMode);
+ sUiEventLogger.log(VolumeDialogEvent.fromRingerMode(ringerMode));
+ sb.append(ringerModeToString(ringerMode));
+ break;
}
+ case EVENT_EXTERNAL_RINGER_MODE_CHANGED: {
+ final Integer ringerMode = (Integer) list[0];
+ sLegacyLogger.action(MetricsEvent.ACTION_RINGER_MODE, ringerMode);
+ }
+ // fall through
+ case EVENT_INTERNAL_RINGER_MODE_CHANGED: {
+ final Integer ringerMode = (Integer) list[0];
+ sb.append(ringerModeToString(ringerMode));
+ break;
+ }
+ case EVENT_ZEN_MODE_CHANGED: {
+ final Integer zenMode = (Integer) list[0];
+ sb.append(zenModeToString(zenMode));
+ sUiEventLogger.log(ZenModeEvent.fromZenMode(zenMode));
+ break;
+ }
+ case EVENT_SUPPRESSOR_CHANGED: // (component|string) (name|string)
+ if (list.length > 1) {
+ sb.append(list[0]).append(' ').append(list[1]);
+ }
+ break;
+ case EVENT_SHOW_USB_OVERHEAT_ALARM:
+ sLegacyLogger.visible(MetricsEvent.POWER_OVERHEAT_ALARM);
+ sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM);
+ if (list.length > 1) {
+ final Boolean keyguard = (Boolean) list[1];
+ sLegacyLogger.histogram("show_usb_overheat_alarm", keyguard ? 1 : 0);
+ final Integer reason = (Integer) list[0];
+ sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard);
+ }
+ break;
+ case EVENT_DISMISS_USB_OVERHEAT_ALARM:
+ sLegacyLogger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM);
+ sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM_DISMISSED);
+ if (list.length > 1) {
+ final Boolean keyguard = (Boolean) list[1];
+ sLegacyLogger.histogram("dismiss_usb_overheat_alarm", keyguard ? 1 : 0);
+ final Integer reason = (Integer) list[0];
+ sb.append(DISMISS_REASONS[reason])
+ .append(" keyguard=").append(keyguard);
+ }
+ break;
+ default:
+ sb.append(Arrays.asList(list));
+ break;
}
- Log.i(TAG, sb.toString());
- if (sCallback != null) {
- sCallback.writeEvent(time, tag, list);
- }
+ return sb.toString();
}
public static void writeState(long time, State state) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 2242c1adb1d4..42fbf59fef44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -93,7 +93,7 @@ class BroadcastDispatcherTest : SysuiTestCase() {
// These should be valid filters
`when`(intentFilter.countActions()).thenReturn(1)
`when`(intentFilterOther.countActions()).thenReturn(1)
- `when`(mockContext.user).thenReturn(user0)
+ setUserMock(mockContext, user0)
}
@Test
@@ -140,6 +140,18 @@ class BroadcastDispatcherTest : SysuiTestCase() {
verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver)
}
+ @Test
+ fun testRegisterCurrentAsActualUser() {
+ setUserMock(mockContext, user1)
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler,
+ UserHandle.CURRENT)
+
+ testableLooper.processAllMessages()
+
+ verify(mockUBRUser1).registerReceiver(capture(argumentCaptor))
+ assertSame(broadcastReceiver, argumentCaptor.value.receiver)
+ }
+
@Test(expected = IllegalArgumentException::class)
fun testFilterMustContainActions() {
val testFilter = IntentFilter()
@@ -186,6 +198,11 @@ class BroadcastDispatcherTest : SysuiTestCase() {
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
+ private fun setUserMock(mockContext: Context, user: UserHandle) {
+ `when`(mockContext.user).thenReturn(user)
+ `when`(mockContext.userId).thenReturn(user.identifier)
+ }
+
private class TestBroadcastDispatcher(
context: Context,
mainHandler: Handler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index ae43aa2f4118..e0d31d053f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -479,7 +479,7 @@ public class BubbleControllerTest extends SysuiTestCase {
}
@Test
- public void testAutoExpand_FailsNotForeground() {
+ public void testAutoExpand_fails_noFlag() {
assertFalse(mBubbleController.isStackExpanded());
setMetadataFlags(mRow.getEntry(),
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
@@ -498,7 +498,7 @@ public class BubbleControllerTest extends SysuiTestCase {
}
@Test
- public void testAutoExpand_SucceedsForeground() {
+ public void testAutoExpand_succeeds_withFlag() {
setMetadataFlags(mRow.getEntry(),
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
@@ -516,38 +516,52 @@ public class BubbleControllerTest extends SysuiTestCase {
}
@Test
- public void testSuppressNotif_FailsNotForeground() {
+ public void testSuppressNotif_onInitialNotif() {
setMetadataFlags(mRow.getEntry(),
- Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, false /* enableFlag */);
+ Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
// Add the suppress notif bubble
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
- // Should not be suppressed because we weren't forground
- assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ // Notif should be suppressed because we were foreground
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry().getKey()));
+ // Dot + flyout is hidden because notif is suppressed
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
}
@Test
- public void testSuppressNotif_SucceedsForeground() {
+ public void testSuppressNotif_onUpdateNotif() {
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // Should not be suppressed
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry().getKey()));
+ // Should show dot
+ assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+
+ // Update to suppress notif
setMetadataFlags(mRow.getEntry(),
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
-
- // Add the suppress notif bubble
- mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
- // Notif should be suppressed because we were foreground
+ // Notif should be suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry().getKey()));
+ // Dot + flyout is hidden because notif is suppressed
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
}
+
@Test
public void testExpandStackAndSelectBubble_removedFirst() {
final String key = mRow.getEntry().getKey();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 95c7af31865b..1554abcec3b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -42,6 +42,7 @@ import com.android.systemui.bubbles.BubbleData.TimeSource;
import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.google.common.collect.ImmutableList;
@@ -119,7 +120,9 @@ public class BubbleDataTest extends SysuiTestCase {
.setVisuallyInterruptive(true)
.build();
+ ExpandableNotificationRow row = mNotificationTestHelper.createBubble();
mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d");
+ mEntryDismissed.setRow(row);
mBubbleA1 = new Bubble(mContext, mEntryA1);
mBubbleA2 = new Bubble(mContext, mEntryA2);
@@ -192,9 +195,8 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.notificationEntryUpdated(mEntryInterruptive, /* suppressFlyout */
- false, /* showInShade */
- true);
+ mBubbleData.notificationEntryUpdated(mEntryInterruptive,
+ false /* suppressFlyout */, true /* showInShade */);
// Verify
verifyUpdateReceived();
@@ -208,12 +210,12 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleData.setListener(mListener);
// Test
- mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
- true);
+ mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */,
+ true /* showInShade */);
verifyUpdateReceived();
- mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
- true);
+ mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */,
+ true /* showInShade */);
verifyUpdateReceived();
// Verify
@@ -225,16 +227,18 @@ public class BubbleDataTest extends SysuiTestCase {
public void sameUpdate_NotInShade_showFlyout() {
// Setup
mBubbleData.setListener(mListener);
- setMetadataFlags(mEntryDismissed,
- Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, /* enableFlag */ true);
// Test
- mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */ false,
- /* showInShade */ false);
+ mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */,
+ false /* showInShade */);
verifyUpdateReceived();
- mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */
- false, /* showInShade */ false);
+ // Make it look like user swiped away row
+ mEntryDismissed.getRow().dismiss(false /* refocusOnDismiss */);
+ assertThat(mBubbleData.getBubbleWithKey(mEntryDismissed.getKey()).showInShade()).isFalse();
+
+ mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */,
+ false /* showInShade */);
verifyUpdateReceived();
// Verify
@@ -936,23 +940,6 @@ public class BubbleDataTest extends SysuiTestCase {
}
/**
- * Sets the bubble metadata flags for this entry. These flags are normally set by
- * NotificationManagerService when the notification is sent, however, these tests do not
- * go through that path so we set them explicitly when testing.
- */
- private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
- Notification.BubbleMetadata bubbleMetadata =
- entry.getSbn().getNotification().getBubbleMetadata();
- int flags = bubbleMetadata.getFlags();
- if (enableFlag) {
- flags |= flag;
- } else {
- flags &= ~flag;
- }
- bubbleMetadata.setFlags(flags);
- }
-
- /**
* No ExpandableNotificationRow is required to test BubbleData. This setup is all that is
* required for BubbleData functionality and verification. NotificationTestHelper is used only
* as a convenience to create a Notification w/BubbleMetadata.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java
new file mode 100644
index 000000000000..c827ac7ab963
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.glwallpaper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ImageRevealHelperTest extends SysuiTestCase {
+
+ static final int ANIMATION_DURATION = 500;
+ ImageRevealHelper mImageRevealHelper;
+ ImageRevealHelper.RevealStateListener mRevealStateListener;
+
+ @Before
+ public void setUp() throws Exception {
+ mRevealStateListener = new ImageRevealHelper.RevealStateListener() {
+ @Override
+ public void onRevealStateChanged() {
+ // no-op
+ }
+
+ @Override
+ public void onRevealStart(boolean animate) {
+ // no-op
+ }
+
+ @Override
+ public void onRevealEnd() {
+ // no-op
+ }
+ };
+ mImageRevealHelper = new ImageRevealHelper(mRevealStateListener);
+ }
+
+ @Test
+ public void testBiometricAuthUnlockAnimateImageRevealState_shouldNotBlackoutScreen() {
+ assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f);
+
+ mImageRevealHelper.updateAwake(true /* awake */, ANIMATION_DURATION);
+ assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f);
+
+ // When device unlock through Biometric, should not show reveal transition
+ mImageRevealHelper.updateAwake(false /* awake */, 0);
+ assertThat(mImageRevealHelper.getReveal()).isEqualTo(1f);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
index 378bba1afda3..1e8ebeafce8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
@@ -48,7 +48,7 @@ public class SysuiLogTest extends SysuiTestCase {
@Test
public void testLogDisabled_noLogsWritten() {
- mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false);
+ mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false, false);
assertEquals(mSysuiLog.mTimeline, null);
mSysuiLog.log(new Event("msg"));
@@ -57,7 +57,7 @@ public class SysuiLogTest extends SysuiTestCase {
@Test
public void testLogEnabled_logWritten() {
- mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+ mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false);
assertEquals(mSysuiLog.mTimeline.size(), 0);
mSysuiLog.log(new Event("msg"));
@@ -66,7 +66,7 @@ public class SysuiLogTest extends SysuiTestCase {
@Test
public void testMaxLogs() {
- mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+ mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false);
assertEquals(mSysuiLog.mTimeline.size(), 0);
final String msg = "msg";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 39ce8c1209ac..8a9a7a28efb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -120,7 +120,6 @@ public class TileQueryHelperTest extends SysuiTestCase {
).when(mQSTileHost).createTile(anyString());
FakeSystemClock clock = new FakeSystemClock();
- clock.setAutoIncrement(false);
mMainExecutor = new FakeExecutor(clock);
mBgExecutor = new FakeExecutor(clock);
mTileQueryHelper = new TileQueryHelper(mContext, mMainExecutor, mBgExecutor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index a754a00df940..8aac1891a5e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -30,7 +30,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyH
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.google.android.collect.Sets;
@@ -76,7 +76,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext,
mLockscreenUserManager, mSmartReplyController, mEntryManager,
- () -> mock(ShadeController.class),
+ () -> mock(StatusBar.class),
mStateController,
Handler.createAsync(Looper.myLooper()),
mRemoteInputUriController);
@@ -212,12 +212,12 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
- Lazy<ShadeController> shadeController,
+ Lazy<StatusBar> statusBarLazy,
StatusBarStateController statusBarStateController,
Handler mainHandler,
RemoteInputUriController remoteInputUriController) {
super(context, lockscreenUserManager, smartReplyController, notificationEntryManager,
- shadeController, statusBarStateController, mainHandler,
+ statusBarLazy, statusBarStateController, mainHandler,
remoteInputUriController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 95ce53c58e95..3f624128ac2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -41,7 +41,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import org.junit.Before;
@@ -88,7 +88,7 @@ public class SmartReplyControllerTest extends SysuiTestCase {
mRemoteInputManager = new NotificationRemoteInputManager(mContext,
mock(NotificationLockscreenUserManager.class), mSmartReplyController,
- mNotificationEntryManager, () -> mock(ShadeController.class),
+ mNotificationEntryManager, () -> mock(StatusBar.class),
mStatusBarStateController,
Handler.createAsync(Looper.myLooper()),
mRemoteInputUriController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 68730d12dee3..7fabb0fee8e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -100,7 +100,7 @@ public class NotificationFilterTest extends SysuiTestCase {
when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
mRow = new NotificationTestHelper(getContext(), mDependency).createRow();
- mNotificationFilter = new NotificationFilter();
+ mNotificationFilter = new NotificationFilter(mock(StatusBarStateController.class));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
index a25af84ca28e..ffaea156c9d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
@@ -690,7 +690,6 @@ public class NotifListBuilderImplTest extends SysuiTestCase {
mListBuilder.addFilter(filter3);
// GIVEN the SystemClock is set to a particular time:
- mSystemClock.setAutoIncrement(true);
mSystemClock.setUptimeMillis(47);
// WHEN the pipeline is kicked off on a list of notifs
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 61e5058b1a20..b27e84a37e3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -126,7 +126,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Test
public void showBouncer_onlyWhenShowing() {
mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
- mStatusBar.showBouncer(true /* scrimmed */);
+ mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
verify(mBouncer, never()).show(anyBoolean(), anyBoolean());
verify(mBouncer, never()).show(anyBoolean());
}
@@ -135,7 +135,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
public void showBouncer_notWhenBouncerAlreadyShowing() {
mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
when(mBouncer.isSecure()).thenReturn(true);
- mStatusBar.showBouncer(true /* scrimmed */);
+ mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
verify(mBouncer, never()).show(anyBoolean(), anyBoolean());
verify(mBouncer, never()).show(anyBoolean());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 77cdc025bbc9..d7c00cf3038d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -98,6 +98,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
+ private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock
private NotificationRemoteInputManager mRemoteInputManager;
@Mock
private RemoteInputController mRemoteInputController;
@@ -167,7 +169,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
getContext(), mock(CommandQueue.class), () -> mAssistManager,
mEntryManager, mock(HeadsUpManagerPhone.class),
mActivityStarter, mStatusBarService,
- mock(StatusBarStateController.class), mock(KeyguardManager.class),
+ mock(StatusBarStateController.class), mStatusBarKeyguardViewManager,
+ mock(KeyguardManager.class),
mock(IDreamManager.class), mRemoteInputManager,
mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class),
mock(NotificationLockscreenUserManager.class),
@@ -186,7 +189,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// set up addAfterKeyguardGoneRunnable to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
- .when(mStatusBar).addAfterKeyguardGoneRunnable(any(Runnable.class));
+ .when(mStatusBarKeyguardViewManager)
+ .addAfterKeyguardGoneRunnable(any(Runnable.class));
// set up addPostCollapseAction to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 14f5795c39f1..fb6e1684c376 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -39,6 +39,7 @@ import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -113,6 +114,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
mock(NotificationAlertingManager.class),
mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class),
+ mock(KeyguardIndicationController.class),
mStatusBar, mCommandQueue);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 9d76b425725f..6dfd0828de9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -54,6 +54,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private KeyguardStateController mKeyguardStateController;
@Mock private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private ActivityStarter mActivityStarter;
private int mCurrentUserId = 0;
@@ -71,8 +72,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
mock(NotificationGroupManager.class), mNotificationLockscreenUserManager,
- mKeyguardStateController, mStatusBarStateController, mActivityStarter,
- () -> mShadeController, new CommandQueue(mContext)));
+ mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager,
+ mActivityStarter, () -> mShadeController, new CommandQueue(mContext)));
mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 529333effa2c..00ea18749de3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -80,7 +80,7 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mView = new StatusBarWindowView(getContext(), null);
- when(mStatusBar.isDozing()).thenReturn(false);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
mDependency.injectTestDependency(ShadeController.class, mShadeController);
when(mDockManager.isDocked()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
index b1716ff47129..bd641243be12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
@@ -49,7 +49,6 @@ public class FakeExecutorTest extends SysuiTestCase {
@Test
public void testNoDelay() {
FakeSystemClock clock = new FakeSystemClock();
- clock.setAutoIncrement(false);
FakeExecutor fakeExecutor = new FakeExecutor(clock);
RunnableImpl runnable = new RunnableImpl();
@@ -99,7 +98,6 @@ public class FakeExecutorTest extends SysuiTestCase {
@Test
public void testDelayed() {
FakeSystemClock clock = new FakeSystemClock();
- clock.setAutoIncrement(false);
FakeExecutor fakeExecutor = new FakeExecutor(clock);
RunnableImpl runnable = new RunnableImpl();
@@ -134,7 +132,6 @@ public class FakeExecutorTest extends SysuiTestCase {
@Test
public void testDelayed_AdvanceAndRun() {
FakeSystemClock clock = new FakeSystemClock();
- clock.setAutoIncrement(false);
FakeExecutor fakeExecutor = new FakeExecutor(clock);
RunnableImpl runnable = new RunnableImpl();
@@ -181,7 +178,6 @@ public class FakeExecutorTest extends SysuiTestCase {
@Test
public void testExecutionOrder() {
FakeSystemClock clock = new FakeSystemClock();
- clock.setAutoIncrement(false);
FakeExecutor fakeExecutor = new FakeExecutor(clock);
RunnableImpl runnableA = new RunnableImpl();
RunnableImpl runnableB = new RunnableImpl();
@@ -251,7 +247,6 @@ public class FakeExecutorTest extends SysuiTestCase {
@Test
public void testRemoval_single() {
FakeSystemClock clock = new FakeSystemClock();
- clock.setAutoIncrement(false);
FakeExecutor fakeExecutor = new FakeExecutor(clock);
RunnableImpl runnable = new RunnableImpl();
Runnable removeFunction;
@@ -291,7 +286,6 @@ public class FakeExecutorTest extends SysuiTestCase {
@Test
public void testRemoval_multi() {
FakeSystemClock clock = new FakeSystemClock();
- clock.setAutoIncrement(false);
FakeExecutor fakeExecutor = new FakeExecutor(clock);
List<Runnable> removeFunctions = new ArrayList<>();
RunnableImpl runnable = new RunnableImpl();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
index 65e5902c84df..e94eaafdb692 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
@@ -20,8 +20,6 @@ import java.util.ArrayList;
import java.util.List;
public class FakeSystemClock implements SystemClock {
- private boolean mAutoIncrement = true;
-
private long mUptimeMillis;
private long mElapsedRealtime;
private long mElapsedRealtimeNanos;
@@ -34,54 +32,36 @@ public class FakeSystemClock implements SystemClock {
@Override
public long uptimeMillis() {
long value = mUptimeMillis;
- if (mAutoIncrement) {
- setUptimeMillis(mUptimeMillis + 1);
- }
return value;
}
@Override
public long elapsedRealtime() {
long value = mElapsedRealtime;
- if (mAutoIncrement) {
- setElapsedRealtime(mElapsedRealtime + 1);
- }
return value;
}
@Override
public long elapsedRealtimeNanos() {
long value = mElapsedRealtimeNanos;
- if (mAutoIncrement) {
- setElapsedRealtimeNanos(mElapsedRealtimeNanos + 1);
- }
return value;
}
@Override
public long currentThreadTimeMillis() {
long value = mCurrentThreadTimeMillis;
- if (mAutoIncrement) {
- setCurrentThreadTimeMillis(mCurrentThreadTimeMillis + 1);
- }
return value;
}
@Override
public long currentThreadTimeMicro() {
long value = mCurrentThreadTimeMicro;
- if (mAutoIncrement) {
- setCurrentThreadTimeMicro(mCurrentThreadTimeMicro + 1);
- }
return value;
}
@Override
public long currentTimeMicro() {
long value = mCurrentTimeMicro;
- if (mAutoIncrement) {
- setCurrentTimeMicro(mCurrentTimeMicro + 1);
- }
return value;
}
@@ -127,11 +107,6 @@ public class FakeSystemClock implements SystemClock {
}
}
- /** If true, each call to get____ will be one higher than the previous call to that method. */
- public void setAutoIncrement(boolean autoIncrement) {
- mAutoIncrement = autoIncrement;
- }
-
public void addListener(ClockTickListener listener) {
mListeners.add(listener);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java
new file mode 100644
index 000000000000..701b2fab5f85
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import static org.junit.Assert.assertEquals;
+
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.metrics.LogMaker;
+import android.provider.Settings;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Queue;
+
+/**
+ * Parameterized unit test for Events.logEvent.
+ *
+ * This test captures a translation table between the Event class tags, the debugging logs,
+ * the event-buffer logs, and the statsd logs.
+ *
+ * This test works as a straight JUnit4 test, but is declared as a SysuiTestCase because
+ * AAAPlusPlusVerifySysuiRequiredTestPropertiesTest requires all tests in SystemUiTest extend
+ * either SysuiTestCase or SysUiBaseFragmentTest.
+ *
+ */
+@RunWith(Parameterized.class)
+@SmallTest
+public class EventsTest extends SysuiTestCase {
+ private FakeMetricsLogger mLegacyLogger;
+ private UiEventLoggerFake mUiEventLogger;
+
+ @Before
+ public void setFakeLoggers() {
+ mLegacyLogger = new FakeMetricsLogger();
+ Events.sLegacyLogger = mLegacyLogger;
+ mUiEventLogger = new UiEventLoggerFake();
+ Events.sUiEventLogger = mUiEventLogger;
+ }
+
+ // Parameters for calling writeEvent with arbitrary args.
+ @Parameterized.Parameter
+ public int mTag;
+
+ @Parameterized.Parameter(1)
+ public Object[] mArgs;
+
+ // Expect returned string exactly matches.
+ @Parameterized.Parameter(2)
+ public String mExpectedMessage;
+
+ // Expect these MetricsLogger calls.
+
+ @Parameterized.Parameter(3)
+ public int[] mExpectedMetrics;
+
+ // Expect this UiEvent (use null if there isn't one).
+ @Parameterized.Parameter(4)
+ public UiEventLogger.UiEventEnum mUiEvent;
+
+ @Test
+ public void testLogEvent() {
+ String result = Events.logEvent(mTag, mArgs);
+ assertEquals("Show Dialog", mExpectedMessage, result);
+
+ Queue<LogMaker> logs = mLegacyLogger.getLogs();
+ if (mExpectedMetrics == null) {
+ assertEquals(0, logs.size());
+ } else {
+ assertEquals(mExpectedMetrics.length, logs.size());
+ if (mExpectedMetrics.length > 0) {
+ assertEquals(mExpectedMetrics[0], logs.remove().getCategory());
+ }
+ if (mExpectedMetrics.length > 1) {
+ assertEquals(mExpectedMetrics[1], logs.remove().getCategory());
+ }
+ }
+ Queue<UiEventLoggerFake.FakeUiEvent> events = mUiEventLogger.getLogs();
+ if (mUiEvent != null) {
+ assertEquals(mUiEvent.getId(), events.remove().eventId);
+ }
+ }
+
+ @Parameterized.Parameters(name = "{index}: {2}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][]{
+ {Events.EVENT_SETTINGS_CLICK, null,
+ "writeEvent settings_click",
+ new int[]{MetricsEvent.ACTION_VOLUME_SETTINGS},
+ Events.VolumeDialogEvent.VOLUME_DIALOG_SETTINGS_CLICK},
+ {Events.EVENT_SHOW_DIALOG, new Object[]{Events.SHOW_REASON_VOLUME_CHANGED, false},
+ "writeEvent show_dialog volume_changed keyguard=false",
+ new int[]{MetricsEvent.VOLUME_DIALOG,
+ MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM},
+ Events.VolumeDialogOpenEvent.VOLUME_DIALOG_SHOW_VOLUME_CHANGED},
+ {Events.EVENT_EXPAND, new Object[]{true},
+ "writeEvent expand true",
+ new int[]{MetricsEvent.VOLUME_DIALOG_DETAILS},
+ Events.VolumeDialogEvent.VOLUME_DIALOG_EXPAND_DETAILS},
+ {Events.EVENT_DISMISS_DIALOG,
+ new Object[]{Events.DISMISS_REASON_TOUCH_OUTSIDE, true},
+ "writeEvent dismiss_dialog touch_outside",
+ new int[]{MetricsEvent.VOLUME_DIALOG},
+ Events.VolumeDialogCloseEvent.VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE},
+ {Events.EVENT_ACTIVE_STREAM_CHANGED, new Object[]{AudioSystem.STREAM_ACCESSIBILITY},
+ "writeEvent active_stream_changed STREAM_ACCESSIBILITY",
+ new int[]{MetricsEvent.ACTION_VOLUME_STREAM},
+ Events.VolumeDialogEvent.VOLUME_DIALOG_ACTIVE_STREAM_CHANGED},
+ {Events.EVENT_ICON_CLICK,
+ new Object[]{AudioSystem.STREAM_MUSIC, Events.ICON_STATE_MUTE},
+ "writeEvent icon_click STREAM_MUSIC mute",
+ new int[]{MetricsEvent.ACTION_VOLUME_ICON},
+ Events.VolumeDialogEvent.VOLUME_DIALOG_MUTE_STREAM},
+ {Events.EVENT_TOUCH_LEVEL_DONE,
+ new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0},
+ "writeEvent touch_level_done STREAM_MUSIC 0",
+ new int[]{MetricsEvent.ACTION_VOLUME_SLIDER},
+ Events.VolumeDialogEvent.VOLUME_DIALOG_SLIDER_TO_ZERO},
+ {Events.EVENT_TOUCH_LEVEL_DONE,
+ new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 1},
+ "writeEvent touch_level_done STREAM_MUSIC 1",
+ new int[]{MetricsEvent.ACTION_VOLUME_SLIDER},
+ Events.VolumeDialogEvent.VOLUME_DIALOG_SLIDER},
+ {Events.EVENT_TOUCH_LEVEL_CHANGED,
+ new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0},
+ "writeEvent touch_level_changed STREAM_MUSIC 0",
+ null, null},
+ {Events.EVENT_LEVEL_CHANGED,
+ new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0},
+ "writeEvent level_changed STREAM_MUSIC 0",
+ null, null},
+ {Events.EVENT_MUTE_CHANGED,
+ new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0},
+ "writeEvent mute_changed STREAM_MUSIC 0",
+ null, null},
+ {Events.EVENT_KEY,
+ new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0},
+ "writeEvent key STREAM_MUSIC 0",
+ new int[]{MetricsEvent.ACTION_VOLUME_KEY},
+ Events.VolumeDialogEvent.VOLUME_KEY_TO_ZERO},
+ {Events.EVENT_KEY,
+ new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 1},
+ "writeEvent key STREAM_MUSIC 1",
+ new int[]{MetricsEvent.ACTION_VOLUME_KEY},
+ Events.VolumeDialogEvent.VOLUME_KEY},
+ {Events.EVENT_RINGER_TOGGLE, new Object[]{AudioManager.RINGER_MODE_NORMAL},
+ "writeEvent ringer_toggle normal",
+ new int[]{MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE},
+ Events.VolumeDialogEvent.RINGER_MODE_NORMAL},
+ {Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED,
+ new Object[]{AudioManager.RINGER_MODE_NORMAL},
+ "writeEvent external_ringer_mode_changed normal",
+ new int[]{MetricsEvent.ACTION_RINGER_MODE},
+ null},
+ {Events.EVENT_INTERNAL_RINGER_MODE_CHANGED,
+ new Object[]{AudioManager.RINGER_MODE_NORMAL},
+ "writeEvent internal_ringer_mode_changed normal",
+ null, null},
+ {Events.EVENT_ZEN_MODE_CHANGED,
+ new Object[]{Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS},
+ "writeEvent zen_mode_changed important_interruptions",
+ null, Events.ZenModeEvent.ZEN_MODE_IMPORTANT_ONLY},
+ {Events.EVENT_ZEN_MODE_CHANGED,
+ new Object[]{Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS},
+ "writeEvent zen_mode_changed important_interruptions",
+ null, Events.ZenModeEvent.ZEN_MODE_IMPORTANT_ONLY},
+ {Events.EVENT_SUPPRESSOR_CHANGED,
+ new Object[]{"component", "name"},
+ "writeEvent suppressor_changed component name",
+ null, null},
+ {Events.EVENT_SHOW_USB_OVERHEAT_ALARM,
+ new Object[]{Events.SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED, true},
+ "writeEvent show_usb_overheat_alarm usb_temperature_above_threshold "
+ + "keyguard=true",
+ new int[]{MetricsEvent.POWER_OVERHEAT_ALARM,
+ MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM},
+ Events.VolumeDialogEvent.USB_OVERHEAT_ALARM},
+ {Events.EVENT_DISMISS_USB_OVERHEAT_ALARM,
+ new Object[]{Events.DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED, true},
+ "writeEvent dismiss_usb_overheat_alarm usb_temperature_below_threshold "
+ + "keyguard=true",
+ new int[]{MetricsEvent.POWER_OVERHEAT_ALARM,
+ MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM},
+ Events.VolumeDialogEvent.USB_OVERHEAT_ALARM_DISMISSED},
+ });
+ }
+}
+
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 7e8721d3cc70..3c953b348ed9 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -31,6 +31,7 @@ java_defaults {
"android.hardware.tetheroffload.control-V1.0-java",
"tethering-client",
],
+ libs: ["unsupportedappusage"],
manifest: "AndroidManifestBase.xml",
}
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
index 3fb62f3405a3..078302ac51a4 100644
--- a/packages/Tethering/apex/manifest.json
+++ b/packages/Tethering/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.tethering.apex",
- "version": 290000000
+ "version": 300000000
}
diff --git a/services/Android.bp b/services/Android.bp
index 3b566078bd51..fd4094f2a7c2 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -14,6 +14,7 @@ filegroup {
":services.appwidget-sources",
":services.autofill-sources",
":services.backup-sources",
+ ":backuplib-sources",
":services.companion-sources",
":services.contentcapture-sources",
":services.contentsuggestions-sources",
@@ -101,3 +102,29 @@ filegroup {
name: "art-profile",
srcs: ["art-profile"],
}
+
+// API stub
+// =============================================================
+
+droidstubs {
+ name: "services-stubs.sources",
+ srcs: [":services-sources"],
+ installable: false,
+ // TODO: remove the --hide options below
+ args: " --show-single-annotation android.annotation.SystemApi" +
+ " --hide-annotation android.annotation.Hide" +
+ " --hide-package com.google.android.startop.iorap" +
+ " --hide ReferencesHidden" +
+ " --hide DeprecationMismatch" +
+ " --hide HiddenTypedefConstant",
+ libs: [
+ "framework-all",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+java_library {
+ name: "services-stubs",
+ srcs: [":services-stubs.sources"],
+ installable: false,
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7fdd83bebbcd..6a6e2b2f3467 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -16,6 +16,11 @@
package com.android.server.accessibility;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
+import static android.view.accessibility.AccessibilityManager.ShortcutType;
+
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -31,6 +36,7 @@ import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManagerInternal;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -70,6 +76,7 @@ import android.provider.Settings;
import android.provider.SettingsStringUtil.SettingStringHelper;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -113,9 +120,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* This class is instantiated by the system as a system level service and can be
@@ -754,6 +761,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
userState.setDisplayMagnificationEnabledLocked(false);
userState.setNavBarMagnificationEnabledLocked(false);
+ userState.disableShortcutMagnificationLocked();
+
userState.setAutoclickEnabledLocked(false);
userState.mEnabledServices.clear();
userState.mEnabledServices.add(service);
@@ -1072,6 +1081,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ // TODO(a11y shortcut): Remove this function and Use #performAccessibilityShortcutInternal(
+ // ACCESSIBILITY_BUTTON) instead, after the new Settings shortcut Ui merged.
private void notifyAccessibilityButtonClickedLocked(int displayId) {
final AccessibilityUserState state = getCurrentUserStateLocked();
@@ -1105,8 +1116,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (state.getServiceAssignedToAccessibilityButtonLocked() == null
&& !state.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) {
mMainHandler.sendMessage(obtainMessage(
- AccessibilityManagerService::showAccessibilityButtonTargetSelection, this,
- displayId));
+ AccessibilityManagerService::showAccessibilityTargetsSelection, this,
+ displayId, ACCESSIBILITY_BUTTON));
} else if (state.isNavBarMagnificationEnabledLocked()
&& state.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) {
mMainHandler.sendMessage(obtainMessage(
@@ -1125,8 +1136,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
// The user may have turned off the assigned service or feature
mMainHandler.sendMessage(obtainMessage(
- AccessibilityManagerService::showAccessibilityButtonTargetSelection, this,
- displayId));
+ AccessibilityManagerService::showAccessibilityTargetsSelection, this,
+ displayId, ACCESSIBILITY_BUTTON));
}
}
@@ -1138,13 +1149,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- private void showAccessibilityButtonTargetSelection(int displayId) {
+ private void showAccessibilityTargetsSelection(int displayId,
+ @ShortcutType int shortcutType) {
Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+ bundle.putInt(AccessibilityManager.EXTRA_SHORTCUT_TYPE, shortcutType);
mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
}
+ private void launchShortcutTargetActivity(int displayId, ComponentName name) {
+ final Intent intent = new Intent();
+ final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+ intent.setComponent(name);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ try {
+ mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
+ } catch (ActivityNotFoundException ignore) {
+ // ignore the exception
+ }
+ }
+
private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) {
final AccessibilityUserState state = getCurrentUserStateLocked();
mIsAccessibilityButtonShown = available;
@@ -1353,9 +1378,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
private void readComponentNamesFromSettingLocked(String settingName, int userId,
Set<ComponentName> outComponentNames) {
- String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- settingName, userId);
- readComponentNamesFromStringLocked(settingValue, outComponentNames, false);
+ readColonDelimitedSettingToSet(settingName, userId, outComponentNames,
+ str -> ComponentName.unflattenFromString(str));
}
/**
@@ -1370,34 +1394,57 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void readComponentNamesFromStringLocked(String names,
Set<ComponentName> outComponentNames,
boolean doMerge) {
+ readColonDelimitedStringToSet(names, outComponentNames, doMerge,
+ str -> ComponentName.unflattenFromString(str));
+ }
+
+ @Override
+ public void persistComponentNamesToSettingLocked(String settingName,
+ Set<ComponentName> componentNames, int userId) {
+ persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames,
+ componentName -> componentName.flattenToShortString());
+ }
+
+ private <T> void readColonDelimitedSettingToSet(String settingName, int userId, Set<T> outSet,
+ Function<String, T> toItem) {
+ final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ settingName, userId);
+ readColonDelimitedStringToSet(settingValue, outSet, false, toItem);
+ }
+
+ private <T> void readColonDelimitedStringToSet(String names, Set<T> outSet, boolean doMerge,
+ Function<String, T> toItem) {
if (!doMerge) {
- outComponentNames.clear();
+ outSet.clear();
}
- if (names != null) {
- TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ if (!TextUtils.isEmpty(names)) {
+ final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(names);
while (splitter.hasNext()) {
- String str = splitter.next();
- if (str == null || str.length() <= 0) {
+ final String str = splitter.next();
+ if (TextUtils.isEmpty(str)) {
continue;
}
- ComponentName enabledService = ComponentName.unflattenFromString(str);
- if (enabledService != null) {
- outComponentNames.add(enabledService);
+ final T item = toItem.apply(str);
+ if (item != null) {
+ outSet.add(item);
}
}
}
}
- @Override
- public void persistComponentNamesToSettingLocked(String settingName,
- Set<ComponentName> componentNames, int userId) {
- StringBuilder builder = new StringBuilder();
- for (ComponentName componentName : componentNames) {
+ private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
+ Set<T> set, Function<T, String> toString) {
+ final StringBuilder builder = new StringBuilder();
+ for (T item : set) {
+ final String str = (item != null ? toString.apply(item) : null);
+ if (TextUtils.isEmpty(str)) {
+ continue;
+ }
if (builder.length() > 0) {
builder.append(COMPONENT_NAME_SEPARATOR);
}
- builder.append(componentName.flattenToShortString());
+ builder.append(str);
}
final long identity = Binder.clearCallingIdentity();
try {
@@ -1537,7 +1584,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (userState.isDisplayMagnificationEnabledLocked()) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
}
- if (userState.isNavBarMagnificationEnabledLocked()) {
+ if (userState.isNavBarMagnificationEnabledLocked()
+ || userState.isShortcutKeyMagnificationEnabledLocked()) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
}
if (userHasMagnificationServicesLocked(userState)) {
@@ -1647,7 +1695,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mInitialized = true;
updateLegacyCapabilitiesLocked(userState);
updateServicesLocked(userState);
- updateAccessibilityShortcutLocked(userState);
updateWindowsForAccessibilityCallbackLocked(userState);
updateFilterKeyEventsLocked(userState);
updateTouchExplorationLocked(userState);
@@ -1657,6 +1704,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
scheduleUpdateInputFilter(userState);
updateRelevantEventsLocked(userState);
scheduleUpdateClientsIfNeededLocked(userState);
+ updateAccessibilityShortcutKeyTargetsLocked(userState);
updateAccessibilityButtonTargetsLocked(userState);
}
@@ -1751,7 +1799,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
somethingChanged |= readAutoclickEnabledSettingLocked(userState);
- somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
+ somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState);
somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
return somethingChanged;
@@ -1847,57 +1895,43 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- private boolean readAccessibilityShortcutSettingLocked(AccessibilityUserState userState) {
- String componentNameToEnableString = AccessibilityShortcutController
- .getTargetServiceComponentNameString(mContext, userState.mUserId);
- if ((componentNameToEnableString == null) || componentNameToEnableString.isEmpty()) {
- if (userState.getServiceToEnableWithShortcutLocked() == null) {
- return false;
+ private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) {
+ final Set<String> targetsFromSetting = new ArraySet<>();
+ readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ userState.mUserId, targetsFromSetting, str -> str);
+ if (targetsFromSetting.isEmpty()) {
+ // Fall back to device's default a11y service.
+ final String defaultService = mContext.getString(
+ R.string.config_defaultAccessibilityService);
+ if (!TextUtils.isEmpty(defaultService)) {
+ targetsFromSetting.add(defaultService);
}
- userState.setServiceToEnableWithShortcutLocked(null);
- return true;
}
- ComponentName componentNameToEnable =
- ComponentName.unflattenFromString(componentNameToEnableString);
- if ((componentNameToEnable != null)
- && componentNameToEnable.equals(userState.getServiceToEnableWithShortcutLocked())) {
+
+ final Set<String> currentTargets =
+ userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+ if (targetsFromSetting.equals(currentTargets)) {
return false;
}
-
- userState.setServiceToEnableWithShortcutLocked(componentNameToEnable);
+ currentTargets.clear();
+ currentTargets.addAll(targetsFromSetting);
scheduleNotifyClientsOfServicesStateChangeLocked(userState);
return true;
}
private boolean readAccessibilityButtonSettingsLocked(AccessibilityUserState userState) {
- String componentId = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, userState.mUserId);
- if (TextUtils.isEmpty(componentId)) {
- if ((userState.getServiceAssignedToAccessibilityButtonLocked() == null)
- && !userState.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) {
- return false;
- }
- userState.setServiceAssignedToAccessibilityButtonLocked(null);
- userState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(false);
- return true;
- }
-
- if (componentId.equals(MagnificationController.class.getName())) {
- if (userState.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) {
- return false;
- }
- userState.setServiceAssignedToAccessibilityButtonLocked(null);
- userState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(true);
- return true;
- }
+ final Set<String> targetsFromSetting = new ArraySet<>();
+ readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+ userState.mUserId, targetsFromSetting, str -> str);
- ComponentName componentName = ComponentName.unflattenFromString(componentId);
- if (Objects.equals(componentName,
- userState.getServiceAssignedToAccessibilityButtonLocked())) {
+ final Set<String> currentTargets =
+ userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+ if (targetsFromSetting.equals(currentTargets)) {
return false;
}
- userState.setServiceAssignedToAccessibilityButtonLocked(componentName);
- userState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(false);
+ currentTargets.clear();
+ currentTargets.addAll(targetsFromSetting);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
return true;
}
@@ -1921,34 +1955,33 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
/**
- * Check if the service that will be enabled by the shortcut is installed. If it isn't,
- * clear the value and the associated setting so a sideloaded service can't spoof the
- * package name of the default service.
- *
- * @param userState
+ * Check if the targets that will be enabled by the accessibility shortcut key is installed.
+ * If it isn't, remove it from the list and associated setting so a side loaded service can't
+ * spoof the package name of the default service.
*/
- private void updateAccessibilityShortcutLocked(AccessibilityUserState userState) {
- if (userState.getServiceToEnableWithShortcutLocked() == null) {
+ private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) {
+ final Set<String> currentTargets =
+ userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+ final int lastSize = currentTargets.size();
+ if (lastSize == 0) {
return;
}
- boolean shortcutServiceIsInstalled =
- AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
- .containsKey(userState.getServiceToEnableWithShortcutLocked());
- for (int i = 0; !shortcutServiceIsInstalled && (i < userState.mInstalledServices.size());
- i++) {
- if (userState.mInstalledServices.get(i).getComponentName()
- .equals(userState.getServiceToEnableWithShortcutLocked())) {
- shortcutServiceIsInstalled = true;
- }
+ currentTargets.removeIf(
+ name -> !userState.isShortcutTargetInstalledLocked(name));
+ if (lastSize == currentTargets.size()) {
+ return;
}
- if (!shortcutServiceIsInstalled) {
- userState.setServiceToEnableWithShortcutLocked(null);
+
+ // Update setting key with new value.
+ persistColonDelimitedSetToSettingLocked(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ userState.mUserId, currentTargets, str -> str);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+
+ // Disable accessibility shortcut key if there's no shortcut installed.
+ if (currentTargets.isEmpty()) {
final long identity = Binder.clearCallingIdentity();
try {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null,
- userState.mUserId);
-
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
} finally {
@@ -2004,7 +2037,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// displays in one display. It's not a real display and there's no input events for it.
final ArrayList<Display> displays = getValidDisplayList();
if (userState.isDisplayMagnificationEnabledLocked()
- || userState.isNavBarMagnificationEnabledLocked()) {
+ || userState.isNavBarMagnificationEnabledLocked()
+ || userState.isShortcutKeyMagnificationEnabledLocked()) {
for (int i = 0; i < displays.size(); i++) {
final Display display = displays.get(i);
getMagnificationController().register(display.getDisplayId());
@@ -2088,7 +2122,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ /**
+ * 1) Update accessibility button availability to accessibility services.
+ * 2) Check if the targets that will be enabled by the accessibility button is installed.
+ * If it isn't, remove it from the list and associated setting so a side loaded service can't
+ * spoof the package name of the default service.
+ */
private void updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
+ // Update accessibility button availability.
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.mRequestAccessibilityButton) {
@@ -2096,6 +2137,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
service.isAccessibilityButtonAvailableLocked(userState));
}
}
+
+ final Set<String> currentTargets =
+ userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+ final int lastSize = currentTargets.size();
+ if (lastSize == 0) {
+ return;
+ }
+ currentTargets.removeIf(
+ name -> !userState.isShortcutTargetInstalledLocked(name));
+ if (lastSize == currentTargets.size()) {
+ return;
+ }
+
+ // Update setting key with new value.
+ persistColonDelimitedSetToSettingLocked(
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+ userState.mUserId, currentTargets, str -> str);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
}
private void updateRecommendedUiTimeoutLocked(AccessibilityUserState userState) {
@@ -2156,7 +2215,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
/**
- * AIDL-exposed method to be called when the accessibility shortcut is enabled. Requires
+ * AIDL-exposed method to be called when the accessibility shortcut key is enabled. Requires
* permission to write secure settings, since someone with that permission can enable
* accessibility services themselves.
*/
@@ -2168,52 +2227,177 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
throw new SecurityException(
"performAccessibilityShortcut requires the MANAGE_ACCESSIBILITY permission");
}
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::performAccessibilityShortcutInternal, this,
+ Display.DEFAULT_DISPLAY, ACCESSIBILITY_SHORTCUT_KEY));
+ }
+
+ /**
+ * Perform the accessibility shortcut action.
+ *
+ * @param shortcutType The shortcut type.
+ * @param displayId The display id of the accessibility button.
+ */
+ private void performAccessibilityShortcutInternal(int displayId,
+ @ShortcutType int shortcutType) {
+ final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType);
+ if (shortcutTargets.isEmpty()) {
+ Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType);
+ return;
+ }
+ // In case there are many targets assigned to the given shortcut.
+ if (shortcutTargets.size() > 1) {
+ showAccessibilityTargetsSelection(displayId, shortcutType);
+ return;
+ }
+ final String targetName = shortcutTargets.get(0);
+ // In case user assigned magnification to the given shortcut.
+ if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) {
+ sendAccessibilityButtonToInputFilter(displayId);
+ return;
+ }
+ final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
+ if (targetComponentName == null) {
+ Slog.d(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
+ return;
+ }
+ // In case user assigned an accessibility framework feature to the given shortcut.
+ if (performAccessibilityFrameworkFeature(targetComponentName)) {
+ return;
+ }
+ // In case user assigned an accessibility shortcut target to the given shortcut.
+ if (performAccessibilityShortcutTargetActivity(displayId, targetComponentName)) {
+ return;
+ }
+ // in case user assigned an accessibility service to the given shortcut.
+ if (performAccessibilityShortcutTargetService(
+ displayId, shortcutType, targetComponentName)) {
+ return;
+ }
+ }
+
+ private boolean performAccessibilityFrameworkFeature(ComponentName assignedTarget) {
final Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
- synchronized(mLock) {
- final AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
- final ComponentName serviceName = userState.getServiceToEnableWithShortcutLocked();
- if (serviceName == null) {
- return;
- }
- if (frameworkFeatureMap.containsKey(serviceName)) {
- // Toggle the requested framework feature
- ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(serviceName);
- SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(),
- featureInfo.getSettingKey(), mCurrentUserId);
- // Assuming that the default state will be to have the feature off
- if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) {
- setting.write(featureInfo.getSettingOnValue());
- } else {
- setting.write(featureInfo.getSettingOffValue());
+ if (!frameworkFeatureMap.containsKey(assignedTarget)) {
+ return false;
+ }
+ // Toggle the requested framework feature
+ final ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(assignedTarget);
+ final SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(),
+ featureInfo.getSettingKey(), mCurrentUserId);
+ // Assuming that the default state will be to have the feature off
+ if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) {
+ setting.write(featureInfo.getSettingOnValue());
+ } else {
+ setting.write(featureInfo.getSettingOffValue());
+ }
+ return true;
+ }
+
+ private boolean performAccessibilityShortcutTargetActivity(int displayId,
+ ComponentName assignedTarget) {
+ synchronized (mLock) {
+ final AccessibilityUserState userState = getCurrentUserStateLocked();
+ for (int i = 0; i < userState.mInstalledShortcuts.size(); i++) {
+ final AccessibilityShortcutInfo shortcutInfo = userState.mInstalledShortcuts.get(i);
+ if (!shortcutInfo.getComponentName().equals(assignedTarget)) {
+ continue;
}
+ launchShortcutTargetActivity(displayId, assignedTarget);
+ return true;
}
- final long identity = Binder.clearCallingIdentity();
- try {
- if (userState.mComponentNameToServiceMap.get(serviceName) == null) {
- enableAccessibilityServiceLocked(serviceName, mCurrentUserId);
+ }
+ return false;
+ }
+
+ /**
+ * Perform accessibility service shortcut action.
+ *
+ * 1) For {@link AccessibilityManager#ACCESSIBILITY_BUTTON} type and services targeting sdk
+ * version <= Q: callbacks to accessibility service if service is bounded and requests
+ * accessibility button.
+ * 2) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk
+ * version <= Q: turns on / off the accessibility service.
+ * 3) For services targeting sdk version > Q:
+ * a) Turns on / off the accessibility service, if service does not request accessibility
+ * button.
+ * b) Callbacks to accessibility service if service is bounded and requests accessibility
+ * button.
+ */
+ private boolean performAccessibilityShortcutTargetService(int displayId,
+ @ShortcutType int shortcutType, ComponentName assignedTarget) {
+ synchronized (mLock) {
+ final AccessibilityUserState userState = getCurrentUserStateLocked();
+ final AccessibilityServiceInfo installedServiceInfo =
+ userState.getInstalledServiceInfoLocked(assignedTarget);
+ if (installedServiceInfo == null) {
+ Slog.d(LOG_TAG, "Perform shortcut failed, invalid component name:"
+ + assignedTarget);
+ return false;
+ }
+
+ final AccessibilityServiceConnection serviceConnection =
+ userState.getServiceConnectionLocked(assignedTarget);
+ final int targetSdk = installedServiceInfo.getResolveInfo()
+ .serviceInfo.applicationInfo.targetSdkVersion;
+ final boolean requestA11yButton = (installedServiceInfo.flags
+ & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+ // Turns on / off the accessibility service
+ if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
+ || (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) {
+ if (serviceConnection == null) {
+ enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
} else {
- disableAccessibilityServiceLocked(serviceName, mCurrentUserId);
+ disableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
}
- } finally {
- Binder.restoreCallingIdentity(identity);
+ return true;
+ }
+ // Callbacks to a11y service if it's bounded and requests a11y button.
+ if (serviceConnection == null
+ || !userState.mBoundServices.contains(serviceConnection)
+ || !serviceConnection.mRequestAccessibilityButton) {
+ Slog.d(LOG_TAG, "Perform shortcut failed, service is not ready:"
+ + assignedTarget);
+ return false;
}
+ serviceConnection.notifyAccessibilityButtonClickedLocked(displayId);
+ return true;
}
- };
+ }
@Override
- public String getAccessibilityShortcutService() {
- if (mContext.checkCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(
"getAccessibilityShortcutService requires the MANAGE_ACCESSIBILITY permission");
}
- synchronized(mLock) {
- final AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
- if (userState.getServiceToEnableWithShortcutLocked() == null) {
- return null;
+ return getAccessibilityShortcutTargetsInternal(shortcutType);
+ }
+
+ private List<String> getAccessibilityShortcutTargetsInternal(@ShortcutType int shortcutType) {
+ synchronized (mLock) {
+ final AccessibilityUserState userState = getCurrentUserStateLocked();
+ final ArrayList<String> shortcutTargets = new ArrayList<>(
+ userState.getShortcutTargetsLocked(shortcutType));
+ if (shortcutType != ACCESSIBILITY_BUTTON) {
+ return shortcutTargets;
+ }
+ // Adds legacy a11y services requesting a11y button into the list.
+ for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+ if (!service.mRequestAccessibilityButton
+ || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo
+ .targetSdkVersion > Build.VERSION_CODES.Q) {
+ continue;
+ }
+ final String serviceName = service.getComponentName().flattenToString();
+ if (!TextUtils.isEmpty(serviceName)) {
+ shortcutTargets.add(serviceName);
+ }
}
- return userState.getServiceToEnableWithShortcutLocked().flattenToString();
+ return shortcutTargets;
}
}
@@ -2609,6 +2793,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
+ // TODO(a11y shortcut): Remove this setting key, and have a migrate function in
+ // Setting provider after new shortcut UI merged.
private final Uri mNavBarMagnificationEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
@@ -2713,7 +2899,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|| mShowImeWithHardKeyboardUri.equals(uri)) {
userState.reconcileSoftKeyboardModeWithSettingsLocked();
} else if (mAccessibilityShortcutServiceIdUri.equals(uri)) {
- if (readAccessibilityShortcutSettingLocked(userState)) {
+ if (readAccessibilityShortcutKeySettingLocked(userState)) {
onUserStateChangedLocked(userState);
}
} else if (mAccessibilityButtonComponentIdUri.equals(uri)) {
@@ -2724,8 +2910,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|| mUserInteractiveUiTimeoutUri.equals(uri)) {
readUserRecommendedUiTimeoutSettingsLocked(userState);
}
- // TODO(a11y shortcut): Monitor new setting keys, when user adds shortcut, and
- // remove from the list of enabled targets anything that's been uninstalled.
}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 6cadb6d0f31f..cbff6bdcec77 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -294,6 +294,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
}
+ // TODO(a11y shortcut): Refactoring the logic here, after the new Settings shortcut Ui merged.
public boolean isAccessibilityButtonAvailableLocked(AccessibilityUserState userState) {
// If the service does not request the accessibility button, it isn't available
if (!mRequestAccessibilityButton) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index a0b9866e24d2..a163f7434e1f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -22,6 +22,11 @@ import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_K
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
+import static android.view.accessibility.AccessibilityManager.ShortcutType;
+
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import android.accessibilityservice.AccessibilityService.SoftKeyboardShowMode;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -33,10 +38,14 @@ import android.content.Context;
import android.os.Binder;
import android.os.RemoteCallbackList;
import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
+import com.android.internal.accessibility.AccessibilityShortcutController;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -79,19 +88,18 @@ class AccessibilityUserState {
final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>();
- private final ServiceInfoChangeListener mServiceInfoChangeListener;
+ final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
- private ComponentName mServiceAssignedToAccessibilityButton;
+ final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
- private ComponentName mServiceChangingSoftKeyboardMode;
+ private final ServiceInfoChangeListener mServiceInfoChangeListener;
- private ComponentName mServiceToEnableWithShortcut;
+ private ComponentName mServiceChangingSoftKeyboardMode;
private boolean mBindInstantServiceAllowed;
private boolean mIsAutoclickEnabled;
private boolean mIsDisplayMagnificationEnabled;
private boolean mIsFilterKeyEventsEnabled;
- private boolean mIsNavBarMagnificationAssignedToAccessibilityButton;
private boolean mIsNavBarMagnificationEnabled;
private boolean mIsPerformGesturesEnabled;
private boolean mIsTextHighContrastEnabled;
@@ -141,11 +149,11 @@ class AccessibilityUserState {
// Clear state persisted in settings.
mEnabledServices.clear();
mTouchExplorationGrantedServices.clear();
+ mAccessibilityShortcutKeyTargets.clear();
+ mAccessibilityButtonTargets.clear();
mIsTouchExplorationEnabled = false;
mIsDisplayMagnificationEnabled = false;
mIsNavBarMagnificationEnabled = false;
- mServiceAssignedToAccessibilityButton = null;
- mIsNavBarMagnificationAssignedToAccessibilityButton = false;
mIsAutoclickEnabled = false;
mUserNonInteractiveUiTimeout = 0;
mUserInteractiveUiTimeout = 0;
@@ -435,6 +443,26 @@ class AccessibilityUserState {
pw.append(", installedServiceCount=").append(String.valueOf(mInstalledServices.size()));
pw.append("}");
pw.println();
+ pw.append(" shortcut key:{");
+ int size = mAccessibilityShortcutKeyTargets.size();
+ for (int i = 0; i < size; i++) {
+ final String componentId = mAccessibilityShortcutKeyTargets.valueAt(i);
+ pw.append(componentId);
+ if (i + 1 < size) {
+ pw.append(", ");
+ }
+ }
+ pw.println("}");
+ pw.append(" button:{");
+ size = mAccessibilityButtonTargets.size();
+ for (int i = 0; i < size; i++) {
+ final String componentId = mAccessibilityButtonTargets.valueAt(i);
+ pw.append(componentId);
+ if (i + 1 < size) {
+ pw.append(", ");
+ }
+ }
+ pw.println("}");
pw.append(" Bound services:{");
final int serviceCount = mBoundServices.size();
for (int j = 0; j < serviceCount; j++) {
@@ -525,20 +553,85 @@ class AccessibilityUserState {
mLastSentClientState = state;
}
- public boolean isNavBarMagnificationAssignedToAccessibilityButtonLocked() {
- return mIsNavBarMagnificationAssignedToAccessibilityButton;
+ public boolean isShortcutKeyMagnificationEnabledLocked() {
+ return mAccessibilityShortcutKeyTargets.contains(MAGNIFICATION_CONTROLLER_NAME);
}
- public void setNavBarMagnificationAssignedToAccessibilityButtonLocked(boolean assigned) {
- mIsNavBarMagnificationAssignedToAccessibilityButton = assigned;
+ /**
+ * Disable both shortcuts' magnification function.
+ */
+ public void disableShortcutMagnificationLocked() {
+ mAccessibilityShortcutKeyTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
+ mAccessibilityButtonTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
}
- public boolean isNavBarMagnificationEnabledLocked() {
- return mIsNavBarMagnificationEnabled;
+ /**
+ * Returns a set which contains the flattened component names and the system class names
+ * assigned to the given shortcut.
+ *
+ * @param shortcutType The shortcut type.
+ * @return The array set of the strings
+ */
+ public ArraySet<String> getShortcutTargetsLocked(@ShortcutType int shortcutType) {
+ if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ return mAccessibilityShortcutKeyTargets;
+ } else if (shortcutType == ACCESSIBILITY_BUTTON) {
+ return mAccessibilityButtonTargets;
+ }
+ return null;
}
- public void setNavBarMagnificationEnabledLocked(boolean enabled) {
- mIsNavBarMagnificationEnabled = enabled;
+ /**
+ * Whether or not the given shortcut target is installed in device.
+ *
+ * @param name The shortcut target name
+ * @return true if the shortcut target is installed.
+ */
+ public boolean isShortcutTargetInstalledLocked(String name) {
+ if (TextUtils.isEmpty(name)) {
+ return false;
+ }
+ if (MAGNIFICATION_CONTROLLER_NAME.equals(name)) {
+ return true;
+ }
+
+ final ComponentName componentName = ComponentName.unflattenFromString(name);
+ if (componentName == null) {
+ return false;
+ }
+ if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
+ .containsKey(componentName)) {
+ return true;
+ }
+ if (getInstalledServiceInfoLocked(componentName) != null) {
+ return true;
+ }
+ for (int i = 0; i < mInstalledShortcuts.size(); i++) {
+ if (mInstalledShortcuts.get(i).getComponentName().equals(componentName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns installed accessibility service info by the given service component name.
+ */
+ public AccessibilityServiceInfo getInstalledServiceInfoLocked(ComponentName componentName) {
+ for (int i = 0; i < mInstalledServices.size(); i++) {
+ final AccessibilityServiceInfo serviceInfo = mInstalledServices.get(i);
+ if (serviceInfo.getComponentName().equals(componentName)) {
+ return serviceInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns accessibility service connection by the given service component name.
+ */
+ public AccessibilityServiceConnection getServiceConnectionLocked(ComponentName componentName) {
+ return mComponentNameToServiceMap.get(componentName);
}
public int getNonInteractiveUiTimeoutLocked() {
@@ -557,14 +650,6 @@ class AccessibilityUserState {
mIsPerformGesturesEnabled = enabled;
}
- public ComponentName getServiceAssignedToAccessibilityButtonLocked() {
- return mServiceAssignedToAccessibilityButton;
- }
-
- public void setServiceAssignedToAccessibilityButtonLocked(ComponentName componentName) {
- mServiceAssignedToAccessibilityButton = componentName;
- }
-
public ComponentName getServiceChangingSoftKeyboardModeLocked() {
return mServiceChangingSoftKeyboardMode;
}
@@ -574,14 +659,6 @@ class AccessibilityUserState {
mServiceChangingSoftKeyboardMode = serviceChangingSoftKeyboardMode;
}
- public ComponentName getServiceToEnableWithShortcutLocked() {
- return mServiceToEnableWithShortcut;
- }
-
- public void setServiceToEnableWithShortcutLocked(ComponentName componentName) {
- mServiceToEnableWithShortcut = componentName;
- }
-
public boolean isTextHighContrastEnabledLocked() {
return mIsTextHighContrastEnabled;
}
@@ -613,4 +690,28 @@ class AccessibilityUserState {
public void setUserNonInteractiveUiTimeoutLocked(int timeout) {
mUserNonInteractiveUiTimeout = timeout;
}
+
+ // TODO(a11y shortcut): These functions aren't necessary, after the new Settings shortcut Ui
+ // is merged.
+ boolean isNavBarMagnificationEnabledLocked() {
+ return mIsNavBarMagnificationEnabled;
+ }
+
+ void setNavBarMagnificationEnabledLocked(boolean enabled) {
+ mIsNavBarMagnificationEnabled = enabled;
+ }
+
+ boolean isNavBarMagnificationAssignedToAccessibilityButtonLocked() {
+ return mAccessibilityButtonTargets.contains(MAGNIFICATION_CONTROLLER_NAME);
+ }
+
+ ComponentName getServiceAssignedToAccessibilityButtonLocked() {
+ final String targetName = mAccessibilityButtonTargets.isEmpty() ? null
+ : mAccessibilityButtonTargets.valueAt(0);
+ if (targetName == null) {
+ return null;
+ }
+ return ComponentName.unflattenFromString(targetName);
+ }
+ // TODO(a11y shortcut): End
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index be597d7b40d6..de6a080f1330 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -766,8 +766,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
backupManagerService.prepareOperationTimeout(
mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT);
startedAgentRestore = true;
- mAgent.doRestore(mBackupData, appVersionCode, mNewState,
- mEphemeralOpToken, backupManagerService.getBackupManagerBinder());
+ mAgent.doRestoreWithExcludedKeys(mBackupData, appVersionCode, mNewState,
+ mEphemeralOpToken, backupManagerService.getBackupManagerBinder(),
+ mExcludedKeys.containsKey(packageName)
+ ? new ArrayList<>(mExcludedKeys.get(packageName)) : null);
} catch (Exception e) {
Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index de6cca520e65..53f306bae8e5 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -29,6 +29,8 @@ import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.ComponentInfoFlags;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManager.ResolveInfoFlags;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.ArraySet;
@@ -326,7 +328,7 @@ public abstract class PackageManagerInternal {
* @param installed the new installed state
* @return true if the installed state changed as a result
*/
- public abstract boolean setInstalled(PackageParser.Package pkg,
+ public abstract boolean setInstalled(AndroidPackage pkg,
@UserIdInt int userId, boolean installed);
/**
@@ -405,7 +407,7 @@ public abstract class PackageManagerInternal {
* Returns whether or not the given package represents a legacy system application released
* prior to runtime permissions.
*/
- public abstract boolean isLegacySystemApp(PackageParser.Package pkg);
+ public abstract boolean isLegacySystemApp(AndroidPackage pkg);
/**
* Get all overlay packages for a user.
@@ -497,13 +499,17 @@ public abstract class PackageManagerInternal {
/**
* Returns a package object for the given package name.
*/
- public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName);
+ public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName);
+
+ // TODO(b/135203078): PackageSetting can't be referenced directly. Should move to a server side
+ // internal PM which is aware of PS.
+ public abstract @Nullable Object getPackageSetting(String packageName);
/**
* Returns a package for the given UID. If the UID is part of a shared user ID, one
* of the packages will be chosen to be returned.
*/
- public abstract @Nullable PackageParser.Package getPackage(int uid);
+ public abstract @Nullable AndroidPackage getPackage(int uid);
/**
* Returns a list without a change observer.
@@ -534,17 +540,19 @@ public abstract class PackageManagerInternal {
*/
public abstract void removePackageListObserver(@NonNull PackageListObserver observer);
+ // TODO(b/135203078): PackageSetting can't be referenced directly
/**
* Returns a package object for the disabled system package name.
*/
- public abstract @Nullable PackageParser.Package getDisabledSystemPackage(
- @NonNull String packageName);
+ public abstract @Nullable Object getDisabledSystemPackage(@NonNull String packageName);
/**
* Returns the package name for the disabled system package.
*
* This is equivalent to
- * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName}
+ * {@link #getDisabledSystemPackage(String)}
+ * .{@link com.android.server.pm.PackageSetting#pkg}
+ * .{@link AndroidPackage#getPackageName()}
*/
public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName);
@@ -579,7 +587,7 @@ public abstract class PackageManagerInternal {
* @see #canAccessInstantApps
*/
public abstract boolean filterAppAccess(
- @NonNull PackageParser.Package pkg, int callingUid, int userId);
+ @NonNull AndroidPackage pkg, int callingUid, int userId);
/**
* Returns whether or not access to the application should be filtered.
@@ -653,7 +661,8 @@ public abstract class PackageManagerInternal {
throws IOException;
/** Returns {@code true} if the specified component is enabled and matches the given flags. */
- public abstract boolean isEnabledAndMatches(@NonNull ComponentInfo info, int flags, int userId);
+ public abstract boolean isEnabledAndMatches(
+ @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId);
/** Returns {@code true} if the given user requires extra badging for icons. */
public abstract boolean userNeedsBadging(int userId);
@@ -664,14 +673,14 @@ public abstract class PackageManagerInternal {
*
* @param actionLocked action to be performed
*/
- public abstract void forEachPackage(Consumer<PackageParser.Package> actionLocked);
+ public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked);
/**
* Perform the given action for each installed package for a user.
* Note that packages lock will be held while performin the actions.
*/
public abstract void forEachInstalledPackage(
- @NonNull Consumer<PackageParser.Package> actionLocked, @UserIdInt int userId);
+ @NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId);
/** Returns the list of enabled components */
public abstract ArraySet<String> getEnabledComponents(String packageName, int userId);
@@ -806,11 +815,26 @@ public abstract class PackageManagerInternal {
* Otherwise, {@code false}.
*/
public abstract boolean isCallerInstallerOfRecord(
- @NonNull PackageParser.Package pkg, int callingUid);
+ @NonNull AndroidPackage pkg, int callingUid);
/** Returns whether or not default runtime permissions are granted for the given user */
public abstract boolean areDefaultRuntimePermissionsGranted(@UserIdInt int userId);
/** Sets the enforcement of reading external storage */
public abstract void setReadExternalStorageEnforced(boolean enforced);
+
+ /**
+ * Allows the integrity component to respond to the
+ * {@link Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION package verification
+ * broadcast} to respond to the package manager. The response must include
+ * the {@code verificationCode} which is one of
+ * {@link PackageManager#VERIFICATION_ALLOW} or
+ * {@link PackageManager#VERIFICATION_REJECT}.
+ *
+ * @param verificationId pending package identifier as passed via the
+ * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
+ * @param verificationResult either {@link PackageManager#VERIFICATION_ALLOW}
+ * or {@link PackageManager#VERIFICATION_REJECT}.
+ */
+ public abstract void setIntegrityVerificationResult(int verificationId, int verificationResult);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 753c1171aeb3..f8f685d939a7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5596,7 +5596,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
ns, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
mDnsResolver, mNMS, factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
- nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
+ nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSSID() : extraInfo;
@@ -5950,11 +5950,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- final NetworkCapabilities prevNc;
- synchronized (nai) {
- prevNc = nai.networkCapabilities;
- nai.setNetworkCapabilities(newNc);
- }
+ final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
updateUids(nai, prevNc, newNc);
@@ -5963,7 +5959,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// the change we're processing can't affect any requests, it can only affect the listens
// on this network. We might have been called by rematchNetworkAndRequests when a
// network changed foreground state.
- processListenRequests(nai, true);
+ processListenRequests(nai);
} else {
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
@@ -6271,8 +6267,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateAllVpnsCapabilities();
}
- private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
+ private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
// For consistency with previous behaviour, send onLost callbacks before onAvailable.
+ processNewlyLostListenRequests(nai);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+ processNewlySatisfiedListenRequests(nai);
+ }
+
+ private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) {
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
@@ -6281,11 +6283,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
}
}
+ }
- if (capabilitiesChanged) {
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
+ private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) {
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
@@ -6468,19 +6468,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
// before LegacyTypeTracker sends legacy broadcasts
for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
- // Second pass: process all listens.
- if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
- // TODO : most of the following is useless because the only thing that changed
- // here is whether the network is a background network. Clean this up.
+ // Finally, process listen requests and update capabilities if the background state has
+ // changed for this network. For consistency with previous behavior, send onLost callbacks
+ // before onAvailable.
+ processNewlyLostListenRequests(newNetwork);
- NetworkCapabilities newNc = mixInCapabilities(newNetwork,
+ // Maybe the network changed background states. Update its capabilities.
+ final boolean backgroundChanged = wasBackgroundNetwork != newNetwork.isBackgroundNetwork();
+ if (backgroundChanged) {
+ final NetworkCapabilities newNc = mixInCapabilities(newNetwork,
newNetwork.networkCapabilities);
- if (Objects.equals(newNetwork.networkCapabilities, newNc)) return;
-
final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities);
final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission && newNetwork.created && !newNetwork.isVPN()) {
+ if (oldPermission != newPermission) {
try {
mNMS.setNetworkPermission(newNetwork.network.netId, newPermission);
} catch (RemoteException e) {
@@ -6488,53 +6489,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- final NetworkCapabilities prevNc;
- synchronized (newNetwork) {
- prevNc = newNetwork.networkCapabilities;
- newNetwork.setNetworkCapabilities(newNc);
- }
-
- updateUids(newNetwork, prevNc, newNc);
-
- if (newNetwork.getCurrentScore() == score
- && newNc.equalRequestableCapabilities(prevNc)) {
- // If the requestable capabilities haven't changed, and the score hasn't changed,
- // then the change we're processing can't affect any requests, it can only affect
- // the listens on this network.
- processListenRequests(newNetwork, true);
- } else {
- rematchAllNetworksAndRequests();
- notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
- if (prevNc != null) {
- final boolean oldMetered = prevNc.isMetered();
- final boolean newMetered = newNc.isMetered();
- final boolean meteredChanged = oldMetered != newMetered;
-
- if (meteredChanged) {
- maybeNotifyNetworkBlocked(newNetwork, oldMetered, newMetered,
- mRestrictBackground, mRestrictBackground);
- }
-
- final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
- != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
-
- // Report changes that are interesting for network statistics tracking.
- if (meteredChanged || roamingChanged) {
- notifyIfacesChangedForNetworkStats();
- }
- }
-
- if (!newNc.hasTransport(TRANSPORT_VPN)) {
- // Tell VPNs about updated capabilities, since they may need to
- // bubble those changes through.
- updateAllVpnsCapabilities();
- }
-
- } else {
- processListenRequests(newNetwork, false);
+ newNetwork.getAndSetNetworkCapabilities(newNc);
+ notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
+
+ processNewlySatisfiedListenRequests(newNetwork);
}
/**
@@ -6719,9 +6678,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// NetworkCapabilities need to be set before sending the private DNS config to
// NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
- synchronized (networkAgent) {
- networkAgent.setNetworkCapabilities(networkAgent.networkCapabilities);
- }
+ networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
+
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties),
null);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 54dfc98e888d..6300ab878d49 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -343,11 +343,6 @@ public class LocationManagerService extends ILocationManager.Stub {
onLocationModeChangedLocked(userId);
}
});
- mSettingsStore.addOnLocationProvidersAllowedChangedListener((userId) -> {
- synchronized (mLock) {
- onProviderAllowedChangedLocked(userId);
- }
- });
mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
synchronized (mLock) {
onBackgroundThrottleIntervalChangedLocked();
@@ -474,18 +469,11 @@ public class LocationManagerService extends ILocationManager.Stub {
}
Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
- intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabled());
+ intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId));
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
for (LocationProvider p : mProviders) {
- p.onLocationModeChangedLocked(userId);
- }
- }
-
- @GuardedBy("mLock")
- private void onProviderAllowedChangedLocked(int userId) {
- for (LocationProvider p : mProviders) {
- p.onAllowedChangedLocked(userId);
+ p.onUseableChangedLocked(userId);
}
}
@@ -649,7 +637,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (GnssManagerService.isGnssSupported()) {
// Create a gps location provider manager
- LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
+ LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER);
mRealProviders.add(gnssProviderManager);
addProviderLocked(gnssProviderManager);
@@ -680,7 +668,7 @@ public class LocationManagerService extends ILocationManager.Stub {
ensureFallbackFusedProviderPresentLocked(pkgs);
// bind to network provider
- LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
+ LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER);
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
mContext,
networkProviderManager,
@@ -793,8 +781,8 @@ public class LocationManagerService extends ILocationManager.Stub {
// let providers know the current user has changed
for (LocationProvider p : mProviders) {
- p.onCurrentUserChangedLocked(oldUserId);
- p.onCurrentUserChangedLocked(mCurrentUserId);
+ p.onUseableChangedLocked(oldUserId);
+ p.onUseableChangedLocked(mCurrentUserId);
}
}
@@ -805,9 +793,6 @@ public class LocationManagerService extends ILocationManager.Stub {
private final String mName;
- // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
- private final boolean mIsManagedBySettings;
-
// remember to clear binder identity before invoking any provider operation
@GuardedBy("mLock")
@Nullable
@@ -816,8 +801,6 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private SparseArray<Boolean> mUseable; // combined state for each user id
@GuardedBy("mLock")
- private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
- @GuardedBy("mLock")
private boolean mEnabled; // state of provider
@GuardedBy("mLock")
@@ -825,27 +808,19 @@ public class LocationManagerService extends ILocationManager.Stub {
private ProviderProperties mProperties;
private LocationProvider(String name) {
- this(name, false);
- }
-
- private LocationProvider(String name, boolean isManagedBySettings) {
mName = name;
- mIsManagedBySettings = isManagedBySettings;
mProvider = null;
mUseable = new SparseArray<>(1);
- mAllowed = !mIsManagedBySettings;
mEnabled = false;
mProperties = null;
- if (mIsManagedBySettings) {
- // since we assume providers are disabled by default
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "-" + mName,
- mCurrentUserId);
- }
+ // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ "-" + mName,
+ mCurrentUserId);
}
@GuardedBy("mLock")
@@ -861,7 +836,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// it would be more correct to call this for all users, but we know this can only
// affect the current user since providers are disabled for non-current users
- onUseableChangedLocked(false, mCurrentUserId);
+ onUseableChangedLocked(mCurrentUserId);
}
public String getName() {
@@ -931,9 +906,6 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.println("useable=" + isUseableLocked(mCurrentUserId));
if (!isUseableLocked(mCurrentUserId)) {
pw.println("attached=" + (mProvider != null));
- if (mIsManagedBySettings) {
- pw.println("allowed=" + mAllowed);
- }
pw.println("enabled=" + mEnabled);
}
@@ -997,7 +969,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// it would be more correct to call this for all users, but we know this can only
// affect the current user since providers are disabled for non-current users
- onUseableChangedLocked(false, mCurrentUserId);
+ onUseableChangedLocked(mCurrentUserId);
}
}
@@ -1009,43 +981,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- public void onLocationModeChangedLocked(int userId) {
- if (!isCurrentProfileLocked(userId)) {
- return;
- }
-
- onUseableChangedLocked(false, userId);
- }
-
- @GuardedBy("mLock")
- public void onAllowedChangedLocked(int userId) {
- if (!isCurrentProfileLocked(userId)) {
- return;
- }
-
- if (mIsManagedBySettings) {
- boolean allowed = mSettingsStore.getLocationProvidersAllowed(
- mCurrentUserId).contains(mName);
-
- if (allowed == mAllowed) {
- return;
- }
-
- if (D) {
- Log.d(TAG, mName + " provider allowed is now " + mAllowed);
- }
-
- mAllowed = allowed;
- onUseableChangedLocked(true, userId);
- }
- }
-
- @GuardedBy("mLock")
- public void onCurrentUserChangedLocked(int userId) {
- onUseableChangedLocked(false, userId);
- }
-
- @GuardedBy("mLock")
public boolean isUseableLocked() {
return isUseableLocked(mCurrentUserId);
}
@@ -1056,38 +991,13 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- public void onUseableChangedLocked(boolean isAllowedChanged, int userId) {
+ public void onUseableChangedLocked(int userId) {
// if any property that contributes to "useability" here changes state, it MUST result
// in a direct or indrect call to onUseableChangedLocked. this allows the provider to
// guarantee that it will always eventually reach the correct state.
- boolean useableIgnoringAllowed = mProvider != null && mProviders.contains(this)
+ boolean useable = mProvider != null && mProviders.contains(this)
&& isCurrentProfileLocked(userId) && isLocationEnabledForUser(userId)
&& mEnabled;
- boolean useable = useableIgnoringAllowed && mAllowed;
-
- // update deprecated provider allowed settings for backwards compatibility
- if (mIsManagedBySettings) {
- // a "-" change derived from the allowed setting should not be overwritten, but a
- // "+" change should be corrected if necessary
- if (useableIgnoringAllowed && !isAllowedChanged) {
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "+" + mName,
- userId);
- } else if (!useableIgnoringAllowed) {
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "-" + mName,
- userId);
- }
-
- Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
- intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
- intent.putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- }
if (useable == isUseableLocked(userId)) {
return;
@@ -1098,6 +1008,21 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.d(TAG, "[u" + userId + "] " + mName + " provider useable = " + useable);
}
+ // fused and passive provider never get public updates for legacy reasons
+ if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
+ // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ (useable ? "+" : "-") + mName,
+ userId);
+
+ Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
+ intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
+ intent.putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ }
+
if (!useable) {
// If any provider has been disabled, clear all last locations for all
// providers. This is to be on the safe side in case a provider has location
@@ -1541,12 +1466,9 @@ public class LocationManagerService extends ILocationManager.Stub {
mProviders.add(provider);
- // allowed state may change while provider was inactive
- provider.onAllowedChangedLocked(mCurrentUserId);
-
// it would be more correct to call this for all users, but we know this can only
// affect the current user since providers are disabled for non-current users
- provider.onUseableChangedLocked(false, mCurrentUserId);
+ provider.onUseableChangedLocked(mCurrentUserId);
}
@GuardedBy("mLock")
@@ -1554,7 +1476,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (mProviders.remove(provider)) {
// it would be more correct to call this for all users, but we know this can only
// affect the current user since providers are disabled for non-current users
- provider.onUseableChangedLocked(false, mCurrentUserId);
+ provider.onUseableChangedLocked(mCurrentUserId);
}
}
@@ -2805,10 +2727,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private boolean isLocationEnabled() {
- return isLocationEnabledForUser(mCurrentUserId);
- }
-
@Override
public boolean isLocationEnabledForUser(int userId) {
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
@@ -3247,7 +3165,7 @@ public class LocationManagerService extends ILocationManager.Stub {
+ TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
ipw.println("Current user: " + mCurrentUserId + " " + Arrays.toString(
mCurrentUserProfiles));
- ipw.println("Location Mode: " + isLocationEnabled());
+ ipw.println("Location Mode: " + isLocationEnabledForUser(mCurrentUserId));
ipw.println("Battery Saver Location Mode: "
+ locationPowerSaveModeToString(mBatterySaverMode));
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 840b7af19890..0d496b6b427d 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,6 +58,7 @@ import android.net.NetworkStack;
import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.TetherConfigParcel;
import android.net.TetherStatsParcel;
import android.net.UidRange;
import android.net.UidRangeParcel;
@@ -1023,7 +1024,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
NetworkStack.checkNetworkStackPermission(mContext);
// an odd number of addrs will fail
try {
- mNetdService.tetherStartWithConfiguration(usingLegacyDnsProxy, dhcpRange);
+ final TetherConfigParcel config = new TetherConfigParcel();
+ config.usingLegacyDnsProxy = usingLegacyDnsProxy;
+ config.dhcpRanges = dhcpRange;
+ mNetdService.tetherStartWithConfiguration(config);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 521b39305d9d..15e6021d23cd 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -29,6 +29,7 @@ import android.net.ConnectivityModuleConnector;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -82,6 +83,12 @@ public class PackageWatchdog {
static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED =
"watchdog_explicit_health_check_enabled";
+ // TODO: make the following values configurable via DeviceConfig
+ private static final long NATIVE_CRASH_POLLING_INTERVAL_MILLIS =
+ TimeUnit.SECONDS.toMillis(30);
+ private static final long NUMBER_OF_NATIVE_CRASH_POLLS = 10;
+
+
public static final int FAILURE_REASON_UNKNOWN = 0;
public static final int FAILURE_REASON_NATIVE_CRASH = 1;
public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2;
@@ -110,6 +117,8 @@ public class PackageWatchdog {
// Whether explicit health checks are enabled or not
private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true;
+ private long mNumberOfNativeCrashPollsRemaining;
+
private static final int DB_VERSION = 1;
private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
private static final String TAG_PACKAGE = "package";
@@ -188,6 +197,7 @@ public class PackageWatchdog {
mHealthCheckController = controller;
mConnectivityModuleConnector = connectivityModuleConnector;
mSystemClock = clock;
+ mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
loadFromFile();
}
@@ -337,37 +347,68 @@ public class PackageWatchdog {
return;
}
- for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
- VersionedPackage versionedPackage = packages.get(pIndex);
- // Observer that will receive failure for versionedPackage
- PackageHealthObserver currentObserverToNotify = null;
- int currentObserverImpact = Integer.MAX_VALUE;
-
- // Find observer with least user impact
- for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
- ObserverInternal observer = mAllObservers.valueAt(oIndex);
- PackageHealthObserver registeredObserver = observer.registeredObserver;
- if (registeredObserver != null
- && observer.onPackageFailureLocked(
- versionedPackage.getPackageName())) {
- int impact = registeredObserver.onHealthCheckFailed(versionedPackage);
- if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
- && impact < currentObserverImpact) {
- currentObserverToNotify = registeredObserver;
- currentObserverImpact = impact;
+ if (failureReason == FAILURE_REASON_NATIVE_CRASH) {
+ handleFailureImmediately(packages, failureReason);
+ } else {
+ for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+ VersionedPackage versionedPackage = packages.get(pIndex);
+ // Observer that will receive failure for versionedPackage
+ PackageHealthObserver currentObserverToNotify = null;
+ int currentObserverImpact = Integer.MAX_VALUE;
+
+ // Find observer with least user impact
+ for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+ ObserverInternal observer = mAllObservers.valueAt(oIndex);
+ PackageHealthObserver registeredObserver = observer.registeredObserver;
+ if (registeredObserver != null
+ && observer.onPackageFailureLocked(
+ versionedPackage.getPackageName())) {
+ int impact = registeredObserver.onHealthCheckFailed(
+ versionedPackage, failureReason);
+ if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
+ && impact < currentObserverImpact) {
+ currentObserverToNotify = registeredObserver;
+ currentObserverImpact = impact;
+ }
}
}
- }
- // Execute action with least user impact
- if (currentObserverToNotify != null) {
- currentObserverToNotify.execute(versionedPackage, failureReason);
+ // Execute action with least user impact
+ if (currentObserverToNotify != null) {
+ currentObserverToNotify.execute(versionedPackage, failureReason);
+ }
}
}
}
});
}
+ /**
+ * For native crashes, call directly into each observer to mitigate the error without going
+ * through failure threshold logic.
+ */
+ private void handleFailureImmediately(List<VersionedPackage> packages,
+ @FailureReasons int failureReason) {
+ VersionedPackage failingPackage = packages.size() > 0 ? packages.get(0) : null;
+ PackageHealthObserver currentObserverToNotify = null;
+ int currentObserverImpact = Integer.MAX_VALUE;
+ for (ObserverInternal observer: mAllObservers.values()) {
+ PackageHealthObserver registeredObserver = observer.registeredObserver;
+ if (registeredObserver != null) {
+ int impact = registeredObserver.onHealthCheckFailed(
+ failingPackage, failureReason);
+ if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
+ && impact < currentObserverImpact) {
+ currentObserverToNotify = registeredObserver;
+ currentObserverImpact = impact;
+ }
+ }
+ }
+ if (currentObserverToNotify != null) {
+ currentObserverToNotify.execute(failingPackage, failureReason);
+ }
+ }
+
// TODO(b/120598832): Optimize write? Maybe only write a separate smaller file? Also
// avoid holding lock?
// This currently adds about 7ms extra to shutdown thread
@@ -400,6 +441,37 @@ public class PackageWatchdog {
}
}
+ /**
+ * This method should be only called on mShortTaskHandler, since it modifies
+ * {@link #mNumberOfNativeCrashPollsRemaining}.
+ */
+ private void checkAndMitigateNativeCrashes() {
+ mNumberOfNativeCrashPollsRemaining--;
+ // Check if native watchdog reported a crash
+ if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
+ // We rollback everything available when crash is unattributable
+ onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
+ // we stop polling after an attempt to execute rollback, regardless of whether the
+ // attempt succeeds or not
+ } else {
+ if (mNumberOfNativeCrashPollsRemaining > 0) {
+ mShortTaskHandler.postDelayed(() -> checkAndMitigateNativeCrashes(),
+ NATIVE_CRASH_POLLING_INTERVAL_MILLIS);
+ }
+ }
+ }
+
+ /**
+ * Since this method can eventually trigger a rollback, it should be called
+ * only once boot has completed {@code onBootCompleted} and not earlier, because the install
+ * session must be entirely completed before we try to rollback.
+ */
+ public void scheduleCheckAndMitigateNativeCrashes() {
+ Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check "
+ + "and mitigate native crashes");
+ mShortTaskHandler.post(()->checkAndMitigateNativeCrashes());
+ }
+
/** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */
@Retention(SOURCE)
@IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_NONE,
@@ -422,17 +494,28 @@ public class PackageWatchdog {
/**
* Called when health check fails for the {@code versionedPackage}.
*
+ * @param versionedPackage the package that is failing. This may be null if a native
+ * service is crashing.
+ * @param failureReason the type of failure that is occurring.
+ *
+ *
* @return any one of {@link PackageHealthObserverImpact} to express the impact
* to the user on {@link #execute}
*/
- @PackageHealthObserverImpact int onHealthCheckFailed(VersionedPackage versionedPackage);
+ @PackageHealthObserverImpact int onHealthCheckFailed(
+ @Nullable VersionedPackage versionedPackage,
+ @FailureReasons int failureReason);
/**
* Executes mitigation for {@link #onHealthCheckFailed}.
*
+ * @param versionedPackage the package that is failing. This may be null if a native
+ * service is crashing.
+ * @param failureReason the type of failure that is occurring.
* @return {@code true} if action was executed successfully, {@code false} otherwise
*/
- boolean execute(VersionedPackage versionedPackage, @FailureReasons int failureReason);
+ boolean execute(@Nullable VersionedPackage versionedPackage,
+ @FailureReasons int failureReason);
// TODO(b/120598832): Ensure uniqueness?
/**
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 822fc90cd78e..0a6473ab92d9 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
@@ -49,6 +50,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.KeyguardManager;
@@ -253,6 +255,11 @@ class StorageManagerService extends IStorageManager.Stub
public void onCleanupUser(int userHandle) {
mStorageManagerService.onCleanupUser(userHandle);
}
+
+ @Override
+ public void onStopUser(int userHandle) {
+ mStorageManagerService.onStopUser(userHandle);
+ }
}
private static final boolean DEBUG_EVENTS = false;
@@ -1075,6 +1082,15 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ private void onStopUser(int userId) {
+ Slog.i(TAG, "onStopUser " + userId);
+ try {
+ mStorageSessionController.onUserStopping(userId);
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ }
+
private boolean supportsBlockCheckpoint() throws RemoteException {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
return mVold.supportsBlockCheckpoint();
@@ -1309,6 +1325,15 @@ class StorageManagerService extends IStorageManager.Stub
Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
return;
}
+ final ActivityManagerInternal amInternal =
+ LocalServices.getService(ActivityManagerInternal.class);
+
+ if (mIsFuseEnabled && vol.mountUserId >= 0
+ && !amInternal.isUserRunning(vol.mountUserId, 0)) {
+ Slog.d(TAG, "Ignoring volume " + vol.getId() + " because user "
+ + Integer.toString(vol.mountUserId) + " is no longer running.");
+ return;
+ }
if (vol.type == VolumeInfo.TYPE_EMULATED) {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
@@ -2229,6 +2254,11 @@ class StorageManagerService extends IStorageManager.Stub
}
private void remountUidExternalStorage(int uid, int mode) {
+ if (uid == Process.SYSTEM_UID) {
+ // No need to remount uid for system because it has all access anyways
+ return;
+ }
+
try {
mVold.remountUid(uid, mode);
} catch (Exception e) {
@@ -3399,7 +3429,13 @@ class StorageManagerService extends IStorageManager.Stub
public void opChanged(int op, int uid, String packageName) throws RemoteException {
if (!ENABLE_ISOLATED_STORAGE) return;
- remountUidExternalStorage(uid, getMountMode(uid, packageName));
+ int mountMode = getMountMode(uid, packageName);
+ boolean isUidActive = LocalServices.getService(ActivityManagerInternal.class)
+ .getUidProcessState(uid) != PROCESS_STATE_NONEXISTENT;
+
+ if (isUidActive) {
+ remountUidExternalStorage(uid, mountMode);
+ }
}
};
@@ -4092,6 +4128,13 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ @Override
+ public void resetUser(int userId) {
+ // TODO(b/145931219): ideally, we only reset storage for the user in question,
+ // but for now, reset everything.
+ mHandler.obtainMessage(H_RESET).sendToTarget();
+ }
+
public boolean hasExternalStorage(int uid, String packageName) {
// No need to check for system uid. This avoids a deadlock between
// PackageManagerService and AppOpsService.
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6105c7422153..b560761aa94f 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -357,7 +357,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.getDefaultSubscriptionId());
int newDefaultPhoneId = intent.getIntExtra(
- PhoneConstants.PHONE_KEY,
+ SubscriptionManager.EXTRA_SLOT_INDEX,
SubscriptionManager.getPhoneId(newDefaultSubId));
if (DBG) {
log("onReceive:current mDefaultSubId=" + mDefaultSubId
@@ -446,9 +446,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN;
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
- mCallQuality[i] = new CallQuality();
+ mCallQuality[i] = createCallQuality();
mCallAttributes[i] = new CallAttributes(new PreciseCallState(),
- TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = new PreciseCallState();
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -541,9 +541,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN;
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
- mCallQuality[i] = new CallQuality();
+ mCallQuality[i] = createCallQuality();
mCallAttributes[i] = new CallAttributes(new PreciseCallState(),
- TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = new PreciseCallState();
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -1571,8 +1571,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
broadcastDataConnectionStateChanged(state, isDataAllowed, apn, apnType, linkProperties,
networkCapabilities, roaming, subId);
- broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn,
- linkProperties, DataFailCause.NONE);
}
public void notifyDataConnectionFailed(String apnType) {
@@ -1612,9 +1610,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
handleRemoveListLocked();
}
broadcastDataConnectionFailed(apnType, subId);
- broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, null, null,
- DataFailCause.NONE);
}
public void notifyCellLocation(Bundle cellLocation) {
@@ -1704,7 +1699,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (mPreciseCallState[phoneId].getForegroundCallState()
!= PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- mCallQuality[phoneId] = new CallQuality();
+ mCallQuality[phoneId] = createCallQuality();
}
mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
mCallNetworkType[phoneId], mCallQuality[phoneId]);
@@ -1732,8 +1727,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
handleRemoveListLocked();
}
- broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState,
- backgroundCallState);
}
public void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
@@ -1815,8 +1808,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
handleRemoveListLocked();
}
- broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, null, failCause);
}
@Override
@@ -2146,6 +2137,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
// the legacy intent broadcasting
//
+ // Legacy intent action.
+ /** Fired when a subscription's phone state changes. */
+ private static final String ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED =
+ "android.intent.action.SUBSCRIPTION_PHONE_STATE";
+
+ // Legacy intent extra keys, copied from PhoneConstants.
+ // Used in legacy intents sent here, for backward compatibility.
+ private static final String PHONE_CONSTANTS_SLOT_KEY = "slot";
+ private static final String PHONE_CONSTANTS_SUBSCRIPTION_KEY = "subscription";
+
private void broadcastServiceStateChanged(ServiceState state, int phoneId, int subId) {
long ident = Binder.clearCallingIdentity();
try {
@@ -2162,9 +2163,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
state.fillInNotifierBundle(data);
intent.putExtras(data);
// Pass the subscription along with the intent.
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
- intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
+ intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -2183,8 +2185,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
Bundle data = new Bundle();
signalStrength.fillInNotifierBundle(data);
intent.putExtras(data);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
- intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -2219,13 +2221,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
// If a valid subId was specified, we should fire off a subId-specific state
// change intent and include the subId.
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- intent.setAction(PhoneConstants.ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.setAction(ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
}
// If the phoneId is invalid, the broadcast is for overall call state.
if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
- intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
+ intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
}
// Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast.
@@ -2285,44 +2288,17 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
private void broadcastDataConnectionFailed(String apnType, int subId) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
- int backgroundCallState) {
- Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
- intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
- intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
- intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- android.Manifest.permission.READ_PRECISE_PHONE_STATE);
- }
-
- private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
- String apnType, String apn, LinkProperties linkProperties,
- @DataFailureCause int failCause) {
- Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
- intent.putExtra(TelephonyManager.EXTRA_STATE, state);
- intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
- if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
- if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
- if (linkProperties != null) {
- intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
- }
- intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
-
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- android.Manifest.permission.READ_PRECISE_PHONE_STATE);
- }
-
private void enforceNotifyPermissionOrCarrierPrivilege(String method) {
if (checkNotifyPermission()) {
return;
@@ -2719,4 +2695,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ /** Returns a new CallQuality object with default values. */
+ private static CallQuality createCallQuality() {
+ return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index b5702541432a..5bec7a3f4a39 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -56,6 +56,7 @@ import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.ArraySet;
import android.util.Slog;
+
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.DisableCarModeActivity;
@@ -73,8 +74,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import static android.content.Intent.ACTION_SCREEN_OFF;
-
final class UiModeManagerService extends SystemService {
private static final String TAG = UiModeManager.class.getSimpleName();
private static final boolean LOG = false;
@@ -97,10 +96,15 @@ final class UiModeManagerService extends SystemService {
private boolean mCarModeEnabled = false;
private boolean mCharging = false;
private boolean mPowerSave = false;
+ // Do not change configuration now. wait until screen turns off.
+ // This prevents jank and activity restart when the user
+ // is actively using the device
+ private boolean mWaitForScreenOff = false;
private int mDefaultUiModeType;
private boolean mCarModeKeepsScreenOn;
private boolean mDeskModeKeepsScreenOn;
private boolean mTelevision;
+ private boolean mCar;
private boolean mWatch;
private boolean mVrHeadset;
private boolean mComputedNightMode;
@@ -208,24 +212,27 @@ final class UiModeManagerService extends SystemService {
public void onTwilightStateChanged(@Nullable TwilightState state) {
synchronized (mLock) {
if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- final IntentFilter intentFilter =
- new IntentFilter(ACTION_SCREEN_OFF);
- getContext().registerReceiver(mOnScreenOffHandler, intentFilter);
+ if (mCar) {
+ updateLocked(0, 0);
+ } else {
+ registerScreenOffEvent();
+ }
}
}
}
};
+ /**
+ * DO NOT USE DIRECTLY
+ * see register registerScreenOffEvent and unregisterScreenOffEvent
+ */
private final BroadcastReceiver mOnScreenOffHandler = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
+ // must unregister first before updating
+ unregisterScreenOffEvent();
updateLocked(0, 0);
- try {
- getContext().unregisterReceiver(mOnScreenOffHandler);
- } catch (IllegalArgumentException e) {
- // we ignore this exception if the receiver is unregistered already.
- }
}
}
};
@@ -327,6 +334,7 @@ final class UiModeManagerService extends SystemService {
final PackageManager pm = context.getPackageManager();
mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
|| pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ mCar = pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
updateNightModeFromSettings(context, res, UserHandle.getCallingUserId());
@@ -335,7 +343,7 @@ final class UiModeManagerService extends SystemService {
SystemServerInitThreadPool.submit(() -> {
synchronized (mLock) {
updateConfigurationLocked();
- sendConfigurationLocked();
+ applyConfigurationExternallyLocked();
}
}, TAG + ".onStart");
@@ -404,6 +412,22 @@ final class UiModeManagerService extends SystemService {
return oldNightMode != mNightMode;
}
+ private void registerScreenOffEvent() {
+ mWaitForScreenOff = true;
+ final IntentFilter intentFilter =
+ new IntentFilter(Intent.ACTION_SCREEN_OFF);
+ getContext().registerReceiver(mOnScreenOffHandler, intentFilter);
+ }
+
+ private void unregisterScreenOffEvent() {
+ mWaitForScreenOff = false;
+ try {
+ getContext().unregisterReceiver(mOnScreenOffHandler);
+ } catch (IllegalArgumentException e) {
+ // we ignore this exception if the receiver is unregistered already.
+ }
+ }
+
private final IUiModeManager.Stub mService = new IUiModeManager.Stub() {
@Override
public void enableCarMode(@UiModeManager.EnableCarMode int flags,
@@ -525,11 +549,7 @@ final class UiModeManagerService extends SystemService {
synchronized (mLock) {
if (mNightMode != mode) {
if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- try {
- getContext().unregisterReceiver(mOnScreenOffHandler);
- } catch (IllegalArgumentException e) {
- // we ignore this exception if the receiver is unregistered already.
- }
+ unregisterScreenOffEvent();
}
// Only persist setting if not in car mode
if (!mCarModeEnabled) {
@@ -541,12 +561,11 @@ final class UiModeManagerService extends SystemService {
mNightMode = mode;
mNightModeOverride = mode;
- //on screen off will update configuration instead
- if (mNightMode != UiModeManager.MODE_NIGHT_AUTO) {
+ // on screen off will update configuration instead
+ if (mNightMode != UiModeManager.MODE_NIGHT_AUTO || mCar) {
updateLocked(0, 0);
} else {
- getContext().registerReceiver(
- mOnScreenOffHandler, new IntentFilter(ACTION_SCREEN_OFF));
+ registerScreenOffEvent();
}
}
}
@@ -594,10 +613,7 @@ final class UiModeManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- try {
- getContext().unregisterReceiver(mOnScreenOffHandler);
- } catch (IllegalArgumentException e) {
- }
+ unregisterScreenOffEvent();
mNightModeOverride = active
? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO;
} else if (mNightMode == UiModeManager.MODE_NIGHT_NO
@@ -608,7 +624,7 @@ final class UiModeManagerService extends SystemService {
mNightMode = UiModeManager.MODE_NIGHT_NO;
}
updateConfigurationLocked();
- sendConfigurationLocked();
+ applyConfigurationExternallyLocked();
return true;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -863,17 +879,16 @@ final class UiModeManagerService extends SystemService {
}
mCurUiMode = uiMode;
- if (!mHoldingConfiguration) {
+ if (!mHoldingConfiguration || !mWaitForScreenOff) {
mConfiguration.uiMode = uiMode;
}
- // load splash screen instead of screenshot
- mWindowManager.clearSnapshotCache();
}
- private void sendConfigurationLocked() {
+ private void applyConfigurationExternallyLocked() {
if (mSetUiMode != mConfiguration.uiMode) {
mSetUiMode = mConfiguration.uiMode;
-
+ // load splash screen instead of screenshot
+ mWindowManager.clearSnapshotCache();
try {
ActivityTaskManager.getService().updateConfiguration(mConfiguration);
} catch (RemoteException e) {
@@ -1053,7 +1068,7 @@ final class UiModeManagerService extends SystemService {
}
// Send the new configuration.
- sendConfigurationLocked();
+ applyConfigurationExternallyLocked();
// If we did not start a dock app, then start dreaming if supported.
if (category != null && !dockAppStarted) {
@@ -1131,7 +1146,6 @@ final class UiModeManagerService extends SystemService {
final int user = UserHandle.getCallingUserId();
Secure.putIntForUser(getContext().getContentResolver(),
OVERRIDE_NIGHT_MODE, mNightModeOverride, user);
-
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b5cab1f8d62b..e101fe0e192c 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1289,6 +1289,33 @@ public class AccountManagerService
}
protected UserAccounts getUserAccounts(int userId) {
+ try {
+ return getUserAccountsNotChecked(userId);
+ } catch (RuntimeException e) {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ // Let it go...
+ throw e;
+ }
+ // User accounts database is corrupted, we must wipe out the whole user, otherwise the
+ // system will crash indefinitely
+ Slog.wtf(TAG, "Removing user " + userId + " due to exception (" + e + ") reading its "
+ + "account database");
+ if (userId == ActivityManager.getCurrentUser() && userId != UserHandle.USER_SYSTEM) {
+ Slog.i(TAG, "Switching to system user first");
+ try {
+ ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Could not switch to " + UserHandle.USER_SYSTEM + ": " + re);
+ }
+ }
+ if (!getUserManager().removeUserEvenWhenDisallowed(userId)) {
+ Slog.e(TAG, "could not remove user " + userId);
+ }
+ throw e;
+ }
+ }
+
+ private UserAccounts getUserAccountsNotChecked(int userId) {
synchronized (mUsers) {
UserAccounts accounts = mUsers.get(userId);
boolean validateAccounts = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 01f3c2666ff7..c2dd046503e2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2386,7 +2386,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mConstants = hasHandlerThread
? new ActivityManagerConstants(mContext, this, mHandler) : null;
final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
- mProcessList.init(this, activeUids);
+ mPlatformCompat = null;
+ mProcessList.init(this, activeUids, mPlatformCompat);
mLowMemDetector = null;
mOomAdjuster = hasHandlerThread
? new OomAdjuster(this, mProcessList, activeUids, handlerThread) : null;
@@ -2410,7 +2411,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mFactoryTest = FACTORY_TEST_OFF;
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mInternal = new LocalService();
- mPlatformCompat = null;
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -2439,7 +2439,9 @@ public class ActivityManagerService extends IActivityManager.Stub
mConstants = new ActivityManagerConstants(mContext, this, mHandler);
final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */);
- mProcessList.init(this, activeUids);
+ mPlatformCompat = (PlatformCompat) ServiceManager.getService(
+ Context.PLATFORM_COMPAT_SERVICE);
+ mProcessList.init(this, activeUids, mPlatformCompat);
mLowMemDetector = new LowMemDetector(this);
mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
@@ -2547,9 +2549,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mHiddenApiBlacklist = new HiddenApiSettings(mHandler, mContext);
- mPlatformCompat = (PlatformCompat) ServiceManager.getService(
- Context.PLATFORM_COMPAT_SERVICE);
-
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
@@ -5032,9 +5031,7 @@ public class ActivityManagerService extends IActivityManager.Stub
bindApplicationTimeMillis = SystemClock.elapsedRealtime();
mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
- long[] disabledCompatChanges = {};
if (mPlatformCompat != null) {
- disabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info);
mPlatformCompat.resetReporting(app.info);
}
if (app.isolatedEntryPoint != null) {
@@ -5053,7 +5050,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
- disabledCompatChanges);
+ app.mDisabledCompatChanges);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
@@ -5063,7 +5060,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
- disabledCompatChanges);
+ app.mDisabledCompatChanges);
}
if (profilerInfo != null) {
profilerInfo.closeFd();
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 7f1d5a33f56a..79fe61072a44 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2909,6 +2909,12 @@ final class ActivityManagerShellCommand extends ShellCommand {
final PlatformCompat platformCompat = (PlatformCompat)
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
String toggleValue = getNextArgRequired();
+ if (toggleValue.equals("reset-all")) {
+ final String packageName = getNextArgRequired();
+ pw.println("Reset all changes for " + packageName + " to default value.");
+ platformCompat.clearOverrides(packageName);
+ return 0;
+ }
long changeId;
String changeIdString = getNextArgRequired();
try {
@@ -3267,9 +3273,14 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" without restarting any processes.");
pw.println(" write");
pw.println(" Write all pending state to storage.");
- pw.println(" compat enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
- pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
- pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" compat [COMMAND] [...]: sub-commands for toggling app-compat changes.");
+ pw.println(" enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
+ pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
+ pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" reset-all <PACKAGE_NAME>");
+ pw.println(" Removes all existing overrides for all changes for ");
+ pw.println(" <PACKAGE_NAME> (back to default behaviour).");
+ pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
pw.println();
Intent.printIntentArgsHelp(pw, "");
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 32975d7792f5..209b1d2e7fb9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -101,6 +101,7 @@ import com.android.internal.util.MemInfoReader;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.Watchdog;
+import com.android.server.compat.PlatformCompat;
import com.android.server.pm.dex.DexManager;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.WindowManagerService;
@@ -405,6 +406,8 @@ public final class ProcessList {
final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses =
new ArrayMap<AppZygote, ArrayList<ProcessRecord>>();
+ private PlatformCompat mPlatformCompat = null;
+
final class IsolatedUidRange {
@VisibleForTesting
public final int mFirstUid;
@@ -596,9 +599,11 @@ public final class ProcessList {
updateOomLevels(0, 0, false);
}
- void init(ActivityManagerService service, ActiveUids activeUids) {
+ void init(ActivityManagerService service, ActiveUids activeUids,
+ PlatformCompat platformCompat) {
mService = service;
mActiveUids = activeUids;
+ mPlatformCompat = platformCompat;
if (sKillHandler == null) {
sKillThread = new ServiceThread(TAG + ":kill",
@@ -612,6 +617,7 @@ public final class ProcessList {
Slog.i(TAG, "Connection with lmkd established");
return onLmkdConnect(ostream);
}
+
@Override
public void onDisconnect() {
Slog.w(TAG, "Lost connection to lmkd");
@@ -619,6 +625,7 @@ public final class ProcessList {
sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage(
KillHandler.LMDK_RECONNECT_MSG), LMDK_RECONNECT_DELAY_MS);
}
+
@Override
public boolean isReplyExpected(ByteBuffer replyBuf,
ByteBuffer dataReceived, int receivedLen) {
@@ -1664,6 +1671,10 @@ public final class ProcessList {
Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
+ " with non-zero pid:" + app.pid);
}
+ app.mDisabledCompatChanges = null;
+ if (mPlatformCompat != null) {
+ app.mDisabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info);
+ }
final long startSeq = app.startSeq = ++mProcStartSeqCounter;
app.setStartParams(uid, hostingRecord, seInfo, startTime);
app.setUsingWrapper(invokeWith != null
@@ -1826,8 +1837,8 @@ public final class ProcessList {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
- app.info.dataDir, null, app.info.packageName,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges,
+ new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else if (hostingRecord.usesAppZygote()) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
@@ -1835,14 +1846,15 @@ public final class ProcessList {
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
- /*useUsapPool=*/ false, isTopApp,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ /*useUsapPool=*/ false, isTopApp, app.mDisabledCompatChanges,
+ new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, isTopApp,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ app.mDisabledCompatChanges,
+ new String[]{PROC_START_SEQ_IDENT + app.startSeq});
}
checkSlow(startTime, "startProcess: returned from zygote!");
return startResult;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 6f6f193721fa..24fc743e0a08 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -310,6 +310,8 @@ class ProcessRecord implements WindowProcessListener {
long startTime;
// This will be same as {@link #uid} usually except for some apps used during factory testing.
int startUid;
+ // set of disabled compat changes for the process (all others are enabled)
+ long[] mDisabledCompatChanges;
// Cached task info for OomAdjuster
private static final int VALUE_INVALID = -1;
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 6010b1dc88c4..8144a7118096 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -24,6 +24,7 @@ import android.bluetooth.BluetoothProfile;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.media.AudioDeviceAddress;
import android.media.AudioManager;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
@@ -400,6 +401,15 @@ import java.io.PrintWriter;
}
}
+ /*package*/ int setPreferredDeviceForStrategySync(int strategy,
+ @NonNull AudioDeviceAddress device) {
+ return mDeviceInventory.setPreferredDeviceForStrategySync(strategy, device);
+ }
+
+ /*package*/ int removePreferredDeviceForStrategySync(int strategy) {
+ return mDeviceInventory.removePreferredDeviceForStrategySync(strategy);
+ }
+
//---------------------------------------------------------------------
// Communication with (to) AudioService
//TODO check whether the AudioService methods are candidates to move here
@@ -533,6 +543,15 @@ import java.io.PrintWriter;
sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
}
+ /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device)
+ {
+ sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy, device);
+ }
+
+ /*package*/ void postSaveRemovePreferredDeviceForStrategy(int strategy) {
+ sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy);
+ }
+
//---------------------------------------------------------------------
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
// only call from a "handle"* method or "on"* method
@@ -631,6 +650,7 @@ import java.io.PrintWriter;
} else {
pw.println("Message handler is null");
}
+ mDeviceInventory.dump(pw, prefix);
}
//---------------------------------------------------------------------
@@ -890,6 +910,15 @@ import java.io.PrintWriter;
info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
}
} break;
+ case MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY: {
+ final int strategy = msg.arg1;
+ final AudioDeviceAddress device = (AudioDeviceAddress) msg.obj;
+ mDeviceInventory.onSaveSetPreferredDevice(strategy, device);
+ } break;
+ case MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY: {
+ final int strategy = msg.arg1;
+ mDeviceInventory.onSaveRemovePreferredDevice(strategy);
+ } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -941,6 +970,8 @@ import java.io.PrintWriter;
private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
// a ScoClient died in BtHelper
private static final int MSG_L_SCOCLIENT_DIED = 32;
+ private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33;
+ private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34;
private static boolean isMessageHandledUnderWakelock(int msgId) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 37add3da5a48..661451b882cc 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -23,6 +23,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
+import android.media.AudioDeviceAddress;
import android.media.AudioDevicePort;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -35,6 +36,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -42,6 +44,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -60,6 +63,9 @@ public class AudioDeviceInventory {
// Key for map created from DeviceInfo.makeDeviceListKey()
private final LinkedHashMap<String, DeviceInfo> mConnectedDevices = new LinkedHashMap<>();
+ // List of preferred devices for strategies
+ private final ArrayMap<Integer, AudioDeviceAddress> mPreferredDevices = new ArrayMap<>();
+
private @NonNull AudioDeviceBroker mDeviceBroker;
// cache of the address of the last dock the device was connected to
@@ -140,12 +146,20 @@ public class AudioDeviceInventory {
}
//------------------------------------------------------------
+ /*package*/ void dump(PrintWriter pw, String prefix) {
+ pw.println("\n" + prefix + "Preferred devices for strategy:");
+ mPreferredDevices.forEach((strategy, device) -> {
+ pw.println(" " + prefix + "strategy:" + strategy + " device:" + device); });
+ }
+
+ //------------------------------------------------------------
// Message handling from AudioDeviceBroker
/**
* Restore previously connected devices. Use in case of audio server crash
* (see AudioService.onAudioServerDied() method)
*/
+ // Always executed on AudioDeviceBroker message queue
/*package*/ void onRestoreDevices() {
synchronized (mConnectedDevices) {
for (DeviceInfo di : mConnectedDevices.values()) {
@@ -157,6 +171,11 @@ public class AudioDeviceInventory {
di.mDeviceCodecFormat);
}
}
+
+ synchronized (mPreferredDevices) {
+ mPreferredDevices.forEach((strategy, device) -> {
+ AudioSystem.setPreferredDeviceForStrategy(strategy, device); });
+ }
}
// only public for mocking/spying
@@ -431,9 +450,41 @@ public class AudioDeviceInventory {
"android"); // reconnect
}
}
+
+ /*package*/ void onSaveSetPreferredDevice(int strategy, @NonNull AudioDeviceAddress device) {
+ mPreferredDevices.put(strategy, device);
+ }
+
+ /*package*/ void onSaveRemovePreferredDevice(int strategy) {
+ mPreferredDevices.remove(strategy);
+ }
+
//------------------------------------------------------------
//
+ /*package*/ int setPreferredDeviceForStrategySync(int strategy,
+ @NonNull AudioDeviceAddress device) {
+ final long identity = Binder.clearCallingIdentity();
+ final int status = AudioSystem.setPreferredDeviceForStrategy(strategy, device);
+ Binder.restoreCallingIdentity(identity);
+
+ if (status == AudioSystem.SUCCESS) {
+ mDeviceBroker.postSaveSetPreferredDeviceForStrategy(strategy, device);
+ }
+ return status;
+ }
+
+ /*package*/ int removePreferredDeviceForStrategySync(int strategy) {
+ final long identity = Binder.clearCallingIdentity();
+ final int status = AudioSystem.removePreferredDeviceForStrategy(strategy);
+ Binder.restoreCallingIdentity(identity);
+
+ if (status == AudioSystem.SUCCESS) {
+ mDeviceBroker.postSaveRemovePreferredDeviceForStrategy(strategy);
+ }
+ return status;
+ }
+
/**
* Implements the communication with AudioSystem to (dis)connect a device in the native layers
* @param connect true if connection
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4bf1de66b408..1a62eb26580c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -63,6 +63,8 @@ import android.hardware.input.InputManager;
import android.hardware.usb.UsbManager;
import android.hidl.manager.V1_0.IServiceManager;
import android.media.AudioAttributes;
+import android.media.AudioDeviceAddress;
+import android.media.AudioDeviceInfo;
import android.media.AudioFocusInfo;
import android.media.AudioFocusRequest;
import android.media.AudioFormat;
@@ -1633,6 +1635,60 @@ public class AudioService extends IAudioService.Stub
///////////////////////////////////////////////////////////////////////////
// IPC methods
///////////////////////////////////////////////////////////////////////////
+ /** @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceInfo) */
+ public int setPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device) {
+ if (device == null) {
+ return AudioSystem.ERROR;
+ }
+ enforceModifyAudioRoutingPermission();
+ final String logString = String.format(
+ "setPreferredDeviceForStrategy u/pid:%d/%d strat:%d dev:%s",
+ Binder.getCallingUid(), Binder.getCallingPid(), strategy, device.toString());
+ sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
+ if (device.getRole() == AudioDeviceAddress.ROLE_INPUT) {
+ Log.e(TAG, "Unsupported input routing in " + logString);
+ return AudioSystem.ERROR;
+ }
+
+ final int status = mDeviceBroker.setPreferredDeviceForStrategySync(strategy, device);
+ if (status != AudioSystem.SUCCESS) {
+ Log.e(TAG, String.format("Error %d in %s)", status, logString));
+ }
+
+ return status;
+ }
+
+ /** @see AudioManager#removePreferredDeviceForStrategy(AudioProductStrategy) */
+ public int removePreferredDeviceForStrategy(int strategy) {
+ enforceModifyAudioRoutingPermission();
+ final String logString =
+ String.format("removePreferredDeviceForStrategy strat:%d", strategy);
+ sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
+
+ final int status = mDeviceBroker.removePreferredDeviceForStrategySync(strategy);
+ if (status != AudioSystem.SUCCESS) {
+ Log.e(TAG, String.format("Error %d in %s)", status, logString));
+ }
+ return status;
+ }
+
+ /** @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) */
+ public AudioDeviceAddress getPreferredDeviceForStrategy(int strategy) {
+ enforceModifyAudioRoutingPermission();
+ AudioDeviceAddress[] devices = new AudioDeviceAddress[1];
+ final long identity = Binder.clearCallingIdentity();
+ final int status = AudioSystem.getPreferredDeviceForStrategy(strategy, devices);
+ Binder.restoreCallingIdentity(identity);
+ if (status != AudioSystem.SUCCESS) {
+ Log.e(TAG, String.format("Error %d in getPreferredDeviceForStrategy(%d)",
+ status, strategy));
+ return null;
+ } else {
+ return devices[0];
+ }
+ }
+
+
/** @see AudioManager#adjustVolume(int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 9f1a6bd15ac3..36332c0ad25c 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -295,6 +295,7 @@ public class BtHelper {
&& mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
+ broadcast = false;
break;
default:
// do not broadcast CONNECTING or invalid state
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
index 27f11ffa60ce..1b1c54682255 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
@@ -31,8 +31,6 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.server.am.BatteryStatsService;
public class DataConnectionStats extends BroadcastReceiver {
@@ -44,7 +42,7 @@ public class DataConnectionStats extends BroadcastReceiver {
private final Handler mListenerHandler;
private final PhoneStateListener mPhoneStateListener;
- private IccCardConstants.State mSimState = IccCardConstants.State.READY;
+ private int mSimState = TelephonyManager.SIM_STATE_READY;
private SignalStrength mSignalStrength;
private ServiceState mServiceState;
private int mDataState = TelephonyManager.DATA_DISCONNECTED;
@@ -66,7 +64,7 @@ public class DataConnectionStats extends BroadcastReceiver {
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
IntentFilter filter = new IntentFilter();
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler);
@@ -75,7 +73,7 @@ public class DataConnectionStats extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+ if (action.equals(Intent.ACTION_SIM_STATE_CHANGED)) {
updateSimState(intent);
notePhoneDataConnectionState();
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
@@ -88,8 +86,8 @@ public class DataConnectionStats extends BroadcastReceiver {
if (mServiceState == null) {
return;
}
- boolean simReadyOrUnknown = mSimState == IccCardConstants.State.READY
- || mSimState == IccCardConstants.State.UNKNOWN;
+ boolean simReadyOrUnknown = mSimState == TelephonyManager.SIM_STATE_READY
+ || mSimState == TelephonyManager.SIM_STATE_UNKNOWN;
boolean visible = (simReadyOrUnknown || isCdma()) // we only check the sim state for GSM
&& hasService()
&& mDataState == TelephonyManager.DATA_CONNECTED;
@@ -105,23 +103,23 @@ public class DataConnectionStats extends BroadcastReceiver {
}
private final void updateSimState(Intent intent) {
- String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
- if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
- mSimState = IccCardConstants.State.ABSENT;
- } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
- mSimState = IccCardConstants.State.READY;
- } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+ String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
+ if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
+ mSimState = TelephonyManager.SIM_STATE_ABSENT;
+ } else if (Intent.SIM_STATE_READY.equals(stateExtra)) {
+ mSimState = TelephonyManager.SIM_STATE_READY;
+ } else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) {
final String lockedReason =
- intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
- if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PIN_REQUIRED;
- } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PUK_REQUIRED;
+ intent.getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
+ if (Intent.SIM_LOCKED_ON_PIN.equals(lockedReason)) {
+ mSimState = TelephonyManager.SIM_STATE_PIN_REQUIRED;
+ } else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) {
+ mSimState = TelephonyManager.SIM_STATE_PUK_REQUIRED;
} else {
- mSimState = IccCardConstants.State.NETWORK_LOCKED;
+ mSimState = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
}
} else {
- mSimState = IccCardConstants.State.UNKNOWN;
+ mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index bb7f86233a40..5e085ca293a4 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -291,13 +291,18 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
*
* <p>If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails,
* the exception is logged but not reported to callers.
+ *
+ * @return the old capabilities of this network.
*/
- public void setNetworkCapabilities(NetworkCapabilities nc) {
+ public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
+ @NonNull final NetworkCapabilities nc) {
+ final NetworkCapabilities oldNc = networkCapabilities;
networkCapabilities = nc;
final NetworkMonitorManager nm = mNetworkMonitor;
if (nm != null) {
nm.notifyNetworkCapabilitiesChanged(nc);
}
+ return oldNc;
}
public ConnectivityService connService() {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 31632dc007a5..177e2d8b5fa2 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -41,6 +41,7 @@ import android.util.MathUtils;
import android.util.Slog;
import android.util.TimeUtils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.server.EventLogTags;
@@ -215,7 +216,26 @@ class AutomaticBrightnessController {
private IActivityTaskManager mActivityTaskManager;
private PackageManager mPackageManager;
- public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
+ private final Injector mInjector;
+
+ AutomaticBrightnessController(Callbacks callbacks, Looper looper,
+ SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
+ int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
+ int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
+ long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
+ HysteresisLevels ambientBrightnessThresholds,
+ HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
+ PackageManager packageManager) {
+ this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
+ lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
+ lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
+ darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
+ ambientBrightnessThresholds, screenBrightnessThresholds, shortTermModelTimeout,
+ packageManager);
+ }
+
+ @VisibleForTesting
+ AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper,
SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
@@ -223,6 +243,7 @@ class AutomaticBrightnessController {
HysteresisLevels ambientBrightnessThresholds,
HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
PackageManager packageManager) {
+ mInjector = injector;
mCallbacks = callbacks;
mSensorManager = sensorManager;
mBrightnessMapper = mapper;
@@ -725,8 +746,8 @@ class AutomaticBrightnessController {
float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
mForegroundAppCategory);
- int newScreenAutoBrightness =
- clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
+ int newScreenAutoBrightness = Math.round(clampScreenBrightness(
+ value * PowerManager.BRIGHTNESS_ON));
// If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
// in which case we ignore the new screen brightness if it doesn't differ enough from the
@@ -750,10 +771,10 @@ class AutomaticBrightnessController {
}
mScreenAutoBrightness = newScreenAutoBrightness;
- mScreenBrighteningThreshold =
- mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness);
- mScreenDarkeningThreshold =
- mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness);
+ mScreenBrighteningThreshold = clampScreenBrightness(
+ mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
+ mScreenDarkeningThreshold = clampScreenBrightness(
+ mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
if (sendUpdate) {
mCallbacks.updateBrightness();
@@ -761,7 +782,7 @@ class AutomaticBrightnessController {
}
}
- private int clampScreenBrightness(int value) {
+ private float clampScreenBrightness(float value) {
return MathUtils.constrain(value,
mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
}
@@ -839,7 +860,7 @@ class AutomaticBrightnessController {
}
// The ActivityTaskManager's lock tends to get contended, so this is done in a background
// thread and applied via this thread's handler synchronously.
- BackgroundThread.getHandler().post(new Runnable() {
+ mInjector.getBackgroundThreadHandler().post(new Runnable() {
public void run() {
try {
// The foreground app is the top activity of the focused tasks stack.
@@ -965,6 +986,9 @@ class AutomaticBrightnessController {
private int mCount;
public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
+ if (lightSensorRate <= 0) {
+ throw new IllegalArgumentException("lightSensorRate must be above 0");
+ }
mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
mRingLux = new float[mCapacity];
mRingTime = new long[mCapacity];
@@ -1076,4 +1100,10 @@ class AutomaticBrightnessController {
return index;
}
}
+
+ public static class Injector {
+ public Handler getBackgroundThreadHandler() {
+ return BackgroundThread.getHandler();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java
index 2db1d03893d2..f0a505d4d818 100644
--- a/services/core/java/com/android/server/display/HysteresisLevels.java
+++ b/services/core/java/com/android/server/display/HysteresisLevels.java
@@ -18,13 +18,16 @@ package com.android.server.display;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.PrintWriter;
import java.util.Arrays;
/**
* A helper class for handling access to illuminance hysteresis level values.
*/
-final class HysteresisLevels {
+@VisibleForTesting
+public class HysteresisLevels {
private static final String TAG = "HysteresisLevels";
// Default hysteresis constraints for brightening or darkening.
@@ -60,7 +63,7 @@ final class HysteresisLevels {
/**
* Return the brightening hysteresis threshold for the given value level.
*/
- float getBrighteningThreshold(float value) {
+ public float getBrighteningThreshold(float value) {
float brightConstant = getReferenceLevel(value, mBrighteningThresholds);
float brightThreshold = value * (1.0f + brightConstant);
if (DEBUG) {
@@ -73,7 +76,7 @@ final class HysteresisLevels {
/**
* Return the darkening hysteresis threshold for the given value level.
*/
- float getDarkeningThreshold(float value) {
+ public float getDarkeningThreshold(float value) {
float darkConstant = getReferenceLevel(value, mDarkeningThresholds);
float darkThreshold = value * (1.0f - darkConstant);
if (DEBUG) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 1d7c942e8224..308c755a0868 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -410,6 +410,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
mInfo.address = physicalAddress;
+ mInfo.densityDpi = (int) (phys.density * 160 + 0.5f);
+ mInfo.xDpi = phys.xDpi;
+ mInfo.yDpi = phys.yDpi;
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
@@ -436,9 +439,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
mInfo.width, mInfo.height);
mInfo.type = Display.TYPE_BUILT_IN;
- mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
- mInfo.xDpi = phys.xDpi;
- mInfo.yDpi = phys.yDpi;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
} else {
mInfo.displayCutout = null;
@@ -447,7 +447,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.name = getContext().getResources().getString(
com.android.internal.R.string.display_manager_hdmi_display_name);
mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
- mInfo.setAssumedDensityForExternalDisplay(phys.width, phys.height);
// For demonstration purposes, allow rotation of the external display.
// In the future we might allow the user to configure this directly.
diff --git a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java
index d7dca90e0b8f..005fb696b089 100644
--- a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java
@@ -14,27 +14,30 @@
* limitations under the License.
*/
-package android.os.ext;
+package com.android.server.integrity;
-import android.os.Build;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.content.Context;
-import junit.framework.TestCase;
+import com.android.server.SystemService;
-public class SdkExtensionsTest extends TestCase {
+/**
+ * Service that manages app integrity rules and verifications.
+ *
+ * @hide
+ */
+public class AppIntegrityManagerService extends SystemService {
- @SmallTest
- public void testBadArgument() throws Exception {
- try {
- SdkExtensions.getExtensionVersion(Build.VERSION_CODES.Q);
- fail("expected IllegalArgumentException");
- } catch (IllegalArgumentException expected) { }
- }
+ private Context mContext;
+ private AppIntegrityManagerServiceImpl mService;
- @SmallTest
- public void testDefault() throws Exception {
- int r = SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R);
- assertTrue(r >= 0);
+ public AppIntegrityManagerService(Context context) {
+ super(context);
+ mContext = context;
}
+ @Override
+ public void onStart() {
+ mService = new AppIntegrityManagerServiceImpl(mContext);
+ // TODO: define and publish a binder service.
+ }
}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
new file mode 100644
index 000000000000..39c1b8535565
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity;
+
+import static android.content.Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION;
+import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+
+/** Implementation of {@link AppIntegrityManagerService}. */
+class AppIntegrityManagerServiceImpl {
+ private static final String TAG = "AppIntegrityManagerServiceImpl";
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final PackageManagerInternal mPackageManagerInternal;
+
+ AppIntegrityManagerServiceImpl(Context context) {
+ mContext = context;
+
+ HandlerThread handlerThread = new HandlerThread("AppIntegrityManagerServiceHandler");
+ handlerThread.start();
+ mHandler = handlerThread.getThreadHandler();
+
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+
+ IntentFilter integrityVerificationFilter = new IntentFilter();
+ integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
+
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION.equals(
+ intent.getAction())) {
+ return;
+ }
+ mHandler.post(() -> handleIntegrityVerification(intent));
+ }
+ },
+ integrityVerificationFilter,
+ /* broadcastPermission= */ null,
+ mHandler);
+ }
+
+ // protected broadcasts cannot be sent in the test.
+ @VisibleForTesting
+ void handleIntegrityVerification(Intent intent) {
+ int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1);
+ // TODO: implement this method.
+ Slog.i(TAG, "Received integrity verification intent " + intent.toString());
+ mPackageManagerInternal.setIntegrityVerificationResult(
+ verificationId, PackageManager.VERIFICATION_ALLOW);
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java
new file mode 100644
index 000000000000..4d3961df6092
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.serializer;
+
+import android.annotation.IntDef;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/** A helper class for identifying the indexing type of a given rule. */
+public class RuleIndexTypeIdentifier {
+
+ static final int NOT_INDEXED = 0;
+ static final int PACKAGE_NAME_INDEXED = 1;
+ static final int APP_CERTIFICATE_INDEXED = 2;
+
+ /** Represents which indexed file the rule should be located. */
+ @IntDef(
+ value = {
+ NOT_INDEXED,
+ PACKAGE_NAME_INDEXED,
+ APP_CERTIFICATE_INDEXED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IndexType {
+ }
+
+ /** Determines the indexing file type that a given rule should be located at. */
+ public static int getIndexType(Rule rule) {
+ if (rule == null) {
+ throw new IllegalArgumentException("Indexing type cannot be determined for null rule.");
+ }
+ return getIndexType(rule.getFormula());
+ }
+
+ private static int getIndexType(Formula formula) {
+ if (formula == null) {
+ throw new IllegalArgumentException(
+ "Indexing type cannot be determined for null formula.");
+ }
+
+ switch (formula.getTag()) {
+ case Formula.COMPOUND_FORMULA_TAG:
+ return getIndexTypeForCompoundFormula((CompoundFormula) formula);
+ case Formula.STRING_ATOMIC_FORMULA_TAG:
+ return getIndexTypeForAtomicStringFormula((AtomicFormula) formula);
+ case Formula.INT_ATOMIC_FORMULA_TAG:
+ case Formula.BOOLEAN_ATOMIC_FORMULA_TAG:
+ // Package name and app certificate related formulas are string atomic formulas.
+ return NOT_INDEXED;
+ default:
+ throw new IllegalArgumentException(
+ String.format("Invalid formula tag type: %s", formula.getTag()));
+ }
+ }
+
+ private static int getIndexTypeForCompoundFormula(CompoundFormula compoundFormula) {
+ int connector = compoundFormula.getConnector();
+ List<Formula> formulas = compoundFormula.getFormulas();
+
+ switch (connector) {
+ case CompoundFormula.NOT:
+ // Having a NOT operator in the indexing messes up the indexing; e.g., deny
+ // installation if app certificate is NOT X (should not be indexed with app cert
+ // X). We will not keep these rules indexed.
+ return NOT_INDEXED;
+ case CompoundFormula.AND:
+ case CompoundFormula.OR:
+ Set<Integer> indexingTypesForAllFormulas =
+ formulas.stream()
+ .map(formula -> getIndexType(formula))
+ .collect(Collectors.toSet());
+ if (indexingTypesForAllFormulas.contains(PACKAGE_NAME_INDEXED)) {
+ return PACKAGE_NAME_INDEXED;
+ } else if (indexingTypesForAllFormulas.contains(APP_CERTIFICATE_INDEXED)) {
+ return APP_CERTIFICATE_INDEXED;
+ } else {
+ return NOT_INDEXED;
+ }
+ default:
+ return NOT_INDEXED;
+ }
+ }
+
+ private static int getIndexTypeForAtomicStringFormula(AtomicFormula atomicFormula) {
+ switch (atomicFormula.getKey()) {
+ case AtomicFormula.PACKAGE_NAME:
+ return PACKAGE_NAME_INDEXED;
+ case AtomicFormula.APP_CERTIFICATE:
+ return APP_CERTIFICATE_INDEXED;
+ default:
+ return NOT_INDEXED;
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 557ba54b536d..f913ba337071 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -531,8 +531,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
CarrierConfigManager configManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
- String mccMnc = SubscriptionManager.isValidSubscriptionId(ddSubId)
- ? phone.getSimOperator(ddSubId) : phone.getSimOperator();
+ if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+ phone = phone.createForSubscriptionId(ddSubId);
+ }
+ String mccMnc = phone.getSimOperator();
boolean isKeepLppProfile = false;
if (!TextUtils.isEmpty(mccMnc)) {
if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
@@ -1913,24 +1915,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
String setId = null;
int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+ phone = phone.createForSubscriptionId(ddSubId);
+ }
if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
- if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
- setId = phone.getSubscriberId(ddSubId);
- }
- if (setId == null) {
- setId = phone.getSubscriberId();
- }
+ setId = phone.getSubscriberId();
if (setId != null) {
// This means the framework has the SIM card.
type = AGPS_SETID_TYPE_IMSI;
}
} else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
- if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
- setId = phone.getLine1Number(ddSubId);
- }
- if (setId == null) {
- setId = phone.getLine1Number();
- }
+ setId = phone.getLine1Number();
if (setId != null) {
// This means the framework has the SIM card.
type = AGPS_SETID_TYPE_MSISDN;
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index ea4f9c456856..dd522b95a938 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -637,7 +637,7 @@ class GnssVisibilityControl {
return new Notification.Builder(context, SystemNotificationChannels.NETWORK_ALERTS)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
.setWhen(0)
- .setOngoing(true)
+ .setOngoing(false)
.setAutoCancel(true)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color))
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index eb2a37b38f1c..3d18d4a12e44 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -23,7 +23,6 @@ import static android.provider.Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_
import static android.provider.Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS;
import static android.provider.Settings.Secure.LOCATION_MODE;
import static android.provider.Settings.Secure.LOCATION_MODE_OFF;
-import static android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
import android.app.ActivityManager;
import android.content.Context;
@@ -89,7 +88,6 @@ public class LocationSettingsStore {
private final Context mContext;
private final IntegerSecureSetting mLocationMode;
- private final StringListCachedSecureSetting mLocationProvidersAllowed;
private final LongGlobalSetting mBackgroundThrottleIntervalMs;
private final StringListCachedSecureSetting mLocationPackageBlacklist;
private final StringListCachedSecureSetting mLocationPackageWhitelist;
@@ -101,8 +99,6 @@ public class LocationSettingsStore {
mContext = context;
mLocationMode = new IntegerSecureSetting(context, LOCATION_MODE, handler);
- mLocationProvidersAllowed = new StringListCachedSecureSetting(context,
- LOCATION_PROVIDERS_ALLOWED, handler);
mBackgroundThrottleIntervalMs = new LongGlobalSetting(context,
LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, handler);
mLocationPackageBlacklist = new StringListCachedSecureSetting(context,
@@ -139,28 +135,6 @@ public class LocationSettingsStore {
}
/**
- * Retrieve the currently allowed location providers.
- */
- public List<String> getLocationProvidersAllowed(int userId) {
- return mLocationProvidersAllowed.getValueForUser(userId);
- }
-
- /**
- * Add a listener for changes to the currently allowed location providers.
- */
- public void addOnLocationProvidersAllowedChangedListener(UserSettingChangedListener listener) {
- mLocationProvidersAllowed.addListener(listener);
- }
-
- /**
- * Remove a listener for changes to the currently allowed location providers.
- */
- public void removeOnLocationProvidersAllowedChangedListener(
- UserSettingChangedListener listener) {
- mLocationProvidersAllowed.removeListener(listener);
- }
-
- /**
* Retrieve the background throttle interval.
*/
public long getBackgroundThrottleIntervalMs() {
@@ -280,9 +254,6 @@ public class LocationSettingsStore {
ipw.print("Location Enabled: ");
ipw.println(isLocationEnabled(userId));
- ipw.print("Location Providers Allowed: ");
- ipw.println(getLocationProvidersAllowed(userId));
-
List<String> locationPackageBlacklist = mLocationPackageBlacklist.getValueForUser(userId);
if (!locationPackageBlacklist.isEmpty()) {
ipw.println("Location Blacklisted Packages:");
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d0ad47d3d7a6..12afef2cf950 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -171,6 +171,7 @@ import android.os.IDeviceIdleController;
import android.os.IInterface;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -292,6 +293,9 @@ public class NotificationManagerService extends SystemService {
public static final boolean ENABLE_CHILD_NOTIFICATIONS
= SystemProperties.getBoolean("debug.child_notifs", true);
+ // pullStats report request: undecorated remote view stats
+ public static final int REPORT_REMOTE_VIEWS = 0x01;
+
static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
"debug.notification.interruptiveness", false);
@@ -4080,6 +4084,8 @@ public class NotificationManagerService extends SystemService {
try {
if (filter.stats) {
dumpJson(pw, filter);
+ } else if (filter.rvStats) {
+ dumpRemoteViewStats(pw, filter);
} else if (filter.proto) {
dumpProto(fd, filter);
} else if (filter.criticalPriority) {
@@ -4556,6 +4562,49 @@ public class NotificationManagerService extends SystemService {
new NotificationShellCmd(NotificationManagerService.this)
.exec(this, in, out, err, args, callback, resultReceiver);
}
+
+ /**
+ * Get stats committed after startNs
+ *
+ * @param startNs Report stats committed after this time in nanoseconds.
+ * @param report Indicatess which section to include in the stats.
+ * @param doAgg Whether to aggregate the stats or keep them separated.
+ * @param out List of protos of individual commits or one representing the
+ * aggregate.
+ * @return the report time in nanoseconds, or 0 on error.
+ */
+ @Override
+ public long pullStats(long startNs, int report, boolean doAgg,
+ List<ParcelFileDescriptor> out) {
+ checkCallerIsSystemOrShell();
+ long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ switch (report) {
+ case REPORT_REMOTE_VIEWS:
+ Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: "
+ + startMs + " wtih " + doAgg);
+ PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg);
+ if (stats != null) {
+ out.add(stats.toParcelFileDescriptor(report));
+ Slog.e(TAG, "exiting pullStats with: " + out.size());
+ long endNs = TimeUnit.NANOSECONDS
+ .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS);
+ return endNs;
+ }
+ Slog.e(TAG, "null stats for: " + report);
+ }
+ } catch (IOException e) {
+
+ Slog.e(TAG, "exiting pullStats: on error", e);
+ return 0;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ Slog.e(TAG, "exiting pullStats: bad request");
+ return 0;
+ }
};
@VisibleForTesting
@@ -4773,6 +4822,15 @@ public class NotificationManagerService extends SystemService {
pw.println(dump);
}
+ private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) {
+ PulledStats stats = mUsageStats.remoteViewStats(filter.since, true);
+ if (stats == null) {
+ pw.println("no remote view stats reported.");
+ return;
+ }
+ stats.dump(REPORT_REMOTE_VIEWS, pw, filter);
+ }
+
private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
synchronized (mNotificationLock) {
@@ -9084,6 +9142,7 @@ public class NotificationManagerService extends SystemService {
public boolean zen;
public long since;
public boolean stats;
+ public boolean rvStats;
public boolean redact = true;
public boolean proto = false;
public boolean criticalPriority = false;
@@ -9119,6 +9178,14 @@ public class NotificationManagerService extends SystemService {
} else {
filter.since = 0;
}
+ } else if ("--remote-view-stats".equals(a)) {
+ filter.rvStats = true;
+ if (ai < args.length-1) {
+ ai++;
+ filter.since = Long.parseLong(args[ai]);
+ } else {
+ filter.since = 0;
+ }
} else if (PRIORITY_ARG.equals(a)) {
// Bugreport will call the service twice with priority arguments, first to dump
// critical sections and then non critical ones. Set approriate filters
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index fe3d0eb3e469..ac8d1a9a9ad4 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -149,6 +149,7 @@ public class NotificationUsageStats {
stats.numPostedByApp++;
stats.updateInterarrivalEstimate(now);
stats.countApiUse(notification);
+ stats.numUndecoratedRemoteViews += (isUndecoratedRemoteView(notification) ? 1 : 0);
}
releaseAggregatedStatsLocked(aggregatedStatsArray);
if (ENABLE_SQLITE_LOG) {
@@ -157,6 +158,13 @@ public class NotificationUsageStats {
}
/**
+ * Does this notification use RemoveViews without a platform decoration?
+ */
+ protected static boolean isUndecoratedRemoteView(NotificationRecord notification) {
+ return (notification.getNotification().getNotificationStyle() == null);
+ }
+
+ /**
* Called when a notification has been updated.
*/
public synchronized void registerUpdatedByApp(NotificationRecord notification,
@@ -337,6 +345,15 @@ public class NotificationUsageStats {
return dump;
}
+ public PulledStats remoteViewStats(long startMs, boolean aggregate) {
+ if (ENABLE_SQLITE_LOG) {
+ if (aggregate) {
+ return mSQLiteLog.remoteViewAggStats(startMs);
+ }
+ }
+ return null;
+ }
+
public synchronized void dump(PrintWriter pw, String indent, DumpFilter filter) {
if (ENABLE_AGGREGATED_IN_MEMORY_STATS) {
for (AggregatedStats as : mStats.values()) {
@@ -414,6 +431,7 @@ public class NotificationUsageStats {
public int numRateViolations;
public int numAlertViolations;
public int numQuotaViolations;
+ public int numUndecoratedRemoteViews;
public long mLastAccessTime;
public int numImagesRemoved;
@@ -685,6 +703,8 @@ public class NotificationUsageStats {
output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numUndecorateRVs=").append(numUndecoratedRemoteViews).append("\n");
output.append(indent).append("}");
return output.toString();
}
@@ -1044,7 +1064,7 @@ public class NotificationUsageStats {
private static final int MSG_DISMISS = 4;
private static final String DB_NAME = "notification_log.db";
- private static final int DB_VERSION = 5;
+ private static final int DB_VERSION = 7;
/** Age in ms after which events are pruned from the DB. */
private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week
@@ -1077,6 +1097,7 @@ public class NotificationUsageStats {
private static final String COL_FIRST_EXPANSIONTIME_MS = "first_expansion_time_ms";
private static final String COL_AIRTIME_EXPANDED_MS = "expansion_airtime_ms";
private static final String COL_EXPAND_COUNT = "expansion_count";
+ private static final String COL_UNDECORATED = "undecorated";
private static final int EVENT_TYPE_POST = 1;
@@ -1102,12 +1123,20 @@ public class NotificationUsageStats {
"COUNT(*) AS cnt, " +
"SUM(" + COL_MUTED + ") as muted, " +
"SUM(" + COL_NOISY + ") as noisy, " +
- "SUM(" + COL_DEMOTED + ") as demoted " +
+ "SUM(" + COL_DEMOTED + ") as demoted, " +
+ "SUM(" + COL_UNDECORATED + ") as undecorated " +
"FROM " + TAB_LOG + " " +
"WHERE " +
COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
" AND " + COL_EVENT_TIME + " > %d " +
" GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+ private static final String UNDECORATED_QUERY = "SELECT " +
+ COL_PKG + ", " +
+ "MAX(" + COL_EVENT_TIME + ") as max_time " +
+ "FROM " + TAB_LOG + " " +
+ "WHERE " + COL_UNDECORATED + "> 0 " +
+ " AND " + COL_EVENT_TIME + " > %d " +
+ "GROUP BY " + COL_PKG;
public SQLiteLog(Context context) {
HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
@@ -1163,7 +1192,8 @@ public class NotificationUsageStats {
COL_AIRTIME_MS + " INT," +
COL_FIRST_EXPANSIONTIME_MS + " INT," +
COL_AIRTIME_EXPANDED_MS + " INT," +
- COL_EXPAND_COUNT + " INT" +
+ COL_EXPAND_COUNT + " INT," +
+ COL_UNDECORATED + " INT" +
")");
}
@@ -1273,6 +1303,7 @@ public class NotificationUsageStats {
} else {
putPosttimeVisibility(r, cv);
}
+ cv.put(COL_UNDECORATED, (isUndecoratedRemoteView(r) ? 1 : 0));
SQLiteDatabase db = mHelper.getWritableDatabase();
if (db.insert(TAB_LOG, null, cv) < 0) {
Log.wtf(TAG, "Error while trying to insert values: " + cv);
@@ -1353,5 +1384,22 @@ public class NotificationUsageStats {
}
return dump;
}
+
+ public PulledStats remoteViewAggStats(long startMs) {
+ PulledStats stats = new PulledStats(startMs);
+ SQLiteDatabase db = mHelper.getReadableDatabase();
+ String q = String.format(UNDECORATED_QUERY, startMs);
+ Cursor cursor = db.rawQuery(q, null);
+ try {
+ for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+ String pkg = cursor.getString(0);
+ long maxTimeMs = cursor.getLong(1);
+ stats.addUndecoratedPackage(pkg, maxTimeMs);
+ }
+ } finally {
+ cursor.close();
+ }
+ return stats;
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/PulledStats.java b/services/core/java/com/android/server/notification/PulledStats.java
new file mode 100644
index 000000000000..ada890a10361
--- /dev/null
+++ b/services/core/java/com/android/server/notification/PulledStats.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.notification;
+
+import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS;
+
+import android.os.ParcelFileDescriptor;
+import android.service.notification.NotificationRemoteViewsProto;
+import android.service.notification.PackageRemoteViewInfoProto;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PulledStats {
+ static final String TAG = "PulledStats";
+
+ private final long mTimePeriodStartMs;
+ private long mTimePeriodEndMs;
+ private List<String> mUndecoratedPackageNames;
+
+ public PulledStats(long startMs) {
+ mTimePeriodEndMs = mTimePeriodStartMs = startMs;
+ mUndecoratedPackageNames = new ArrayList<>();
+ }
+
+ ParcelFileDescriptor toParcelFileDescriptor(int report)
+ throws IOException {
+ final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+ switch(report) {
+ case REPORT_REMOTE_VIEWS:
+ Thread thr = new Thread("NotificationManager pulled metric output") {
+ public void run() {
+ try {
+ FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(
+ fds[1]);
+ final ProtoOutputStream proto = new ProtoOutputStream(fout);
+ writeToProto(report, proto);
+ proto.flush();
+ fout.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure writing pipe", e);
+ }
+ }
+ };
+ thr.start();
+ break;
+
+ default:
+ Slog.w(TAG, "Unknown pulled stats request: " + report);
+ break;
+ }
+ return fds[0];
+ }
+
+ /*
+ * @return the most recent timestamp in the report, as nanoseconds.
+ */
+ public long endTimeMs() {
+ return mTimePeriodEndMs;
+ }
+
+ public void dump(int report, PrintWriter pw, NotificationManagerService.DumpFilter filter) {
+ switch(report) {
+ case REPORT_REMOTE_VIEWS:
+ pw.print(" Packages with undecordated notifications (");
+ pw.print(mTimePeriodStartMs);
+ pw.print(" - ");
+ pw.print(mTimePeriodEndMs);
+ pw.println("):");
+ if (mUndecoratedPackageNames.size() == 0) {
+ pw.println(" none");
+ } else {
+ for (String pkg : mUndecoratedPackageNames) {
+ if (!filter.filtered || pkg.equals(filter.pkgFilter)) {
+ pw.println(" " + pkg);
+ }
+ }
+ }
+ break;
+
+ default:
+ pw.println("Unknown pulled stats request: " + report);
+ break;
+ }
+ }
+
+ @VisibleForTesting
+ void writeToProto(int report, ProtoOutputStream proto) {
+ switch(report) {
+ case REPORT_REMOTE_VIEWS:
+ for (String pkg: mUndecoratedPackageNames) {
+ long token = proto.start(NotificationRemoteViewsProto.PACKAGE_REMOTE_VIEW_INFO);
+ proto.write(PackageRemoteViewInfoProto.PACKAGE_NAME, pkg);
+ proto.end(token);
+ }
+ break;
+
+ default:
+ Slog.w(TAG, "Unknown pulled stats request: " + report);
+ break;
+ }
+ }
+
+ public void addUndecoratedPackage(String packageName, long timestampMs) {
+ mUndecoratedPackageNames.add(packageName);
+ mTimePeriodEndMs = Math.max(mTimePeriodEndMs, timestampMs);
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java b/services/core/java/com/android/server/package-info.java
index 10d0551a3a6f..a783e8d61a32 100644
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java
+++ b/services/core/java/com/android/server/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -12,13 +12,6 @@
* 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.frameworks.coretests;
-
-import android.app.Activity;
-
-public class TestActivity extends Activity {
-
-}
+@android.annotation.Hide
+package com.android.server;
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 14ef2d3a38e1..8374ee63e07e 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -27,7 +27,13 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
-import android.content.pm.ProviderInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.net.Uri;
import android.os.Process;
import android.os.Trace;
@@ -47,6 +53,7 @@ import com.android.server.FgThread;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -117,7 +124,7 @@ public class AppsFilter {
boolean isGloballyEnabled();
/** @return true if the feature is enabled for the given package. */
- boolean packageIsEnabled(PackageParser.Package pkg);
+ boolean packageIsEnabled(AndroidPackage pkg);
}
private static class FeatureConfigImpl implements FeatureConfig {
@@ -156,11 +163,12 @@ public class AppsFilter {
}
@Override
- public boolean packageIsEnabled(PackageParser.Package pkg) {
+ public boolean packageIsEnabled(AndroidPackage pkg) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled");
try {
+ // TODO(b/135203078): Do not use toAppInfo
return mInjector.getCompatibility().isChangeEnabled(
- PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
+ PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -189,12 +197,12 @@ public class AppsFilter {
}
/** Returns true if the querying package may query for the potential target package */
- private static boolean canQueryViaIntent(PackageParser.Package querying,
- PackageParser.Package potentialTarget) {
- if (querying.mQueriesIntents == null) {
+ private static boolean canQueryViaIntent(AndroidPackage querying,
+ AndroidPackage potentialTarget) {
+ if (querying.getQueriesIntents() == null) {
return false;
}
- for (Intent intent : querying.mQueriesIntents) {
+ for (Intent intent : querying.getQueriesIntents()) {
if (matches(intent, potentialTarget)) {
return true;
}
@@ -202,41 +210,40 @@ public class AppsFilter {
return false;
}
- private static boolean matches(Intent intent, PackageParser.Package potentialTarget) {
- for (int p = potentialTarget.providers.size() - 1; p >= 0; p--) {
- PackageParser.Provider provider = potentialTarget.providers.get(p);
- if (!provider.info.exported) {
+ private static boolean matches(Intent intent, AndroidPackage potentialTarget) {
+ for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) {
+ ParsedProvider provider = potentialTarget.getProviders().get(p);
+ if (!provider.isExported()) {
continue;
}
- final ProviderInfo providerInfo = provider.info;
final Uri data = intent.getData();
if ("content".equalsIgnoreCase(intent.getScheme())
&& data != null
- && Objects.equals(providerInfo.authority, data.getAuthority())) {
+ && Objects.equals(provider.getAuthority(), data.getAuthority())) {
return true;
}
}
- for (int s = potentialTarget.services.size() - 1; s >= 0; s--) {
- PackageParser.Service service = potentialTarget.services.get(s);
- if (!service.info.exported) {
+ for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) {
+ ParsedService service = potentialTarget.getServices().get(s);
+ if (!service.exported) {
continue;
}
if (matchesAnyFilter(intent, service)) {
return true;
}
}
- for (int a = potentialTarget.activities.size() - 1; a >= 0; a--) {
- PackageParser.Activity activity = potentialTarget.activities.get(a);
- if (!activity.info.exported) {
+ for (int a = ArrayUtils.size(potentialTarget.getActivities()) - 1; a >= 0; a--) {
+ ParsedActivity activity = potentialTarget.getActivities().get(a);
+ if (!activity.exported) {
continue;
}
if (matchesAnyFilter(intent, activity)) {
return true;
}
}
- for (int r = potentialTarget.receivers.size() - 1; r >= 0; r--) {
- PackageParser.Activity receiver = potentialTarget.receivers.get(r);
- if (!receiver.info.exported) {
+ for (int r = ArrayUtils.size(potentialTarget.getReceivers()) - 1; r >= 0; r--) {
+ ParsedActivity receiver = potentialTarget.getReceivers().get(r);
+ if (!receiver.exported) {
continue;
}
if (matchesAnyFilter(intent, receiver)) {
@@ -247,9 +254,9 @@ public class AppsFilter {
}
private static boolean matchesAnyFilter(
- Intent intent, Component<? extends IntentInfo> component) {
- ArrayList<? extends IntentInfo> intents = component.intents;
- for (int i = intents.size() - 1; i >= 0; i--) {
+ Intent intent, ParsedComponent<? extends ParsedIntentInfo> component) {
+ List<? extends ParsedIntentInfo> intents = component.intents;
+ for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
IntentFilter intentFilter = intents.get(i);
if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
intent.getData(), intent.getCategories(), "AppsFilter") > 0) {
@@ -287,7 +294,7 @@ public class AppsFilter {
ArrayMap<String, PackageSetting> existingSettings) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
try {
- final PackageParser.Package newPkg = newPkgSetting.pkg;
+ final AndroidPackage newPkg = newPkgSetting.pkg;
if (newPkg == null) {
// nothing to add
return;
@@ -296,10 +303,10 @@ public class AppsFilter {
final boolean newIsForceQueryable =
mForceQueryable.contains(newPkgSetting.appId)
/* shared user that is already force queryable */
- || newPkg.mForceQueryable
+ || newPkg.isForceQueryable()
|| (newPkgSetting.isSystem() && (mSystemAppsQueryable
|| ArrayUtils.contains(mForceQueryableByDevicePackageNames,
- newPkg.packageName)));
+ newPkg.getPackageName())));
if (newIsForceQueryable) {
mForceQueryable.add(newPkgSetting.appId);
}
@@ -309,14 +316,14 @@ public class AppsFilter {
if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) {
continue;
}
- final PackageParser.Package existingPkg = existingSetting.pkg;
+ final AndroidPackage existingPkg = existingSetting.pkg;
// let's evaluate the ability of already added packages to see this new package
if (!newIsForceQueryable) {
if (canQueryViaIntent(existingPkg, newPkg)) {
mQueriesViaIntent.add(existingSetting.appId, newPkgSetting.appId);
}
- if (existingPkg.mQueriesPackages != null
- && existingPkg.mQueriesPackages.contains(newPkg.packageName)) {
+ if (existingPkg.getQueriesPackages() != null
+ && existingPkg.getQueriesPackages().contains(newPkg.getPackageName())) {
mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
}
}
@@ -325,8 +332,8 @@ public class AppsFilter {
if (canQueryViaIntent(newPkg, existingPkg)) {
mQueriesViaIntent.add(newPkgSetting.appId, existingSetting.appId);
}
- if (newPkg.mQueriesPackages != null
- && newPkg.mQueriesPackages.contains(existingPkg.packageName)) {
+ if (newPkg.getQueriesPackages() != null
+ && newPkg.getQueriesPackages().contains(existingPkg.getPackageName())) {
mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
}
}
@@ -456,14 +463,14 @@ public class AppsFilter {
// This package isn't technically installed and won't be written to settings, so we can
// treat it as filtered until it's available again.
- final PackageParser.Package targetPkg = targetPkgSetting.pkg;
+ final AndroidPackage targetPkg = targetPkgSetting.pkg;
if (targetPkg == null) {
if (DEBUG_LOGGING) {
Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
}
return true;
}
- final String targetName = targetPkg.packageName;
+ final String targetName = targetPkg.getPackageName();
final int callingAppId;
if (callingPkgSetting != null) {
callingAppId = callingPkgSetting.appId;
@@ -532,9 +539,10 @@ public class AppsFilter {
private static boolean callingPkgInstruments(PackageSetting callingPkgSetting,
PackageSetting targetPkgSetting,
String targetName) {
- final ArrayList<PackageParser.Instrumentation> inst = callingPkgSetting.pkg.instrumentation;
- for (int i = inst.size() - 1; i >= 0; i--) {
- if (inst.get(i).info.targetPackage == targetName) {
+ final List<ComponentParseUtils.ParsedInstrumentation> inst =
+ callingPkgSetting.pkg.getInstrumentations();
+ for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) {
+ if (Objects.equals(inst.get(i).getTargetPackage(), targetName)) {
if (DEBUG_LOGGING) {
log(callingPkgSetting, targetPkgSetting, "instrumentation");
}
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index b1eb7e79bc1b..f2a2e65f733b 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -21,7 +21,6 @@ import static android.content.pm.PackageManagerInternal.PACKAGE_SETUP_WIZARD;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
-import static com.android.server.pm.PackageManagerService.fixProcessName;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -33,13 +32,18 @@ import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.InstantAppResolveInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.ActivityIntentInfo;
-import android.content.pm.PackageParser.ServiceIntentInfo;
import android.content.pm.PackageUserState;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProviderIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.ComponentParseUtils.ParsedServiceIntentInfo;
+import android.content.pm.parsing.PackageInfoUtils;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -55,11 +59,14 @@ import com.android.server.IntentResolver;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.function.Function;
/** Resolves all Android component types [activities, services, providers and receivers]. */
public class ComponentResolver {
@@ -160,7 +167,7 @@ public class ComponentResolver {
/** All available receivers, for your resolving pleasure. */
@GuardedBy("mLock")
- private final ActivityIntentResolver mReceivers = new ActivityIntentResolver();
+ private final ActivityIntentResolver mReceivers = new ReceiverIntentResolver();
/** All available services, for your resolving pleasure. */
@GuardedBy("mLock")
@@ -168,7 +175,7 @@ public class ComponentResolver {
/** Mapping from provider authority [first directory in content URI codePath) to provider. */
@GuardedBy("mLock")
- private final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>();
+ private final ArrayMap<String, ParsedProvider> mProvidersByAuthority = new ArrayMap<>();
/** Whether or not processing protected filters should be deferred. */
private boolean mDeferProtectedFilters = true;
@@ -183,7 +190,7 @@ public class ComponentResolver {
* /system partition in order to know which component is the setup wizard. This can
* only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}.
*/
- private List<PackageParser.ActivityIntentInfo> mProtectedFilters;
+ private List<ParsedActivityIntentInfo> mProtectedFilters;
ComponentResolver(UserManagerService userManager,
PackageManagerInternal packageManagerInternal,
@@ -194,28 +201,28 @@ public class ComponentResolver {
}
/** Returns the given activity */
- PackageParser.Activity getActivity(ComponentName component) {
+ ParsedActivity getActivity(ComponentName component) {
synchronized (mLock) {
return mActivities.mActivities.get(component);
}
}
/** Returns the given provider */
- PackageParser.Provider getProvider(ComponentName component) {
+ ParsedProvider getProvider(ComponentName component) {
synchronized (mLock) {
return mProviders.mProviders.get(component);
}
}
/** Returns the given receiver */
- PackageParser.Activity getReceiver(ComponentName component) {
+ ParsedActivity getReceiver(ComponentName component) {
synchronized (mLock) {
return mReceivers.mActivities.get(component);
}
}
/** Returns the given service */
- PackageParser.Service getService(ComponentName component) {
+ ParsedService getService(ComponentName component) {
synchronized (mLock) {
return mServices.mServices.get(component);
}
@@ -230,7 +237,7 @@ public class ComponentResolver {
@Nullable
List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags,
- List<PackageParser.Activity> activities, int userId) {
+ List<ParsedActivity> activities, int userId) {
synchronized (mLock) {
return mActivities.queryIntentForPackage(
intent, resolvedType, flags, activities, userId);
@@ -246,7 +253,7 @@ public class ComponentResolver {
@Nullable
List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags,
- List<PackageParser.Provider> providers, int userId) {
+ List<ParsedProvider> providers, int userId) {
synchronized (mLock) {
return mProviders.queryIntentForPackage(intent, resolvedType, flags, providers, userId);
}
@@ -261,25 +268,34 @@ public class ComponentResolver {
List<ProviderInfo> providerList = null;
synchronized (mLock) {
for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) {
- final PackageParser.Provider p = mProviders.mProviders.valueAt(i);
- final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+ final ParsedProvider p = mProviders.mProviders.valueAt(i);
+ if (p.getAuthority() == null) {
+ continue;
+ }
+
+ final PackageSetting ps =
+ (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ p.getPackageName());
if (ps == null) {
continue;
}
- if (p.info.authority == null) {
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+ if (pkg == null) {
continue;
}
- if (processName != null && (!p.info.processName.equals(processName)
- || !UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) {
+
+ if (processName != null && (!p.getProcessName().equals(processName)
+ || !UserHandle.isSameApp(pkg.getUid(), uid))) {
continue;
}
// See PM.queryContentProviders()'s javadoc for why we have the metaData parameter.
if (metaDataKey != null
- && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
+ && (p.getMetaData() == null || !p.getMetaData().containsKey(metaDataKey))) {
continue;
}
- final ProviderInfo info = PackageParser.generateProviderInfo(
- p, flags, ps.readUserState(userId), userId);
+ final ProviderInfo info = PackageInfoUtils.generateProviderInfo(
+ pkg, p, flags, ps.readUserState(userId), userId);
if (info == null) {
continue;
}
@@ -295,15 +311,21 @@ public class ComponentResolver {
@Nullable
ProviderInfo queryProvider(String authority, int flags, int userId) {
synchronized (mLock) {
- final PackageParser.Provider p = mProvidersByAuthority.get(authority);
+ final ParsedProvider p = mProvidersByAuthority.get(authority);
if (p == null) {
return null;
}
- final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+ final PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ p.getPackageName());
if (ps == null) {
return null;
}
- return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId);
+ final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+ if (pkg == null) {
+ return null;
+ }
+ return PackageInfoUtils.generateProviderInfo(pkg, p, flags,
+ ps.readUserState(userId), userId);
}
}
@@ -311,20 +333,29 @@ public class ComponentResolver {
int userId) {
synchronized (mLock) {
for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) {
- final PackageParser.Provider p = mProvidersByAuthority.valueAt(i);
- final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+ final ParsedProvider p = mProvidersByAuthority.valueAt(i);
+ if (!p.isSyncable()) {
+ continue;
+ }
+
+ final PackageSetting ps =
+ (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ p.getPackageName());
if (ps == null) {
continue;
}
- if (!p.syncable) {
+
+ final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+ if (pkg == null) {
continue;
}
- if (safeMode
- && (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+
+ if (safeMode && (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
final ProviderInfo info =
- PackageParser.generateProviderInfo(p, 0, ps.readUserState(userId), userId);
+ PackageInfoUtils.generateProviderInfo(pkg, p, 0,
+ ps.readUserState(userId), userId);
if (info == null) {
continue;
}
@@ -343,7 +374,7 @@ public class ComponentResolver {
@Nullable
List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags,
- List<PackageParser.Activity> receivers, int userId) {
+ List<ParsedActivity> receivers, int userId) {
synchronized (mLock) {
return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId);
}
@@ -358,7 +389,7 @@ public class ComponentResolver {
@Nullable
List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags,
- List<PackageParser.Service> services, int userId) {
+ List<ParsedService> services, int userId) {
synchronized (mLock) {
return mServices.queryIntentForPackage(intent, resolvedType, flags, services, userId);
}
@@ -372,15 +403,15 @@ public class ComponentResolver {
}
/** Asserts none of the providers defined in the given package haven't already been defined. */
- void assertProvidersNotDefined(PackageParser.Package pkg) throws PackageManagerException {
+ void assertProvidersNotDefined(AndroidPackage pkg) throws PackageManagerException {
synchronized (mLock) {
assertProvidersNotDefinedLocked(pkg);
}
}
/** Add all components defined in the given package to the internal structures. */
- void addAllComponents(PackageParser.Package pkg, boolean chatty) {
- final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>();
+ void addAllComponents(AndroidPackage pkg, boolean chatty) {
+ final ArrayList<ParsedActivityIntentInfo> newIntents = new ArrayList<>();
synchronized (mLock) {
addActivitiesLocked(pkg, newIntents, chatty);
addReceiversLocked(pkg, chatty);
@@ -393,17 +424,19 @@ public class ComponentResolver {
PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM));
for (int i = newIntents.size() - 1; i >= 0; --i) {
- final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i);
- final PackageParser.Package disabledPkg = sPackageManagerInternal
- .getDisabledSystemPackage(intentInfo.activity.info.packageName);
- final List<PackageParser.Activity> systemActivities =
- disabledPkg != null ? disabledPkg.activities : null;
+ final ParsedActivityIntentInfo intentInfo = newIntents.get(i);
+ final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal
+ .getDisabledSystemPackage(intentInfo.getPackageName());
+ final AndroidPackage disabledPkg =
+ disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
+ final List<ParsedActivity> systemActivities =
+ disabledPkg != null ? disabledPkg.getActivities() : null;
adjustPriority(systemActivities, intentInfo, setupWizardPackage);
}
}
/** Removes all components defined in the given package from the internal structures. */
- void removeAllComponents(PackageParser.Package pkg, boolean chatty) {
+ void removeAllComponents(AndroidPackage pkg, boolean chatty) {
synchronized (mLock) {
removeAllComponentsLocked(pkg, chatty);
}
@@ -422,7 +455,7 @@ public class ComponentResolver {
if (mProtectedFilters == null || mProtectedFilters.size() == 0) {
return;
}
- final List<ActivityIntentInfo> protectedFilters = mProtectedFilters;
+ final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters;
mProtectedFilters = null;
// expect single setupwizard package
@@ -435,13 +468,13 @@ public class ComponentResolver {
+ " All protected intents capped to priority 0");
}
for (int i = protectedFilters.size() - 1; i >= 0; --i) {
- final ActivityIntentInfo filter = protectedFilters.get(i);
- if (filter.activity.info.packageName.equals(setupWizardPackage)) {
+ final ParsedActivityIntentInfo filter = protectedFilters.get(i);
+ if (filter.getPackageName().equals(setupWizardPackage)) {
if (DEBUG_FILTERS) {
Slog.i(TAG, "Found setup wizard;"
+ " allow priority " + filter.getPriority() + ";"
- + " package: " + filter.activity.info.packageName
- + " activity: " + filter.activity.className
+ + " package: " + filter.getPackageName()
+ + " activity: " + filter.getClassName()
+ " priority: " + filter.getPriority());
}
// skip setup wizard; allow it to keep the high priority filter
@@ -449,8 +482,8 @@ public class ComponentResolver {
}
if (DEBUG_FILTERS) {
Slog.i(TAG, "Protected action; cap priority to 0;"
- + " package: " + filter.activity.info.packageName
- + " activity: " + filter.activity.className
+ + " package: " + filter.getPackageName()
+ + " activity: " + filter.getClassName()
+ " origPrio: " + filter.getPriority());
}
filter.setPriority(0);
@@ -491,8 +524,8 @@ public class ComponentResolver {
void dumpContentProviders(PrintWriter pw, DumpState dumpState, String packageName) {
boolean printedSomething = false;
- for (PackageParser.Provider p : mProviders.mProviders.values()) {
- if (packageName != null && !packageName.equals(p.info.packageName)) {
+ for (ParsedProvider p : mProviders.mProviders.values()) {
+ if (packageName != null && !packageName.equals(p.getPackageName())) {
continue;
}
if (!printedSomething) {
@@ -502,14 +535,17 @@ public class ComponentResolver {
pw.println("Registered ContentProviders:");
printedSomething = true;
}
- pw.print(" "); p.printComponentShortName(pw); pw.println(":");
- pw.print(" "); pw.println(p.toString());
+ pw.print(" ");
+ ComponentName.printShortString(pw, p.getPackageName(), p.className);
+ pw.println(":");
+ pw.print(" ");
+ pw.println(p.toString());
}
printedSomething = false;
- for (Map.Entry<String, PackageParser.Provider> entry :
+ for (Map.Entry<String, ParsedProvider> entry :
mProvidersByAuthority.entrySet()) {
- PackageParser.Provider p = entry.getValue();
- if (packageName != null && !packageName.equals(p.info.packageName)) {
+ ParsedProvider p = entry.getValue();
+ if (packageName != null && !packageName.equals(p.getPackageName())) {
continue;
}
if (!printedSomething) {
@@ -521,25 +557,43 @@ public class ComponentResolver {
}
pw.print(" ["); pw.print(entry.getKey()); pw.println("]:");
pw.print(" "); pw.println(p.toString());
- if (p.info != null && p.info.applicationInfo != null) {
- final String appInfo = p.info.applicationInfo.toString();
- pw.print(" applicationInfo="); pw.println(appInfo);
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+
+ if (pkg != null) {
+ // TODO(b/135203078): Print AppInfo?
+ pw.print(" applicationInfo="); pw.println(pkg.toAppInfoWithoutState());
}
}
}
- void dumpServicePermissions(PrintWriter pw, DumpState dumpState, String packageName) {
+ void dumpServicePermissions(PrintWriter pw, DumpState dumpState) {
if (dumpState.onTitlePrinted()) pw.println();
pw.println("Service permissions:");
- final Iterator<ServiceIntentInfo> filterIterator = mServices.filterIterator();
+ final Iterator<ParsedServiceIntentInfo> filterIterator = mServices.filterIterator();
while (filterIterator.hasNext()) {
- final ServiceIntentInfo info = filterIterator.next();
- final ServiceInfo serviceInfo = info.service.info;
- final String permission = serviceInfo.permission;
+ final ParsedServiceIntentInfo info = filterIterator.next();
+
+ ParsedService service = null;
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
+ if (pkg != null && pkg.getServices() != null) {
+ for (ParsedService parsedService : pkg.getServices()) {
+ if (Objects.equals(parsedService.className, info.getClassName())) {
+ service = parsedService;
+ }
+ }
+ }
+
+ if (service == null) {
+ continue;
+ }
+
+ final String permission = service.getPermission();
if (permission != null) {
pw.print(" ");
- pw.print(serviceInfo.getComponentName().flattenToShortString());
+ pw.print(service.getComponentName().flattenToShortString());
pw.print(": ");
pw.println(permission);
}
@@ -547,14 +601,12 @@ public class ComponentResolver {
}
@GuardedBy("mLock")
- private void addActivitiesLocked(PackageParser.Package pkg,
- List<PackageParser.ActivityIntentInfo> newIntents, boolean chatty) {
- final int activitiesSize = pkg.activities.size();
+ private void addActivitiesLocked(AndroidPackage pkg,
+ List<ParsedActivityIntentInfo> newIntents, boolean chatty) {
+ final int activitiesSize = ArrayUtils.size(pkg.getActivities());
StringBuilder r = null;
for (int i = 0; i < activitiesSize; i++) {
- PackageParser.Activity a = pkg.activities.get(i);
- a.info.processName =
- fixProcessName(pkg.applicationInfo.processName, a.info.processName);
+ ParsedActivity a = pkg.getActivities().get(i);
mActivities.addActivity(a, "activity", newIntents);
if (DEBUG_PACKAGE_SCANNING && chatty) {
if (r == null) {
@@ -562,7 +614,7 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(a.getName());
}
}
if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -571,20 +623,17 @@ public class ComponentResolver {
}
@GuardedBy("mLock")
- private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) {
- final int providersSize = pkg.providers.size();
+ private void addProvidersLocked(AndroidPackage pkg, boolean chatty) {
+ final int providersSize = ArrayUtils.size(pkg.getProviders());
StringBuilder r = null;
for (int i = 0; i < providersSize; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- p.info.processName = fixProcessName(pkg.applicationInfo.processName,
- p.info.processName);
+ EffectiveProvider p = new EffectiveProvider(pkg.getProviders().get(i));
mProviders.addProvider(p);
- p.syncable = p.info.isSyncable;
- if (p.info.authority != null) {
- String[] names = p.info.authority.split(";");
- p.info.authority = null;
+ if (p.getAuthority() != null) {
+ String[] names = p.getAuthority().split(";");
+ p.setEffectiveAuthority(null);
for (int j = 0; j < names.length; j++) {
- if (j == 1 && p.syncable) {
+ if (j == 1 && p.isSyncable()) {
// We only want the first authority for a provider to possibly be
// syncable, so if we already added this provider using a different
// authority clear the syncable flag. We copy the provider before
@@ -592,23 +641,23 @@ public class ComponentResolver {
// to a provider that we don't want to change.
// Only do this for the second authority since the resulting provider
// object can be the same for all future authorities for this provider.
- p = new PackageParser.Provider(p);
- p.syncable = false;
+ p = new EffectiveProvider(p);
+ p.setEffectiveSyncable(false);
}
if (!mProvidersByAuthority.containsKey(names[j])) {
mProvidersByAuthority.put(names[j], p);
- if (p.info.authority == null) {
- p.info.authority = names[j];
+ if (p.getAuthority() == null) {
+ p.setEffectiveAuthority(names[j]);
} else {
- p.info.authority = p.info.authority + ";" + names[j];
+ p.setEffectiveAuthority(p.getAuthority() + ";" + names[j]);
}
if (DEBUG_PACKAGE_SCANNING && chatty) {
Log.d(TAG, "Registered content provider: " + names[j]
- + ", className = " + p.info.name
- + ", isSyncable = " + p.info.isSyncable);
+ + ", className = " + p.getName()
+ + ", isSyncable = " + p.isSyncable());
}
} else {
- final PackageParser.Provider other =
+ final ParsedProvider other =
mProvidersByAuthority.get(names[j]);
final ComponentName component =
(other != null && other.getComponentName() != null)
@@ -616,7 +665,7 @@ public class ComponentResolver {
final String packageName =
component != null ? component.getPackageName() : "?";
Slog.w(TAG, "Skipping provider name " + names[j]
- + " (in package " + pkg.applicationInfo.packageName + ")"
+ + " (in package " + pkg.getAppInfoPackageName() + ")"
+ ": name already used by " + packageName);
}
}
@@ -627,7 +676,7 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(p.info.name);
+ r.append(p.getName());
}
}
if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -636,13 +685,11 @@ public class ComponentResolver {
}
@GuardedBy("mLock")
- private void addReceiversLocked(PackageParser.Package pkg, boolean chatty) {
- final int receiversSize = pkg.receivers.size();
+ private void addReceiversLocked(AndroidPackage pkg, boolean chatty) {
+ final int receiversSize = ArrayUtils.size(pkg.getReceivers());
StringBuilder r = null;
for (int i = 0; i < receiversSize; i++) {
- PackageParser.Activity a = pkg.receivers.get(i);
- a.info.processName = fixProcessName(pkg.applicationInfo.processName,
- a.info.processName);
+ ParsedActivity a = pkg.getReceivers().get(i);
mReceivers.addActivity(a, "receiver", null);
if (DEBUG_PACKAGE_SCANNING && chatty) {
if (r == null) {
@@ -650,7 +697,7 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(a.getName());
}
}
if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -659,13 +706,11 @@ public class ComponentResolver {
}
@GuardedBy("mLock")
- private void addServicesLocked(PackageParser.Package pkg, boolean chatty) {
- final int servicesSize = pkg.services.size();
+ private void addServicesLocked(AndroidPackage pkg, boolean chatty) {
+ final int servicesSize = ArrayUtils.size(pkg.getServices());
StringBuilder r = null;
for (int i = 0; i < servicesSize; i++) {
- PackageParser.Service s = pkg.services.get(i);
- s.info.processName = fixProcessName(pkg.applicationInfo.processName,
- s.info.processName);
+ ParsedService s = pkg.getServices().get(i);
mServices.addService(s);
if (DEBUG_PACKAGE_SCANNING && chatty) {
if (r == null) {
@@ -673,7 +718,7 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(s.info.name);
+ r.append(s.getName());
}
}
if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -681,13 +726,12 @@ public class ComponentResolver {
}
}
-
/**
* <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
* MODIFIED. Do not pass in a list that should not be changed.
*/
- private static <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
- IterGenerator<T> generator, Iterator<T> searchIterator) {
+ private static <T> void getIntentListSubset(List<ParsedActivityIntentInfo> intentList,
+ Function<ParsedActivityIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) {
// loop through the set of actions; every one must be found in the intent filter
while (searchIterator.hasNext()) {
// we must have at least one filter in the list to consider a match
@@ -698,14 +742,14 @@ public class ComponentResolver {
final T searchAction = searchIterator.next();
// loop through the set of intent filters
- final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
+ final Iterator<ParsedActivityIntentInfo> intentIter = intentList.iterator();
while (intentIter.hasNext()) {
- final ActivityIntentInfo intentInfo = intentIter.next();
+ final ParsedActivityIntentInfo intentInfo = intentIter.next();
boolean selectionFound = false;
// loop through the intent filter's selection criteria; at least one
// of them must match the searched criteria
- final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
+ final Iterator<T> intentSelectionIter = generator.apply(intentInfo);
while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
final T intentSelection = intentSelectionIter.next();
if (intentSelection != null && intentSelection.equals(searchAction)) {
@@ -723,7 +767,7 @@ public class ComponentResolver {
}
}
- private static boolean isProtectedAction(ActivityIntentInfo filter) {
+ private static boolean isProtectedAction(ParsedActivityIntentInfo filter) {
final Iterator<String> actionsIter = filter.actionsIterator();
while (actionsIter != null && actionsIter.hasNext()) {
final String filterAction = actionsIter.next();
@@ -737,20 +781,20 @@ public class ComponentResolver {
/**
* Finds a privileged activity that matches the specified activity names.
*/
- private static PackageParser.Activity findMatchingActivity(
- List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
- for (PackageParser.Activity sysActivity : activityList) {
- if (sysActivity.info.name.equals(activityInfo.name)) {
+ private static ParsedActivity findMatchingActivity(
+ List<ParsedActivity> activityList, ParsedActivity activityInfo) {
+ for (ParsedActivity sysActivity : activityList) {
+ if (sysActivity.getName().equals(activityInfo.getName())) {
return sysActivity;
}
- if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+ if (sysActivity.getName().equals(activityInfo.targetActivity)) {
return sysActivity;
}
- if (sysActivity.info.targetActivity != null) {
- if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+ if (sysActivity.targetActivity != null) {
+ if (sysActivity.targetActivity.equals(activityInfo.getName())) {
return sysActivity;
}
- if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+ if (sysActivity.targetActivity.equals(activityInfo.targetActivity)) {
return sysActivity;
}
}
@@ -771,24 +815,23 @@ public class ComponentResolver {
* <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
* allowed to obtain any priority on any action.
*/
- private void adjustPriority(List<PackageParser.Activity> systemActivities,
- ActivityIntentInfo intent, String setupWizardPackage) {
+ private void adjustPriority(List<ParsedActivity> systemActivities,
+ ParsedActivityIntentInfo intent, String setupWizardPackage) {
// nothing to do; priority is fine as-is
if (intent.getPriority() <= 0) {
return;
}
- final ActivityInfo activityInfo = intent.activity.info;
- final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(intent.getPackageName());
final boolean privilegedApp =
- ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+ ((pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
if (!privilegedApp) {
// non-privileged applications can never define a priority >0
if (DEBUG_FILTERS) {
Slog.i(TAG, "Non-privileged app; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(0);
@@ -812,8 +855,8 @@ public class ComponentResolver {
mProtectedFilters.add(intent);
if (DEBUG_FILTERS) {
Slog.i(TAG, "Protected action; save for later;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
return;
@@ -822,12 +865,12 @@ public class ComponentResolver {
Slog.i(TAG, "No setup wizard;"
+ " All protected intents capped to priority 0");
}
- if (intent.activity.info.packageName.equals(setupWizardPackage)) {
+ if (intent.getPackageName().equals(setupWizardPackage)) {
if (DEBUG_FILTERS) {
Slog.i(TAG, "Found setup wizard;"
+ " allow priority " + intent.getPriority() + ";"
- + " package: " + intent.activity.info.packageName
- + " activity: " + intent.activity.className
+ + " package: " + intent.getPackageName()
+ + " activity: " + intent.getClassName()
+ " priority: " + intent.getPriority());
}
// setup wizard gets whatever it wants
@@ -835,8 +878,8 @@ public class ComponentResolver {
}
if (DEBUG_FILTERS) {
Slog.i(TAG, "Protected action; cap priority to 0;"
- + " package: " + intent.activity.info.packageName
- + " activity: " + intent.activity.className
+ + " package: " + intent.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(0);
@@ -848,14 +891,28 @@ public class ComponentResolver {
}
// privileged app unbundled update ... try to find the same activity
- final PackageParser.Activity foundActivity =
- findMatchingActivity(systemActivities, activityInfo);
+
+ ParsedActivity foundActivity = null;
+ ParsedActivity activity = null;
+
+ if (pkg.getActivities() != null) {
+ for (ParsedActivity parsedProvider : pkg.getActivities()) {
+ if (Objects.equals(parsedProvider.className, intent.getClassName())) {
+ activity = parsedProvider;
+ }
+ }
+ }
+
+ if (activity != null) {
+ foundActivity = findMatchingActivity(systemActivities, activity);
+ }
+
if (foundActivity == null) {
// this is a new activity; it cannot obtain >0 priority
if (DEBUG_FILTERS) {
Slog.i(TAG, "New activity; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(0);
@@ -865,19 +922,19 @@ public class ComponentResolver {
// found activity, now check for filter equivalence
// a shallow copy is enough; we modify the list, not its contents
- final List<ActivityIntentInfo> intentListCopy = new ArrayList<>(foundActivity.intents);
- final List<ActivityIntentInfo> foundFilters = mActivities.findFilters(intent);
+ final List<ParsedActivityIntentInfo> intentListCopy =
+ new ArrayList<>(foundActivity.intents);
// find matching action subsets
final Iterator<String> actionsIterator = intent.actionsIterator();
if (actionsIterator != null) {
- getIntentListSubset(intentListCopy, new ActionIterGenerator(), actionsIterator);
+ getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched action; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(0);
@@ -888,13 +945,14 @@ public class ComponentResolver {
// find matching category subsets
final Iterator<String> categoriesIterator = intent.categoriesIterator();
if (categoriesIterator != null) {
- getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), categoriesIterator);
+ getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator,
+ categoriesIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched category; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(0);
@@ -905,13 +963,13 @@ public class ComponentResolver {
// find matching schemes subsets
final Iterator<String> schemesIterator = intent.schemesIterator();
if (schemesIterator != null) {
- getIntentListSubset(intentListCopy, new SchemesIterGenerator(), schemesIterator);
+ getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(0);
@@ -923,14 +981,14 @@ public class ComponentResolver {
final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator =
intent.authoritiesIterator();
if (authoritiesIterator != null) {
- getIntentListSubset(intentListCopy, new AuthoritiesIterGenerator(),
+ getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator,
authoritiesIterator);
if (intentListCopy.size() == 0) {
// no more intents to match; we're not equivalent
if (DEBUG_FILTERS) {
Slog.i(TAG, "Mismatched authority; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(0);
@@ -947,8 +1005,8 @@ public class ComponentResolver {
if (DEBUG_FILTERS) {
Slog.i(TAG, "Found matching filter(s);"
+ " cap priority to " + cappedPriority + ";"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
+ + " package: " + pkg.getPackageName()
+ + " activity: " + intent.getClassName()
+ " origPrio: " + intent.getPriority());
}
intent.setPriority(cappedPriority);
@@ -958,15 +1016,15 @@ public class ComponentResolver {
}
@GuardedBy("mLock")
- private void removeAllComponentsLocked(PackageParser.Package pkg, boolean chatty) {
+ private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) {
int componentSize;
StringBuilder r;
int i;
- componentSize = pkg.activities.size();
+ componentSize = ArrayUtils.size(pkg.getActivities());
r = null;
for (i = 0; i < componentSize; i++) {
- PackageParser.Activity a = pkg.activities.get(i);
+ ParsedActivity a = pkg.getActivities().get(i);
mActivities.removeActivity(a, "activity");
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -974,32 +1032,32 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(a.getName());
}
}
if (DEBUG_REMOVE && chatty) {
Log.d(TAG, " Activities: " + (r == null ? "<NONE>" : r));
}
- componentSize = pkg.providers.size();
+ componentSize = ArrayUtils.size(pkg.getProviders());
r = null;
for (i = 0; i < componentSize; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
+ ParsedProvider p = pkg.getProviders().get(i);
mProviders.removeProvider(p);
- if (p.info.authority == null) {
+ if (p.getAuthority() == null) {
// Another content provider with this authority existed when this app was
// installed, so this authority is null. Ignore it as we don't have to
// unregister the provider.
continue;
}
- String[] names = p.info.authority.split(";");
+ String[] names = p.getAuthority().split(";");
for (int j = 0; j < names.length; j++) {
if (mProvidersByAuthority.get(names[j]) == p) {
mProvidersByAuthority.remove(names[j]);
if (DEBUG_REMOVE && chatty) {
Log.d(TAG, "Unregistered content provider: " + names[j]
- + ", className = " + p.info.name + ", isSyncable = "
- + p.info.isSyncable);
+ + ", className = " + p.getName() + ", isSyncable = "
+ + p.isSyncable());
}
}
}
@@ -1009,17 +1067,17 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(p.info.name);
+ r.append(p.getName());
}
}
if (DEBUG_REMOVE && chatty) {
Log.d(TAG, " Providers: " + (r == null ? "<NONE>" : r));
}
- componentSize = pkg.receivers.size();
+ componentSize = ArrayUtils.size(pkg.getReceivers());
r = null;
for (i = 0; i < componentSize; i++) {
- PackageParser.Activity a = pkg.receivers.get(i);
+ ParsedActivity a = pkg.getReceivers().get(i);
mReceivers.removeActivity(a, "receiver");
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -1027,17 +1085,17 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(a.getName());
}
}
if (DEBUG_REMOVE && chatty) {
Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r));
}
- componentSize = pkg.services.size();
+ componentSize = ArrayUtils.size(pkg.getServices());
r = null;
for (i = 0; i < componentSize; i++) {
- PackageParser.Service s = pkg.services.get(i);
+ ParsedService s = pkg.getServices().get(i);
mServices.removeService(s);
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -1045,7 +1103,7 @@ public class ComponentResolver {
} else {
r.append(' ');
}
- r.append(s.info.name);
+ r.append(s.getName());
}
}
if (DEBUG_REMOVE && chatty) {
@@ -1054,26 +1112,26 @@ public class ComponentResolver {
}
@GuardedBy("mLock")
- private void assertProvidersNotDefinedLocked(PackageParser.Package pkg)
+ private void assertProvidersNotDefinedLocked(AndroidPackage pkg)
throws PackageManagerException {
- final int providersSize = pkg.providers.size();
+ final int providersSize = ArrayUtils.size(pkg.getProviders());
int i;
for (i = 0; i < providersSize; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- if (p.info.authority != null) {
- final String[] names = p.info.authority.split(";");
+ ParsedProvider p = pkg.getProviders().get(i);
+ if (p.getAuthority() != null) {
+ final String[] names = p.getAuthority().split(";");
for (int j = 0; j < names.length; j++) {
if (mProvidersByAuthority.containsKey(names[j])) {
- final PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
+ final ParsedProvider other = mProvidersByAuthority.get(names[j]);
final String otherPackageName =
(other != null && other.getComponentName() != null)
? other.getComponentName().getPackageName() : "?";
// if we're installing over the same already-installed package, this is ok
- if (!otherPackageName.equals(pkg.packageName)) {
+ if (!otherPackageName.equals(pkg.getPackageName())) {
throw new PackageManagerException(
INSTALL_FAILED_CONFLICTING_PROVIDER,
"Can't install because provider name " + names[j]
- + " (in package " + pkg.applicationInfo.packageName
+ + " (in package " + pkg.getPackageName()
+ ") is already used by " + otherPackageName);
}
}
@@ -1082,8 +1140,9 @@ public class ComponentResolver {
}
}
- private static final class ActivityIntentResolver
- extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
+ private static class ActivityIntentResolver
+ extends IntentResolver<ParsedActivityIntentInfo, ResolveInfo> {
+
@Override
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
boolean defaultOnly, int userId) {
@@ -1104,24 +1163,24 @@ public class ComponentResolver {
}
List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
- int flags, List<PackageParser.Activity> packageActivities, int userId) {
+ int flags, List<ParsedActivity> packageActivities, int userId) {
if (!sUserManager.exists(userId)) {
return null;
}
if (packageActivities == null) {
- return null;
+ return Collections.emptyList();
}
mFlags = flags;
final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int activitiesSize = packageActivities.size();
- ArrayList<PackageParser.ActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize);
+ ArrayList<ParsedActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize);
- ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
+ List<ParsedActivityIntentInfo> intentFilters;
for (int i = 0; i < activitiesSize; ++i) {
intentFilters = packageActivities.get(i).intents;
if (intentFilters != null && intentFilters.size() > 0) {
- PackageParser.ActivityIntentInfo[] array =
- new PackageParser.ActivityIntentInfo[intentFilters.size()];
+ ParsedActivityIntentInfo[] array =
+ new ParsedActivityIntentInfo[intentFilters.size()];
intentFilters.toArray(array);
listCut.add(array);
}
@@ -1129,21 +1188,21 @@ public class ComponentResolver {
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
- private void addActivity(PackageParser.Activity a, String type,
- List<PackageParser.ActivityIntentInfo> newIntents) {
+ private void addActivity(ParsedActivity a, String type,
+ List<ParsedActivityIntentInfo> newIntents) {
mActivities.put(a.getComponentName(), a);
if (DEBUG_SHOW_INFO) {
- final CharSequence label = a.info.nonLocalizedLabel != null
- ? a.info.nonLocalizedLabel
- : a.info.name;
+ final CharSequence label = a.nonLocalizedLabel != null
+ ? a.nonLocalizedLabel
+ : a.getName();
Log.v(TAG, " " + type + " " + label + ":");
}
if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " Class=" + a.info.name);
+ Log.v(TAG, " Class=" + a.getName());
}
final int intentsSize = a.intents.size();
for (int j = 0; j < intentsSize; j++) {
- PackageParser.ActivityIntentInfo intent = a.intents.get(j);
+ ParsedActivityIntentInfo intent = a.intents.get(j);
if (newIntents != null && "activity".equals(type)) {
newIntents.add(intent);
}
@@ -1152,23 +1211,23 @@ public class ComponentResolver {
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
if (!intent.debugCheck()) {
- Log.w(TAG, "==> For Activity " + a.info.name);
+ Log.w(TAG, "==> For Activity " + a.getName());
}
addFilter(intent);
}
}
- private void removeActivity(PackageParser.Activity a, String type) {
+ private void removeActivity(ParsedActivity a, String type) {
mActivities.remove(a.getComponentName());
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " " + type + " "
- + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel
- : a.info.name) + ":");
- Log.v(TAG, " Class=" + a.info.name);
+ + (a.nonLocalizedLabel != null ? a.nonLocalizedLabel
+ : a.getName()) + ":");
+ Log.v(TAG, " Class=" + a.getName());
}
final int intentsSize = a.intents.size();
for (int j = 0; j < intentsSize; j++) {
- PackageParser.ActivityIntentInfo intent = a.intents.get(j);
+ ParsedActivityIntentInfo intent = a.intents.get(j);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
@@ -1179,11 +1238,11 @@ public class ComponentResolver {
@Override
protected boolean allowFilterResult(
- PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
- ActivityInfo filterAi = filter.activity.info;
+ ParsedActivityIntentInfo filter, List<ResolveInfo> dest) {
for (int i = dest.size() - 1; i >= 0; --i) {
ActivityInfo destAi = dest.get(i).activityInfo;
- if (destAi.name == filterAi.name && destAi.packageName == filterAi.packageName) {
+ if (Objects.equals(destAi.name, filter.getClassName())
+ && Objects.equals(destAi.packageName, filter.getPackageName())) {
return false;
}
}
@@ -1191,34 +1250,39 @@ public class ComponentResolver {
}
@Override
- protected ActivityIntentInfo[] newArray(int size) {
- return new ActivityIntentInfo[size];
+ protected ParsedActivityIntentInfo[] newArray(int size) {
+ return new ParsedActivityIntentInfo[size];
}
@Override
- protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
+ protected boolean isFilterStopped(ParsedActivityIntentInfo filter, int userId) {
if (!sUserManager.exists(userId)) return true;
- PackageParser.Package p = filter.activity.owner;
- if (p != null) {
- PackageSetting ps = (PackageSetting) p.mExtras;
- if (ps != null) {
- // System apps are never considered stopped for purposes of
- // filtering, because there may be no way for the user to
- // actually re-launch them.
- return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
- && ps.getStopped(userId);
- }
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg == null) {
+ return false;
}
- return false;
+
+ PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ filter.getPackageName());
+ if (ps == null) {
+ return false;
+ }
+
+ // System apps are never considered stopped for purposes of
+ // filtering, because there may be no way for the user to
+ // actually re-launch them.
+ return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+ && ps.getStopped(userId);
}
@Override
protected boolean isPackageForFilter(String packageName,
- PackageParser.ActivityIntentInfo info) {
- return packageName.equals(info.activity.owner.packageName);
+ ParsedActivityIntentInfo info) {
+ return packageName.equals(info.getPackageName());
}
- private void log(String reason, ActivityIntentInfo info, int match,
+ private void log(String reason, ParsedActivityIntentInfo info, int match,
int userId) {
Slog.w(TAG, reason
+ "; match: "
@@ -1228,7 +1292,7 @@ public class ComponentResolver {
}
@Override
- protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
+ protected ResolveInfo newResult(ParsedActivityIntentInfo info,
int match, int userId) {
if (!sUserManager.exists(userId)) {
if (DEBUG) {
@@ -1236,7 +1300,29 @@ public class ComponentResolver {
}
return null;
}
- if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) {
+
+ ParsedActivity activity = null;
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
+ if (pkg == null) {
+ return null;
+ }
+
+ // TODO(b/135203078): Consider more efficient ways of doing this.
+ List<ParsedActivity> activities = getResolveList(pkg);
+ if (activities != null) {
+ for (ParsedActivity parsedActivity : activities) {
+ if (Objects.equals(parsedActivity.className, info.getClassName())) {
+ activity = parsedActivity;
+ }
+ }
+ }
+
+ if (activity == null) {
+ return null;
+ }
+
+ if (!sPackageManagerInternal.isEnabledAndMatches(activity, mFlags, userId)) {
if (DEBUG) {
log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
+ DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags),
@@ -1244,8 +1330,8 @@ public class ComponentResolver {
}
return null;
}
- final PackageParser.Activity activity = info.activity;
- PackageSetting ps = (PackageSetting) activity.owner.mExtras;
+ PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ info.getPackageName());
if (ps == null) {
if (DEBUG) {
log("info.activity.owner.mExtras == null", info, match, userId);
@@ -1254,10 +1340,10 @@ public class ComponentResolver {
}
final PackageUserState userState = ps.readUserState(userId);
ActivityInfo ai =
- PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
+ PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, userState, userId);
if (ai == null) {
if (DEBUG) {
- log("Failed to create ActivityInfo based on " + info.activity, info, match,
+ log("Failed to create ActivityInfo based on " + activity, info, match,
userId);
}
return null;
@@ -1307,7 +1393,7 @@ public class ComponentResolver {
}
res.handleAllWebDataURI = info.handleAllWebDataURI();
res.priority = info.getPriority();
- res.preferredOrder = activity.owner.mPreferredOrder;
+ res.preferredOrder = pkg.getPreferredOrder();
//System.out.println("Result: " + res.activityInfo.className +
// " = " + res.priority);
res.match = match;
@@ -1332,40 +1418,64 @@ public class ComponentResolver {
@Override
protected void dumpFilter(PrintWriter out, String prefix,
- PackageParser.ActivityIntentInfo filter) {
+ ParsedActivityIntentInfo filter) {
+ ParsedActivity activity = null;
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg != null && pkg.getActivities() != null) {
+ for (ParsedActivity parsedActivity : pkg.getActivities()) {
+ if (Objects.equals(parsedActivity.className, filter.getClassName())) {
+ activity = parsedActivity;
+ }
+ }
+ }
+
out.print(prefix);
- out.print(Integer.toHexString(System.identityHashCode(filter.activity)));
+ out.print(Integer.toHexString(System.identityHashCode(activity)));
out.print(' ');
- filter.activity.printComponentShortName(out);
+ ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
out.print(" filter ");
out.println(Integer.toHexString(System.identityHashCode(filter)));
}
@Override
- protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) {
- return filter.activity;
+ protected Object filterToLabel(ParsedActivityIntentInfo filter) {
+ return filter;
}
protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
- PackageParser.Activity activity = (PackageParser.Activity) label;
+ ParsedActivityIntentInfo activity = (ParsedActivityIntentInfo) label;
out.print(prefix);
out.print(Integer.toHexString(System.identityHashCode(activity)));
out.print(' ');
- activity.printComponentShortName(out);
+ ComponentName.printShortString(out, activity.getPackageName(), activity.getClassName());
if (count > 1) {
out.print(" ("); out.print(count); out.print(" filters)");
}
out.println();
}
+ protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
+ return pkg.getActivities();
+ }
+
// Keys are String (activity class name), values are Activity.
- private final ArrayMap<ComponentName, PackageParser.Activity> mActivities =
+ private final ArrayMap<ComponentName, ParsedActivity> mActivities =
new ArrayMap<>();
private int mFlags;
}
+ // Both receivers and activities share a class, but point to different get methods
+ private static final class ReceiverIntentResolver extends ActivityIntentResolver {
+
+ @Override
+ protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
+ return pkg.getReceivers();
+ }
+ }
+
private static final class ProviderIntentResolver
- extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> {
+ extends IntentResolver<ParsedProviderIntentInfo, ResolveInfo> {
@Override
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
boolean defaultOnly, int userId) {
@@ -1387,24 +1497,24 @@ public class ComponentResolver {
@Nullable
List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
- int flags, List<PackageParser.Provider> packageProviders, int userId) {
+ int flags, List<ParsedProvider> packageProviders, int userId) {
if (!sUserManager.exists(userId)) {
return null;
}
if (packageProviders == null) {
- return null;
+ return Collections.emptyList();
}
mFlags = flags;
final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int providersSize = packageProviders.size();
- ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(providersSize);
+ ArrayList<ParsedProviderIntentInfo[]> listCut = new ArrayList<>(providersSize);
- ArrayList<PackageParser.ProviderIntentInfo> intentFilters;
+ List<ParsedProviderIntentInfo> intentFilters;
for (int i = 0; i < providersSize; ++i) {
- intentFilters = packageProviders.get(i).intents;
+ intentFilters = packageProviders.get(i).getIntents();
if (intentFilters != null && intentFilters.size() > 0) {
- PackageParser.ProviderIntentInfo[] array =
- new PackageParser.ProviderIntentInfo[intentFilters.size()];
+ ParsedProviderIntentInfo[] array =
+ new ParsedProviderIntentInfo[intentFilters.size()];
intentFilters.toArray(array);
listCut.add(array);
}
@@ -1412,7 +1522,7 @@ public class ComponentResolver {
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
- void addProvider(PackageParser.Provider p) {
+ void addProvider(ParsedProvider p) {
if (mProviders.containsKey(p.getComponentName())) {
Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
return;
@@ -1421,39 +1531,39 @@ public class ComponentResolver {
mProviders.put(p.getComponentName(), p);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " "
- + (p.info.nonLocalizedLabel != null
- ? p.info.nonLocalizedLabel
- : p.info.name)
+ + (p.nonLocalizedLabel != null
+ ? p.nonLocalizedLabel
+ : p.getName())
+ ":");
- Log.v(TAG, " Class=" + p.info.name);
+ Log.v(TAG, " Class=" + p.getName());
}
- final int intentsSize = p.intents.size();
+ final int intentsSize = p.getIntents().size();
int j;
for (j = 0; j < intentsSize; j++) {
- PackageParser.ProviderIntentInfo intent = p.intents.get(j);
+ ParsedProviderIntentInfo intent = p.getIntents().get(j);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
if (!intent.debugCheck()) {
- Log.w(TAG, "==> For Provider " + p.info.name);
+ Log.w(TAG, "==> For Provider " + p.getName());
}
addFilter(intent);
}
}
- void removeProvider(PackageParser.Provider p) {
+ void removeProvider(ParsedProvider p) {
mProviders.remove(p.getComponentName());
if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " " + (p.info.nonLocalizedLabel != null
- ? p.info.nonLocalizedLabel
- : p.info.name) + ":");
- Log.v(TAG, " Class=" + p.info.name);
+ Log.v(TAG, " " + (p.nonLocalizedLabel != null
+ ? p.nonLocalizedLabel
+ : p.getName()) + ":");
+ Log.v(TAG, " Class=" + p.getName());
}
- final int intentsSize = p.intents.size();
+ final int intentsSize = p.getIntents().size();
int j;
for (j = 0; j < intentsSize; j++) {
- PackageParser.ProviderIntentInfo intent = p.intents.get(j);
+ ParsedProviderIntentInfo intent = p.getIntents().get(j);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
@@ -1464,12 +1574,11 @@ public class ComponentResolver {
@Override
protected boolean allowFilterResult(
- PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) {
- ProviderInfo filterPi = filter.provider.info;
+ ParsedProviderIntentInfo filter, List<ResolveInfo> dest) {
for (int i = dest.size() - 1; i >= 0; i--) {
ProviderInfo destPi = dest.get(i).providerInfo;
- if (destPi.name == filterPi.name
- && destPi.packageName == filterPi.packageName) {
+ if (Objects.equals(destPi.name, filter.getClassName())
+ && Objects.equals(destPi.packageName, filter.getPackageName())) {
return false;
}
}
@@ -1477,47 +1586,68 @@ public class ComponentResolver {
}
@Override
- protected PackageParser.ProviderIntentInfo[] newArray(int size) {
- return new PackageParser.ProviderIntentInfo[size];
+ protected ParsedProviderIntentInfo[] newArray(int size) {
+ return new ParsedProviderIntentInfo[size];
}
@Override
- protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) {
+ protected boolean isFilterStopped(ParsedProviderIntentInfo filter, int userId) {
if (!sUserManager.exists(userId)) {
return true;
}
- PackageParser.Package p = filter.provider.owner;
- if (p != null) {
- PackageSetting ps = (PackageSetting) p.mExtras;
- if (ps != null) {
- // System apps are never considered stopped for purposes of
- // filtering, because there may be no way for the user to
- // actually re-launch them.
- return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
- && ps.getStopped(userId);
- }
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg == null) {
+ return false;
+ }
+
+ PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ filter.getPackageName());
+ if (ps == null) {
+ return false;
}
- return false;
+
+ // System apps are never considered stopped for purposes of
+ // filtering, because there may be no way for the user to
+ // actually re-launch them.
+ return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+ && ps.getStopped(userId);
}
@Override
protected boolean isPackageForFilter(String packageName,
- PackageParser.ProviderIntentInfo info) {
- return packageName.equals(info.provider.owner.packageName);
+ ParsedProviderIntentInfo info) {
+ return packageName.equals(info.getPackageName());
}
@Override
- protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter,
+ protected ResolveInfo newResult(ParsedProviderIntentInfo filter,
int match, int userId) {
if (!sUserManager.exists(userId)) {
return null;
}
- final PackageParser.ProviderIntentInfo info = filter;
- if (!sPackageManagerInternal.isEnabledAndMatches(info.provider.info, mFlags, userId)) {
+
+ ParsedProvider provider = null;
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg != null && pkg.getProviders() != null) {
+ for (ParsedProvider parsedProvider : pkg.getProviders()) {
+ if (Objects.equals(parsedProvider.className, filter.getClassName())) {
+ provider = parsedProvider;
+ }
+ }
+ }
+
+ if (provider == null) {
+ return null;
+ }
+
+ if (!sPackageManagerInternal.isEnabledAndMatches(provider, mFlags, userId)) {
return null;
}
- final PackageParser.Provider provider = info.provider;
- PackageSetting ps = (PackageSetting) provider.owner.mExtras;
+
+ PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ filter.getPackageName());
if (ps == null) {
return null;
}
@@ -1527,7 +1657,7 @@ public class ComponentResolver {
final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to instant applications
if (matchVisibleToInstantApp
- && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+ && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
return null;
}
// throw out instant application filters if we're not explicitly requesting them
@@ -1539,8 +1669,8 @@ public class ComponentResolver {
if (userState.instantApp && ps.isUpdateAvailable()) {
return null;
}
- ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags,
- userState, userId);
+ ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider,
+ mFlags, userState, userId);
if (pi == null) {
return null;
}
@@ -1549,13 +1679,13 @@ public class ComponentResolver {
if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = filter;
}
- res.priority = info.getPriority();
- res.preferredOrder = provider.owner.mPreferredOrder;
+ res.priority = filter.getPriority();
+ res.preferredOrder = pkg.getPreferredOrder();
res.match = match;
- res.isDefault = info.hasDefault;
- res.labelRes = info.labelRes;
- res.nonLocalizedLabel = info.nonLocalizedLabel;
- res.icon = info.icon;
+ res.isDefault = filter.hasDefault;
+ res.labelRes = filter.labelRes;
+ res.nonLocalizedLabel = filter.nonLocalizedLabel;
+ res.icon = filter.icon;
res.system = res.providerInfo.applicationInfo.isSystemApp();
return res;
}
@@ -1567,26 +1697,37 @@ public class ComponentResolver {
@Override
protected void dumpFilter(PrintWriter out, String prefix,
- PackageParser.ProviderIntentInfo filter) {
+ ParsedProviderIntentInfo filter) {
+ ParsedProvider provider = null;
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg != null && pkg.getProviders() != null) {
+ for (ParsedProvider parsedProvider : pkg.getProviders()) {
+ if (Objects.equals(parsedProvider.className, filter.getClassName())) {
+ provider = parsedProvider;
+ }
+ }
+ }
+
out.print(prefix);
- out.print(Integer.toHexString(System.identityHashCode(filter.provider)));
+ out.print(Integer.toHexString(System.identityHashCode(provider)));
out.print(' ');
- filter.provider.printComponentShortName(out);
+ ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
out.print(" filter ");
out.println(Integer.toHexString(System.identityHashCode(filter)));
}
@Override
- protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) {
- return filter.provider;
+ protected Object filterToLabel(ParsedProviderIntentInfo filter) {
+ return filter;
}
protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
- final PackageParser.Provider provider = (PackageParser.Provider) label;
+ final ParsedProviderIntentInfo provider = (ParsedProviderIntentInfo) label;
out.print(prefix);
out.print(Integer.toHexString(System.identityHashCode(provider)));
out.print(' ');
- provider.printComponentShortName(out);
+ ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName());
if (count > 1) {
out.print(" (");
out.print(count);
@@ -1595,12 +1736,12 @@ public class ComponentResolver {
out.println();
}
- private final ArrayMap<ComponentName, PackageParser.Provider> mProviders = new ArrayMap<>();
+ private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>();
private int mFlags;
}
private static final class ServiceIntentResolver
- extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
+ extends IntentResolver<ParsedServiceIntentInfo, ResolveInfo> {
@Override
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
boolean defaultOnly, int userId) {
@@ -1618,22 +1759,22 @@ public class ComponentResolver {
}
List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
- int flags, List<PackageParser.Service> packageServices, int userId) {
+ int flags, List<ParsedService> packageServices, int userId) {
if (!sUserManager.exists(userId)) return null;
if (packageServices == null) {
- return null;
+ return Collections.emptyList();
}
mFlags = flags;
final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int servicesSize = packageServices.size();
- ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize);
+ ArrayList<ParsedServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize);
- ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
+ List<ParsedServiceIntentInfo> intentFilters;
for (int i = 0; i < servicesSize; ++i) {
intentFilters = packageServices.get(i).intents;
if (intentFilters != null && intentFilters.size() > 0) {
- PackageParser.ServiceIntentInfo[] array =
- new PackageParser.ServiceIntentInfo[intentFilters.size()];
+ ParsedServiceIntentInfo[] array =
+ new ParsedServiceIntentInfo[intentFilters.size()];
intentFilters.toArray(array);
listCut.add(array);
}
@@ -1641,40 +1782,40 @@ public class ComponentResolver {
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
- void addService(PackageParser.Service s) {
+ void addService(ParsedService s) {
mServices.put(s.getComponentName(), s);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " "
- + (s.info.nonLocalizedLabel != null
- ? s.info.nonLocalizedLabel : s.info.name) + ":");
- Log.v(TAG, " Class=" + s.info.name);
+ + (s.nonLocalizedLabel != null
+ ? s.nonLocalizedLabel : s.getName()) + ":");
+ Log.v(TAG, " Class=" + s.getName());
}
final int intentsSize = s.intents.size();
int j;
for (j = 0; j < intentsSize; j++) {
- PackageParser.ServiceIntentInfo intent = s.intents.get(j);
+ ParsedServiceIntentInfo intent = s.intents.get(j);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
if (!intent.debugCheck()) {
- Log.w(TAG, "==> For Service " + s.info.name);
+ Log.w(TAG, "==> For Service " + s.getName());
}
addFilter(intent);
}
}
- void removeService(PackageParser.Service s) {
+ void removeService(ParsedService s) {
mServices.remove(s.getComponentName());
if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " " + (s.info.nonLocalizedLabel != null
- ? s.info.nonLocalizedLabel : s.info.name) + ":");
- Log.v(TAG, " Class=" + s.info.name);
+ Log.v(TAG, " " + (s.nonLocalizedLabel != null
+ ? s.nonLocalizedLabel : s.getName()) + ":");
+ Log.v(TAG, " Class=" + s.getName());
}
final int intentsSize = s.intents.size();
int j;
for (j = 0; j < intentsSize; j++) {
- PackageParser.ServiceIntentInfo intent = s.intents.get(j);
+ ParsedServiceIntentInfo intent = s.intents.get(j);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
@@ -1685,12 +1826,11 @@ public class ComponentResolver {
@Override
protected boolean allowFilterResult(
- PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
- ServiceInfo filterSi = filter.service.info;
+ ParsedServiceIntentInfo filter, List<ResolveInfo> dest) {
for (int i = dest.size() - 1; i >= 0; --i) {
ServiceInfo destAi = dest.get(i).serviceInfo;
- if (destAi.name == filterSi.name
- && destAi.packageName == filterSi.packageName) {
+ if (Objects.equals(destAi.name, filter.getClassName())
+ && Objects.equals(destAi.packageName, filter.getPackageName())) {
return false;
}
}
@@ -1698,48 +1838,69 @@ public class ComponentResolver {
}
@Override
- protected PackageParser.ServiceIntentInfo[] newArray(int size) {
- return new PackageParser.ServiceIntentInfo[size];
+ protected ParsedServiceIntentInfo[] newArray(int size) {
+ return new ParsedServiceIntentInfo[size];
}
@Override
- protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
+ protected boolean isFilterStopped(ParsedServiceIntentInfo filter, int userId) {
if (!sUserManager.exists(userId)) return true;
- PackageParser.Package p = filter.service.owner;
- if (p != null) {
- PackageSetting ps = (PackageSetting) p.mExtras;
- if (ps != null) {
- // System apps are never considered stopped for purposes of
- // filtering, because there may be no way for the user to
- // actually re-launch them.
- return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
- && ps.getStopped(userId);
- }
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg == null) {
+ return false;
}
- return false;
+
+ PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ filter.getPackageName());
+ if (ps == null) {
+ return false;
+ }
+
+ // System apps are never considered stopped for purposes of
+ // filtering, because there may be no way for the user to
+ // actually re-launch them.
+ return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+ && ps.getStopped(userId);
}
@Override
protected boolean isPackageForFilter(String packageName,
- PackageParser.ServiceIntentInfo info) {
- return packageName.equals(info.service.owner.packageName);
+ ParsedServiceIntentInfo info) {
+ return packageName.equals(info.getPackageName());
}
@Override
- protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
+ protected ResolveInfo newResult(ParsedServiceIntentInfo filter,
int match, int userId) {
if (!sUserManager.exists(userId)) return null;
- final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo) filter;
- if (!sPackageManagerInternal.isEnabledAndMatches(info.service.info, mFlags, userId)) {
+
+ ParsedService service = null;
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg != null && pkg.getServices() != null) {
+ for (ParsedService parsedService : pkg.getServices()) {
+ if (Objects.equals(parsedService.className, filter.getClassName())) {
+ service = parsedService;
+ }
+ }
+ }
+
+ if (service == null) {
+ return null;
+ }
+
+ if (!sPackageManagerInternal.isEnabledAndMatches(service, mFlags, userId)) {
return null;
}
- final PackageParser.Service service = info.service;
- PackageSetting ps = (PackageSetting) service.owner.mExtras;
+
+ PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+ filter.getPackageName());
if (ps == null) {
return null;
}
final PackageUserState userState = ps.readUserState(userId);
- ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
+ ServiceInfo si = PackageInfoUtils.generateServiceInfo(pkg, service, mFlags,
userState, userId);
if (si == null) {
return null;
@@ -1749,7 +1910,7 @@ public class ComponentResolver {
final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to ephemeral apps
if (matchVisibleToInstantApp
- && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+ && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
return null;
}
// throw out ephemeral filters if we're not explicitly requesting them
@@ -1766,13 +1927,13 @@ public class ComponentResolver {
if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = filter;
}
- res.priority = info.getPriority();
- res.preferredOrder = service.owner.mPreferredOrder;
+ res.priority = filter.getPriority();
+ res.preferredOrder = pkg.getPreferredOrder();
res.match = match;
- res.isDefault = info.hasDefault;
- res.labelRes = info.labelRes;
- res.nonLocalizedLabel = info.nonLocalizedLabel;
- res.icon = info.icon;
+ res.isDefault = filter.hasDefault;
+ res.labelRes = filter.labelRes;
+ res.nonLocalizedLabel = filter.nonLocalizedLabel;
+ res.icon = filter.icon;
res.system = res.serviceInfo.applicationInfo.isSystemApp();
return res;
}
@@ -1784,31 +1945,42 @@ public class ComponentResolver {
@Override
protected void dumpFilter(PrintWriter out, String prefix,
- PackageParser.ServiceIntentInfo filter) {
+ ParsedServiceIntentInfo filter) {
+ ParsedService service = null;
+
+ AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+ if (pkg != null && pkg.getServices() != null) {
+ for (ParsedService parsedService : pkg.getServices()) {
+ if (Objects.equals(parsedService.className, filter.getClassName())) {
+ service = parsedService;
+ }
+ }
+ }
+
out.print(prefix);
- out.print(Integer.toHexString(System.identityHashCode(filter.service)));
+ out.print(Integer.toHexString(System.identityHashCode(service)));
out.print(' ');
- filter.service.printComponentShortName(out);
+ ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
out.print(" filter ");
out.print(Integer.toHexString(System.identityHashCode(filter)));
- if (filter.service.info.permission != null) {
- out.print(" permission "); out.println(filter.service.info.permission);
+ if (service != null && service.getPermission() != null) {
+ out.print(" permission "); out.println(service.getPermission());
} else {
out.println();
}
}
@Override
- protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) {
- return filter.service;
+ protected Object filterToLabel(ParsedServiceIntentInfo filter) {
+ return filter;
}
protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
- final PackageParser.Service service = (PackageParser.Service) label;
+ final ParsedServiceIntentInfo service = (ParsedServiceIntentInfo) label;
out.print(prefix);
out.print(Integer.toHexString(System.identityHashCode(service)));
out.print(' ');
- service.printComponentShortName(out);
+ ComponentName.printShortString(out, service.getPackageName(), service.getClassName());
if (count > 1) {
out.print(" ("); out.print(count); out.print(" filters)");
}
@@ -1816,7 +1988,7 @@ public class ComponentResolver {
}
// Keys are String (activity class name), values are Activity.
- private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>();
+ private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>();
private int mFlags;
}
@@ -1905,7 +2077,7 @@ public class ComponentResolver {
/** Generic to create an {@link Iterator} for a data type */
static class IterGenerator<E> {
- public Iterator<E> generate(ActivityIntentInfo info) {
+ public Iterator<E> generate(ParsedActivityIntentInfo info) {
return null;
}
}
@@ -1913,7 +2085,7 @@ public class ComponentResolver {
/** Create an {@link Iterator} for intent actions */
static class ActionIterGenerator extends IterGenerator<String> {
@Override
- public Iterator<String> generate(ActivityIntentInfo info) {
+ public Iterator<String> generate(ParsedActivityIntentInfo info) {
return info.actionsIterator();
}
}
@@ -1921,7 +2093,7 @@ public class ComponentResolver {
/** Create an {@link Iterator} for intent categories */
static class CategoriesIterGenerator extends IterGenerator<String> {
@Override
- public Iterator<String> generate(ActivityIntentInfo info) {
+ public Iterator<String> generate(ParsedActivityIntentInfo info) {
return info.categoriesIterator();
}
}
@@ -1929,7 +2101,7 @@ public class ComponentResolver {
/** Create an {@link Iterator} for intent schemes */
static class SchemesIterGenerator extends IterGenerator<String> {
@Override
- public Iterator<String> generate(ActivityIntentInfo info) {
+ public Iterator<String> generate(ParsedActivityIntentInfo info) {
return info.schemesIterator();
}
}
@@ -1937,9 +2109,39 @@ public class ComponentResolver {
/** Create an {@link Iterator} for intent authorities */
static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
@Override
- public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
+ public Iterator<IntentFilter.AuthorityEntry> generate(ParsedActivityIntentInfo info) {
return info.authoritiesIterator();
}
}
+ // TODO(b/135203078): Document or remove this if possible.
+ class EffectiveProvider extends ParsedProvider {
+
+ private String mEffectiveAuthority;
+ private boolean mEffectiveSyncable;
+
+ public EffectiveProvider(ParsedProvider parsedProvider) {
+ this.setFrom(parsedProvider);
+ this.mEffectiveAuthority = parsedProvider.getAuthority();
+ this.mEffectiveSyncable = parsedProvider.isSyncable();
+ }
+
+ public void setEffectiveAuthority(String authority) {
+ this.mEffectiveAuthority = authority;
+ }
+
+ public void setEffectiveSyncable(boolean syncable) {
+ this.mEffectiveSyncable = syncable;
+ }
+
+ @Override
+ public String getAuthority() {
+ return mEffectiveAuthority;
+ }
+
+ @Override
+ public boolean isSyncable() {
+ return mEffectiveSyncable;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 9e04c4b69bd0..ffcd6cf8603c 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -20,9 +20,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageInfoUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -137,7 +140,7 @@ class InstantAppRegistry {
public byte[] getInstantAppCookieLPw(@NonNull String packageName,
@UserIdInt int userId) {
// Only installed packages can get their own cookie
- PackageParser.Package pkg = mService.mPackages.get(packageName);
+ AndroidPackage pkg = mService.mPackages.get(packageName);
if (pkg == null) {
return null;
}
@@ -171,7 +174,7 @@ class InstantAppRegistry {
}
// Only an installed package can set its own cookie
- PackageParser.Package pkg = mService.mPackages.get(packageName);
+ AndroidPackage pkg = mService.mPackages.get(packageName);
if (pkg == null) {
return false;
}
@@ -264,15 +267,15 @@ class InstantAppRegistry {
}
@GuardedBy("mService.mLock")
- public void onPackageInstalledLPw(@NonNull PackageParser.Package pkg, @NonNull int[] userIds) {
- PackageSetting ps = (PackageSetting) pkg.mExtras;
+ public void onPackageInstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) {
+ PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
if (ps == null) {
return;
}
for (int userId : userIds) {
// Ignore not installed apps
- if (mService.mPackages.get(pkg.packageName) == null || !ps.getInstalled(userId)) {
+ if (mService.mPackages.get(pkg.getPackageName()) == null || !ps.getInstalled(userId)) {
continue;
}
@@ -286,16 +289,16 @@ class InstantAppRegistry {
// Remove the in-memory state
removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) ->
- state.mInstantAppInfo.getPackageName().equals(pkg.packageName),
+ state.mInstantAppInfo.getPackageName().equals(pkg.getPackageName()),
userId);
// Remove the on-disk state except the cookie
- File instantAppDir = getInstantApplicationDir(pkg.packageName, userId);
+ File instantAppDir = getInstantApplicationDir(pkg.getPackageName(), userId);
new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete();
new File(instantAppDir, INSTANT_APP_ICON_FILE).delete();
// If app signature changed - wipe the cookie
- File currentCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+ File currentCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId);
if (currentCookieFile == null) {
continue;
}
@@ -310,7 +313,7 @@ class InstantAppRegistry {
// We prefer the modern computation procedure where all certs are taken
// into account but also allow the value from the old computation to avoid
// data loss.
- if (pkg.mSigningDetails.checkCapability(currentCookieSha256,
+ if (pkg.getSigningDetails().checkCapability(currentCookieSha256,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
return;
}
@@ -318,7 +321,7 @@ class InstantAppRegistry {
// For backwards compatibility we accept match based on any signature, since we may have
// recorded only the first for multiply-signed packages
final String[] signaturesSha256Digests =
- PackageUtils.computeSignaturesSha256Digests(pkg.mSigningDetails.signatures);
+ PackageUtils.computeSignaturesSha256Digests(pkg.getSigningDetails().signatures);
for (String s : signaturesSha256Digests) {
if (s.equals(currentCookieSha256)) {
return;
@@ -326,7 +329,7 @@ class InstantAppRegistry {
}
// Sorry, you are out of luck - different signatures - nuke data
- Slog.i(LOG_TAG, "Signature for package " + pkg.packageName
+ Slog.i(LOG_TAG, "Signature for package " + pkg.getPackageName()
+ " changed - dropping cookie");
// Make sure a pending write for the old signed app is cancelled
mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
@@ -335,15 +338,15 @@ class InstantAppRegistry {
}
@GuardedBy("mService.mLock")
- public void onPackageUninstalledLPw(@NonNull PackageParser.Package pkg,
+ public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg,
@NonNull int[] userIds) {
- PackageSetting ps = (PackageSetting) pkg.mExtras;
+ PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
if (ps == null) {
return;
}
for (int userId : userIds) {
- if (mService.mPackages.get(pkg.packageName) != null && ps.getInstalled(userId)) {
+ if (mService.mPackages.get(pkg.getPackageName()) != null && ps.getInstalled(userId)) {
continue;
}
@@ -353,7 +356,7 @@ class InstantAppRegistry {
removeInstantAppLPw(userId, ps.appId);
} else {
// Deleting an app prunes all instant state such as cookie
- deleteDir(getInstantApplicationDir(pkg.packageName, userId));
+ deleteDir(getInstantApplicationDir(pkg.getPackageName(), userId));
mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
removeAppLPw(userId, ps.appId);
}
@@ -487,7 +490,7 @@ class InstantAppRegistry {
}
@GuardedBy("mService.mLock")
- private void addUninstalledInstantAppLPw(@NonNull PackageParser.Package pkg,
+ private void addUninstalledInstantAppLPw(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
InstantAppInfo uninstalledApp = createInstantAppInfoForPackage(
pkg, userId, false);
@@ -511,14 +514,15 @@ class InstantAppRegistry {
writeInstantApplicationIconLPw(pkg, userId);
}
- private void writeInstantApplicationIconLPw(@NonNull PackageParser.Package pkg,
+ private void writeInstantApplicationIconLPw(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
- File appDir = getInstantApplicationDir(pkg.packageName, userId);
+ File appDir = getInstantApplicationDir(pkg.getPackageName(), userId);
if (!appDir.exists()) {
return;
}
- Drawable icon = pkg.applicationInfo.loadIcon(mService.mContext.getPackageManager());
+ // TODO(b/135203078): Remove toAppInfo call? Requires significant additions/changes to PM
+ Drawable icon = pkg.toAppInfoWithoutState().loadIcon(mService.mContext.getPackageManager());
final Bitmap bitmap;
if (icon instanceof BitmapDrawable) {
@@ -531,7 +535,7 @@ class InstantAppRegistry {
icon.draw(canvas);
}
- File iconFile = new File(getInstantApplicationDir(pkg.packageName, userId),
+ File iconFile = new File(getInstantApplicationDir(pkg.getPackageName(), userId),
INSTANT_APP_ICON_FILE);
try (FileOutputStream out = new FileOutputStream(iconFile)) {
@@ -690,14 +694,16 @@ class InstantAppRegistry {
final int packageCount = mService.mPackages.size();
for (int i = 0; i < packageCount; i++) {
- final PackageParser.Package pkg = mService.mPackages.valueAt(i);
+ final AndroidPackage pkg = mService.mPackages.valueAt(i);
if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) {
continue;
}
- if (!(pkg.mExtras instanceof PackageSetting)) {
+
+ final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+ if (ps == null) {
continue;
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+
boolean installedOnlyAsInstantApp = false;
for (int userId : allUsers) {
if (ps.getInstalled(userId)) {
@@ -713,14 +719,14 @@ class InstantAppRegistry {
if (packagesToDelete == null) {
packagesToDelete = new ArrayList<>();
}
- packagesToDelete.add(pkg.packageName);
+ packagesToDelete.add(pkg.getPackageName());
}
}
if (packagesToDelete != null) {
packagesToDelete.sort((String lhs, String rhs) -> {
- final PackageParser.Package lhsPkg = mService.mPackages.get(lhs);
- final PackageParser.Package rhsPkg = mService.mPackages.get(rhs);
+ final AndroidPackage lhsPkg = mService.mPackages.get(lhs);
+ final AndroidPackage rhsPkg = mService.mPackages.get(rhs);
if (lhsPkg == null && rhsPkg == null) {
return 0;
} else if (lhsPkg == null) {
@@ -735,18 +741,23 @@ class InstantAppRegistry {
rhsPkg.getLatestPackageUseTimeInMills()) {
return -1;
} else {
- if (lhsPkg.mExtras instanceof PackageSetting
- && rhsPkg.mExtras instanceof PackageSetting) {
- final PackageSetting lhsPs = (PackageSetting) lhsPkg.mExtras;
- final PackageSetting rhsPs = (PackageSetting) rhsPkg.mExtras;
- if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
- return 1;
- } else {
- return -1;
- }
- } else {
+ final PackageSetting lhsPs = mService.getPackageSetting(
+ lhsPkg.getPackageName());
+ if (lhsPs == null) {
+ return 0;
+ }
+
+ final PackageSetting rhsPs = mService.getPackageSetting(
+ rhsPkg.getPackageName());
+ if (rhsPs == null) {
return 0;
}
+
+ if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
+ return 1;
+ } else {
+ return -1;
+ }
}
}
});
@@ -818,8 +829,8 @@ class InstantAppRegistry {
final int packageCount = mService.mPackages.size();
for (int i = 0; i < packageCount; i++) {
- final PackageParser.Package pkg = mService.mPackages.valueAt(i);
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final AndroidPackage pkg = mService.mPackages.valueAt(i);
+ final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
if (ps == null || !ps.getInstantApp(userId)) {
continue;
}
@@ -839,9 +850,9 @@ class InstantAppRegistry {
private @NonNull
InstantAppInfo createInstantAppInfoForPackage(
- @NonNull PackageParser.Package pkg, @UserIdInt int userId,
+ @NonNull AndroidPackage pkg, @UserIdInt int userId,
boolean addApplicationInfo) {
- PackageSetting ps = (PackageSetting) pkg.mExtras;
+ PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
if (ps == null) {
return null;
}
@@ -849,19 +860,23 @@ class InstantAppRegistry {
return null;
}
- String[] requestedPermissions = new String[pkg.requestedPermissions.size()];
- pkg.requestedPermissions.toArray(requestedPermissions);
+ String[] requestedPermissions = new String[pkg.getRequestedPermissions().size()];
+ pkg.getRequestedPermissions().toArray(requestedPermissions);
Set<String> permissions = ps.getPermissionsState().getPermissions(userId);
String[] grantedPermissions = new String[permissions.size()];
permissions.toArray(grantedPermissions);
+ // TODO(b/135203078): This may be broken due to inner mutability problems that were broken
+ // as part of moving to PackageInfoUtils. Flags couldn't be determined.
+ ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(ps.pkg, 0,
+ ps.readUserState(userId), userId);
if (addApplicationInfo) {
- return new InstantAppInfo(pkg.applicationInfo,
+ return new InstantAppInfo(appInfo,
requestedPermissions, grantedPermissions);
} else {
- return new InstantAppInfo(pkg.applicationInfo.packageName,
- pkg.applicationInfo.loadLabel(mService.mContext.getPackageManager()),
+ return new InstantAppInfo(appInfo.packageName,
+ appInfo.loadLabel(mService.mContext.getPackageManager()),
requestedPermissions, grantedPermissions);
}
}
@@ -887,10 +902,10 @@ class InstantAppRegistry {
return uninstalledApps;
}
- private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg,
+ private void propagateInstantAppPermissionsIfNeeded(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo(
- pkg.packageName, userId);
+ pkg.getPackageName(), userId);
if (appInfo == null) {
return;
}
@@ -902,8 +917,10 @@ class InstantAppRegistry {
for (String grantedPermission : appInfo.getGrantedPermissions()) {
final boolean propagatePermission =
mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
- if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) {
- mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId);
+ if (propagatePermission && pkg.getRequestedPermissions().contains(
+ grantedPermission)) {
+ mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission,
+ userId);
}
}
} finally {
@@ -1188,18 +1205,19 @@ class InstantAppRegistry {
super(looper);
}
- public void schedulePersistLPw(@UserIdInt int userId, @NonNull PackageParser.Package pkg,
+ public void schedulePersistLPw(@UserIdInt int userId, @NonNull AndroidPackage pkg,
@NonNull byte[] cookie) {
// Before we used only the first signature to compute the SHA 256 but some
// apps could be singed by multiple certs and the cert order is undefined.
// We prefer the modern computation procedure where all certs are taken
// into account and delete the file derived via the legacy hash computation.
- File newCookieFile = computeInstantCookieFile(pkg.packageName,
- PackageUtils.computeSignaturesSha256Digest(pkg.mSigningDetails.signatures), userId);
- if (!pkg.mSigningDetails.hasSignatures()) {
+ File newCookieFile = computeInstantCookieFile(pkg.getPackageName(),
+ PackageUtils.computeSignaturesSha256Digest(pkg.getSigningDetails().signatures),
+ userId);
+ if (!pkg.getSigningDetails().hasSignatures()) {
Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!");
}
- File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+ File oldCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId);
if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) {
oldCookieFile.delete();
}
@@ -1209,12 +1227,12 @@ class InstantAppRegistry {
PERSIST_COOKIE_DELAY_MILLIS);
}
- public @Nullable byte[] getPendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
+ public @Nullable byte[] getPendingPersistCookieLPr(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
ArrayMap<String, SomeArgs> pendingWorkForUser =
mPendingPersistCookies.get(userId);
if (pendingWorkForUser != null) {
- SomeArgs state = pendingWorkForUser.get(pkg.packageName);
+ SomeArgs state = pendingWorkForUser.get(pkg.getPackageName());
if (state != null) {
return (byte[]) state.arg1;
}
@@ -1222,7 +1240,7 @@ class InstantAppRegistry {
return null;
}
- public void cancelPendingPersistLPw(@NonNull PackageParser.Package pkg,
+ public void cancelPendingPersistLPw(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
removeMessages(userId, pkg);
SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
@@ -1232,7 +1250,7 @@ class InstantAppRegistry {
}
private void addPendingPersistCookieLPw(@UserIdInt int userId,
- @NonNull PackageParser.Package pkg, @NonNull byte[] cookie,
+ @NonNull AndroidPackage pkg, @NonNull byte[] cookie,
@NonNull File cookieFile) {
ArrayMap<String, SomeArgs> pendingWorkForUser =
mPendingPersistCookies.get(userId);
@@ -1243,16 +1261,16 @@ class InstantAppRegistry {
SomeArgs args = SomeArgs.obtain();
args.arg1 = cookie;
args.arg2 = cookieFile;
- pendingWorkForUser.put(pkg.packageName, args);
+ pendingWorkForUser.put(pkg.getPackageName(), args);
}
- private SomeArgs removePendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
+ private SomeArgs removePendingPersistCookieLPr(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
ArrayMap<String, SomeArgs> pendingWorkForUser =
mPendingPersistCookies.get(userId);
SomeArgs state = null;
if (pendingWorkForUser != null) {
- state = pendingWorkForUser.remove(pkg.packageName);
+ state = pendingWorkForUser.remove(pkg.getPackageName());
if (pendingWorkForUser.isEmpty()) {
mPendingPersistCookies.remove(userId);
}
@@ -1263,7 +1281,7 @@ class InstantAppRegistry {
@Override
public void handleMessage(Message message) {
int userId = message.what;
- PackageParser.Package pkg = (PackageParser.Package) message.obj;
+ AndroidPackage pkg = (AndroidPackage) message.obj;
SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
if (state == null) {
return;
@@ -1271,7 +1289,7 @@ class InstantAppRegistry {
byte[] cookie = (byte[]) state.arg1;
File cookieFile = (File) state.arg2;
state.recycle();
- persistInstantApplicationCookie(cookie, pkg.packageName, cookieFile, userId);
+ persistInstantApplicationCookie(cookie, pkg.getPackageName(), cookieFile, userId);
}
}
}
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index ec48713b0874..0a065eba4309 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -16,7 +16,7 @@
package com.android.server.pm;
-import android.content.pm.ApplicationInfo;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -35,30 +35,16 @@ import java.util.List;
public class InstructionSets {
private static final String PREFERRED_INSTRUCTION_SET =
VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
- public static String[] getAppDexInstructionSets(ApplicationInfo info) {
- if (info.primaryCpuAbi != null) {
- if (info.secondaryCpuAbi != null) {
- return new String[] {
- VMRuntime.getInstructionSet(info.primaryCpuAbi),
- VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
- } else {
- return new String[] {
- VMRuntime.getInstructionSet(info.primaryCpuAbi) };
- }
- }
- return new String[] { getPreferredInstructionSet() };
- }
-
- public static String[] getAppDexInstructionSets(PackageSetting ps) {
- if (ps.primaryCpuAbiString != null) {
- if (ps.secondaryCpuAbiString != null) {
+ public static String[] getAppDexInstructionSets(String primaryCpuAbi, String secondaryCpuAbi) {
+ if (primaryCpuAbi != null) {
+ if (secondaryCpuAbi != null) {
return new String[] {
- VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
- VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
+ VMRuntime.getInstructionSet(primaryCpuAbi),
+ VMRuntime.getInstructionSet(secondaryCpuAbi) };
} else {
return new String[] {
- VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
+ VMRuntime.getInstructionSet(primaryCpuAbi) };
}
}
@@ -124,4 +110,12 @@ public class InstructionSets {
return VMRuntime.getInstructionSet(abis.primary);
}
+ public static String getPrimaryInstructionSet(AndroidPackage pkg) {
+ if (pkg.getPrimaryCpuAbi() == null) {
+ return getPreferredInstructionSet();
+ }
+
+ return VMRuntime.getInstructionSet(pkg.getPrimaryCpuAbi());
+ }
+
}
diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
index a4e9d103b6da..c97d85df00ab 100644
--- a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
+++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
@@ -17,7 +17,7 @@
package com.android.server.pm;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils;
import android.util.ArraySet;
import android.util.Slog;
@@ -35,7 +35,7 @@ public class IntentFilterVerificationState {
private int mState;
- private ArrayList<PackageParser.ActivityIntentInfo> mFilters = new ArrayList<>();
+ private ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> mFilters = new ArrayList<>();
private ArraySet<String> mHosts = new ArraySet<>();
private int mUserId;
@@ -66,7 +66,7 @@ public class IntentFilterVerificationState {
setState(STATE_VERIFICATION_PENDING);
}
- public ArrayList<PackageParser.ActivityIntentInfo> getFilters() {
+ public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() {
return mFilters;
}
@@ -123,7 +123,7 @@ public class IntentFilterVerificationState {
return false;
}
- public void addFilter(PackageParser.ActivityIntentInfo filter) {
+ public void addFilter(ComponentParseUtils.ParsedActivityIntentInfo filter) {
mFilters.add(filter);
mHosts.addAll(filter.getHostsList());
}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 93d3b77511bc..70c0f8d98447 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -20,23 +20,26 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
-import com.android.internal.util.Preconditions;
import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
-import android.util.Slog;
import android.util.LongSparseArray;
+import android.util.Slog;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.security.PublicKey;
-import java.util.Set;
+import com.android.internal.util.Preconditions;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.PublicKey;
+import java.util.Map;
+import java.util.Set;
+
/*
* Manages system-wide KeySet state.
*/
@@ -182,33 +185,31 @@ public class KeySetManagerService {
*
* Returns true if the package can safely be added to the keyset metadata.
*/
- public void assertScannedPackageValid(PackageParser.Package pkg)
+ public void assertScannedPackageValid(AndroidPackage pkg)
throws PackageManagerException {
- if (pkg == null || pkg.packageName == null) {
+ if (pkg == null || pkg.getPackageName() == null) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Passed invalid package to keyset validation.");
}
- ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys;
+ ArraySet<PublicKey> signingKeys = pkg.getSigningDetails().publicKeys;
if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Package has invalid signing-key-set.");
}
- ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping;
+ Map<String, ArraySet<PublicKey>> definedMapping = pkg.getKeySetMapping();
if (definedMapping != null) {
if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Package has null defined key set.");
}
- int defMapSize = definedMapping.size();
- for (int i = 0; i < defMapSize; i++) {
- if (!(definedMapping.valueAt(i).size() > 0)
- || definedMapping.valueAt(i).contains(null)) {
+ for (ArraySet<PublicKey> value : definedMapping.values()) {
+ if (!(value.size() > 0) || value.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Package has null/no public keys for defined key-sets.");
}
}
}
- ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets;
+ Set<String> upgradeAliases = pkg.getUpgradeKeySets();
if (upgradeAliases != null) {
if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -217,17 +218,17 @@ public class KeySetManagerService {
}
}
- public void addScannedPackageLPw(PackageParser.Package pkg) {
+ public void addScannedPackageLPw(AndroidPackage pkg) {
Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms.");
- Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms.");
- PackageSetting ps = mPackages.get(pkg.packageName);
- Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
+ Preconditions.checkNotNull(pkg.getPackageName(), "Attempted to add null pkg to ksms.");
+ PackageSetting ps = mPackages.get(pkg.getPackageName());
+ Preconditions.checkNotNull(ps, "pkg: " + pkg.getPackageName()
+ "does not have a corresponding entry in mPackages.");
- addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys);
- if (pkg.mKeySetMapping != null) {
- addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
- if (pkg.mUpgradeKeySets != null) {
- addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets);
+ addSigningKeySetToPackageLPw(ps, pkg.getSigningDetails().publicKeys);
+ if (pkg.getKeySetMapping() != null) {
+ addDefinedKeySetsToPackageLPw(ps, pkg.getKeySetMapping());
+ if (pkg.getUpgradeKeySets() != null) {
+ addUpgradeKeySetsToPackageLPw(ps, pkg.getUpgradeKeySets());
}
}
}
@@ -280,15 +281,14 @@ public class KeySetManagerService {
* Remove any KeySets the package no longer defines.
*/
void addDefinedKeySetsToPackageLPw(PackageSetting pkg,
- ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
+ Map<String, ArraySet<PublicKey>> definedMapping) {
ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
/* add all of the newly defined KeySets */
- ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
- final int defMapSize = definedMapping.size();
- for (int i = 0; i < defMapSize; i++) {
- String alias = definedMapping.keyAt(i);
- ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
+ Map<String, Long> newKeySetAliases = new ArrayMap<>();
+ for (Map.Entry<String, ArraySet<PublicKey>> entry : definedMapping.entrySet()) {
+ String alias = entry.getKey();
+ ArraySet<PublicKey> pubKeys = entry.getValue();
if (alias != null && pubKeys != null && pubKeys.size() > 0) {
KeySetHandle ks = addKeySetLPw(pubKeys);
newKeySetAliases.put(alias, ks.getId());
@@ -313,12 +313,10 @@ public class KeySetManagerService {
* after all of the defined KeySets have been added.
*/
void addUpgradeKeySetsToPackageLPw(PackageSetting pkg,
- ArraySet<String> upgradeAliases) {
- final int uaSize = upgradeAliases.size();
- for (int i = 0; i < uaSize; i++) {
- pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
+ Set<String> upgradeAliases) {
+ for (String upgradeAlias : upgradeAliases) {
+ pkg.keySetData.addUpgradeKeySet(upgradeAlias);
}
- return;
}
/**
@@ -364,14 +362,14 @@ public class KeySetManagerService {
return true;
}
- public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
- PackageParser.Package newPkg) {
+ public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, AndroidPackage pkg) {
// Upgrade keysets are being used. Determine if new package has a superset of the
// required keys.
long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
for (int i = 0; i < upgradeKeySets.length; i++) {
Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
- if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) {
+ if (upgradeSet != null
+ && pkg.getSigningDetails().publicKeys.containsAll(upgradeSet)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index f7fd1b2ddb37..673e265787f3 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -40,13 +40,13 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
@@ -447,7 +447,7 @@ public class LauncherAppsService extends SystemService {
}
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
- final PackageParser.Package pkg = pmInt.getPackage(appInfo.packageName);
+ final AndroidPackage pkg = pmInt.getPackage(appInfo.packageName);
if (pkg == null) {
// Should not happen, but we shouldn't be failing if it does
return false;
@@ -458,8 +458,8 @@ public class LauncherAppsService extends SystemService {
appInfo.packageName);
}
- private boolean requestsPermissions(@NonNull PackageParser.Package pkg) {
- return !ArrayUtils.isEmpty(pkg.requestedPermissions);
+ private boolean requestsPermissions(@NonNull AndroidPackage pkg) {
+ return !ArrayUtils.isEmpty(pkg.getRequestedPermissions());
}
private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index d49ecdda679d..ae7a4a7b81f5 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -22,7 +22,7 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.IOtaDexopt;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -118,8 +118,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
if (mDexoptCommands != null) {
throw new IllegalStateException("already called prepare()");
}
- final List<PackageParser.Package> important;
- final List<PackageParser.Package> others;
+ final List<AndroidPackage> important;
+ final List<AndroidPackage> others;
synchronized (mPackageManagerService.mLock) {
// Important: the packages we need to run with ab-ota compiler-reason.
important = PackageManagerServiceUtils.getPackagesForDexopt(
@@ -133,12 +133,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
}
- for (PackageParser.Package p : important) {
+ for (AndroidPackage p : important) {
mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA));
}
- for (PackageParser.Package p : others) {
+ for (AndroidPackage p : others) {
// We assume here that there are no core apps left.
- if (p.coreApp) {
+ if (p.isCoreApp()) {
throw new IllegalStateException("Found a core app that's not important");
}
mDexoptCommands.addAll(
@@ -150,8 +150,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
if (spaceAvailable < BULK_DELETE_THRESHOLD) {
Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
+ PackageManagerServiceUtils.packagesToString(others));
- for (PackageParser.Package pkg : others) {
- mPackageManagerService.deleteOatArtifactsOfPackage(pkg.packageName);
+ for (AndroidPackage pkg : others) {
+ mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
}
}
long spaceAvailableNow = getAvailableSpace();
@@ -161,15 +161,15 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
if (DEBUG_DEXOPT) {
try {
// Output some data about the packages.
- PackageParser.Package lastUsed = Collections.max(important,
+ AndroidPackage lastUsed = Collections.max(important,
(pkg1, pkg2) -> Long.compare(
pkg1.getLatestForegroundPackageUseTimeInMills(),
pkg2.getLatestForegroundPackageUseTimeInMills()));
Log.d(TAG, "A/B OTA: lastUsed time = "
+ lastUsed.getLatestForegroundPackageUseTimeInMills());
Log.d(TAG, "A/B OTA: deprioritized packages:");
- for (PackageParser.Package pkg : others) {
- Log.d(TAG, " " + pkg.packageName + " - "
+ for (AndroidPackage pkg : others) {
+ Log.d(TAG, " " + pkg.getPackageName() + " - "
+ pkg.getLatestForegroundPackageUseTimeInMills());
}
} catch (Exception ignored) {
@@ -262,7 +262,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
/**
* Generate all dexopt commands for the given package.
*/
- private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg,
+ private synchronized List<String> generatePackageDexopts(AndroidPackage pkg,
int compilationReason) {
// Intercept and collect dexopt requests
final List<String> commands = new ArrayList<String>();
@@ -336,8 +336,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
optimizer.performDexOpt(pkg,
null /* ISAs */,
null /* CompilerStats.PackageStats */,
- mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
- new DexoptOptions(pkg.packageName, compilationReason,
+ mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(
+ pkg.getPackageName()),
+ new DexoptOptions(pkg.getPackageName(), compilationReason,
DexoptOptions.DEXOPT_BOOT_COMPLETE));
return commands;
@@ -359,10 +360,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
}
// Look into all packages.
- Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
+ Collection<AndroidPackage> pkgs = mPackageManagerService.getPackages();
int packagePaths = 0;
int pathsSuccessful = 0;
- for (PackageParser.Package pkg : pkgs) {
+ for (AndroidPackage pkg : pkgs) {
if (pkg == null) {
continue;
}
@@ -371,27 +372,28 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
continue;
}
- if (pkg.codePath == null) {
+ if (pkg.getCodePath() == null) {
Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
continue;
}
// If the path is in /system, /vendor, /product or /system_ext, ignore. It will
// have been ota-dexopted into /data/ota and moved into the dalvik-cache already.
- if (pkg.codePath.startsWith("/system")
- || pkg.codePath.startsWith("/vendor")
- || pkg.codePath.startsWith("/product")
- || pkg.codePath.startsWith("/system_ext")) {
+ if (pkg.getCodePath().startsWith("/system")
+ || pkg.getCodePath().startsWith("/vendor")
+ || pkg.getCodePath().startsWith("/product")
+ || pkg.getCodePath().startsWith("/system_ext")) {
continue;
}
- final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+ final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+ pkg.getSecondaryCpuAbi());
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (String path : paths) {
- String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
- getAbsolutePath();
+ String oatDir = PackageDexOptimizer.getOatDir(
+ new File(pkg.getCodePath())).getAbsolutePath();
// TODO: Check first whether there is an artifact, to save the roundtrip time.
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index c21d0cf54d91..d7c161cc1a86 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -17,7 +17,8 @@
package com.android.server.pm;
import android.annotation.Nullable;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
@@ -25,21 +26,21 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
import java.util.Set;
+// TODO: Move to .parsing sub-package
@VisibleForTesting
public interface PackageAbiHelper {
/**
* Derive and get the location of native libraries for the given package,
* which varies depending on where and how the package was installed.
*/
- NativeLibraryPaths getNativeLibraryPaths(
- PackageParser.Package pkg, File appLib32InstallDir);
+ NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, File appLib32InstallDir);
/**
* Calculate the abis for a bundled app. These can uniquely be determined from the contents of
* the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
* validate any of this information, and instead assume that the system was built sensibly.
*/
- Abis getBundledAppAbis(PackageParser.Package pkg);
+ Abis getBundledAppAbis(AndroidPackage pkg);
/**
* Derive the ABI of a non-system package located at {@code pkg}. This information
@@ -48,7 +49,7 @@ public interface PackageAbiHelper {
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
Pair<Abis, NativeLibraryPaths> derivePackageAbi(
- PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+ AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
throws PackageManagerException;
/**
@@ -69,11 +70,11 @@ public interface PackageAbiHelper {
*/
@Nullable
String getAdjustedAbiForSharedUser(
- Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+ Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage);
/**
* The native library paths and related properties that should be set on a
- * {@link android.content.pm.PackageParser.Package}.
+ * {@link ParsedPackage}.
*/
final class NativeLibraryPaths {
public final String nativeLibraryRootDir;
@@ -91,11 +92,11 @@ public interface PackageAbiHelper {
this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
}
- public void applyTo(PackageParser.Package pkg) {
- pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
- pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
- pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
- pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+ public void applyTo(ParsedPackage pkg) {
+ pkg.setNativeLibraryRootDir(nativeLibraryRootDir)
+ .setNativeLibraryRootRequiresIsa(nativeLibraryRootRequiresIsa)
+ .setNativeLibraryDir(nativeLibraryDir)
+ .setSecondaryNativeLibraryDir(secondaryNativeLibraryDir);
}
}
@@ -112,13 +113,13 @@ public interface PackageAbiHelper {
this.secondary = secondary;
}
- Abis(PackageParser.Package pkg) {
- this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
+ Abis(AndroidPackage pkg) {
+ this(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi());
}
- public void applyTo(PackageParser.Package pkg) {
- pkg.applicationInfo.primaryCpuAbi = primary;
- pkg.applicationInfo.secondaryCpuAbi = secondary;
+ public void applyTo(ParsedPackage pkg) {
+ pkg.setPrimaryCpuAbi(primary)
+ .setSecondaryCpuAbi(secondary);
}
public void applyTo(PackageSetting pkgSetting) {
// pkgSetting might be null during rescan following uninstall of updates
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 7e478009b6b3..e550bae7484b 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -29,7 +29,7 @@ import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
@@ -132,10 +132,10 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
@Override
public NativeLibraryPaths getNativeLibraryPaths(
- PackageParser.Package pkg, File appLib32InstallDir) {
- return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
- pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
- pkg.applicationInfo.isUpdatedSystemApp());
+ AndroidPackage pkg, File appLib32InstallDir) {
+ return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.getCodePath(),
+ pkg.getBaseCodePath(), pkg.isSystemApp(),
+ pkg.isUpdatedSystemApp());
}
private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
@@ -202,12 +202,12 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
}
@Override
- public Abis getBundledAppAbis(PackageParser.Package pkg) {
- final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+ public Abis getBundledAppAbis(AndroidPackage pkg) {
+ final String apkName = deriveCodePathName(pkg.getCodePath());
// If "/system/lib64/apkname" exists, assume that is the per-package
// native library directory to use; otherwise use "/system/lib/apkname".
- final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+ final String apkRoot = calculateBundledApkRoot(pkg.getBaseCodePath());
final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
return abis;
}
@@ -220,8 +220,8 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
* {@code /oem} under which system libraries are installed.
* @param apkName the name of the installed package.
*/
- private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
- final File codeFile = new File(pkg.codePath);
+ private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) {
+ final File codeFile = new File(pkg.getCodePath());
final boolean has64BitLibs;
final boolean has32BitLibs;
@@ -273,7 +273,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
// ABI that's higher on the list, i.e, a device that's configured to prefer
// 64 bit apps will see a 64 bit primary ABI,
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) == 0) {
Slog.e(PackageManagerService.TAG,
"Package " + pkg + " has multiple bundled libs, but is not multiarch.");
}
@@ -294,14 +294,14 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
@Override
public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
- PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+ AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
throws PackageManagerException {
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
- PackageManagerService.sAppLib32InstallDir, pkg.codePath,
- pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
- pkg.applicationInfo.isUpdatedSystemApp());
+ PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(),
+ pkg.getBaseCodePath(), pkg.isSystemApp(),
+ pkg.isUpdatedSystemApp());
// We shouldn't attempt to extract libs from system app when it was not updated.
if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
@@ -310,7 +310,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
- final boolean onIncremental = isIncrementalPath(pkg.codePath);
+ final boolean onIncremental = isIncrementalPath(pkg.getCodePath());
String primaryCpuAbi = null;
String secondaryCpuAbi = null;
@@ -329,12 +329,13 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
// Null out the abis so that they can be recalculated.
primaryCpuAbi = null;
secondaryCpuAbi = null;
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0) {
// Warn if we've set an abiOverride for multi-lib packages..
// By definition, we need to copy both 32 and 64 bit libraries for
// such packages.
- if (pkg.cpuAbiOverride != null
- && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+ if (pkg.getCpuAbiOverride() != null
+ && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(
+ pkg.getCpuAbiOverride())) {
Slog.w(PackageManagerService.TAG,
"Ignoring abiOverride for multi arch application.");
}
@@ -409,7 +410,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
if (abi32 >= 0) {
final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
if (abi64 >= 0) {
- if (pkg.use32bitAbi) {
+ if (pkg.isUse32BitAbi()) {
secondaryCpuAbi = primaryCpuAbi;
primaryCpuAbi = abi;
} else {
@@ -482,9 +483,9 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
return new Pair<>(abis,
getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
- pkg.codePath, pkg.applicationInfo.sourceDir,
- pkg.applicationInfo.isSystemApp(),
- pkg.applicationInfo.isUpdatedSystemApp()));
+ pkg.getCodePath(), pkg.getBaseCodePath(),
+ pkg.isSystemApp(),
+ pkg.isUpdatedSystemApp()));
}
/**
@@ -503,11 +504,11 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
@Override
@Nullable
public String getAdjustedAbiForSharedUser(
- Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+ Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) {
String requiredInstructionSet = null;
- if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+ if (scannedPackage != null && scannedPackage.getPrimaryCpuAbi() != null) {
requiredInstructionSet = VMRuntime.getInstructionSet(
- scannedPackage.applicationInfo.primaryCpuAbi);
+ scannedPackage.getPrimaryCpuAbi());
}
PackageSetting requirer = null;
@@ -516,7 +517,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
// when scannedPackage is an update of an existing package. Without this check,
// we will never be able to change the ABI of any package belonging to a shared
// user, even if it's compatible with other packages.
- if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
+ if (scannedPackage != null && scannedPackage.getPackageName().equals(ps.name)) {
continue;
}
if (ps.primaryCpuAbiString == null) {
@@ -554,7 +555,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
} else {
// requirer == null implies that we're updating all ABIs in the set to
// match scannedPackage.
- adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+ adjustedAbi = scannedPackage.getPrimaryCpuAbi();
}
return adjustedAbi;
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4f7c8c8da4a9..2b422211077b 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -41,10 +41,10 @@ import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.AndroidPackage;
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -53,6 +53,7 @@ import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
@@ -109,9 +110,9 @@ public class PackageDexOptimizer {
this.mSystemReady = from.mSystemReady;
}
- static boolean canOptimizePackage(PackageParser.Package pkg) {
+ static boolean canOptimizePackage(AndroidPackage pkg) {
// We do not dexopt a package with no code.
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) == 0) {
return false;
}
@@ -125,18 +126,18 @@ public class PackageDexOptimizer {
* <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
* synchronized on {@link #mInstallLock}.
*/
- int performDexOpt(PackageParser.Package pkg,
+ int performDexOpt(AndroidPackage pkg,
String[] instructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
- if (pkg.applicationInfo.uid == -1) {
- throw new IllegalArgumentException("Dexopt for " + pkg.packageName
+ if (pkg.getUid() == -1) {
+ throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName()
+ " has invalid uid.");
}
if (!canOptimizePackage(pkg)) {
return DEX_OPT_SKIPPED;
}
synchronized (mInstallLock) {
- final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
+ final long acquireTime = acquireWakeLockLI(pkg.getUid());
try {
return performDexOptLI(pkg, instructionSets,
packageStats, packageUseInfo, options);
@@ -151,19 +152,20 @@ public class PackageDexOptimizer {
* It assumes the install lock is held.
*/
@GuardedBy("mInstallLock")
- private int performDexOptLI(PackageParser.Package pkg,
+ private int performDexOptLI(AndroidPackage pkg,
String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
- final List<SharedLibraryInfo> sharedLibraries = pkg.usesLibraryInfos;
+ final List<SharedLibraryInfo> sharedLibraries = pkg.getUsesLibraryInfos();
final String[] instructionSets = targetInstructionSets != null ?
- targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
+ targetInstructionSets : getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+ pkg.getSecondaryCpuAbi());
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
final List<String> paths = pkg.getAllCodePaths();
- int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
if (sharedGid == -1) {
- Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID "
- + pkg.applicationInfo.uid, new Throwable());
+ Slog.wtf(TAG, "Well this is awkward; package " + pkg.getAppInfoName() + " had UID "
+ + pkg.getUid(), new Throwable());
sharedGid = android.os.Process.NOBODY_UID;
}
@@ -171,21 +173,21 @@ public class PackageDexOptimizer {
// For each code path in the package, this array contains the class loader context that
// needs to be passed to dexopt in order to ensure correct optimizations.
boolean[] pathsWithCode = new boolean[paths.size()];
- pathsWithCode[0] = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ pathsWithCode[0] = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
for (int i = 1; i < paths.size(); i++) {
- pathsWithCode[i] = (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
}
String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts(
- pkg.applicationInfo, sharedLibraries, pathsWithCode);
+ pkg, sharedLibraries, pathsWithCode);
// Sanity check that we do not call dexopt with inconsistent data.
if (paths.size() != classLoaderContexts.length) {
- String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths();
+ String[] splitCodePaths = pkg.getSplitCodePaths();
throw new IllegalStateException("Inconsistent information "
+ "between PackageParser.Package and its ApplicationInfo. "
+ "pkg.getAllCodePaths=" + paths
- + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath()
- + " pkg.applicationInfo.getSplitCodePaths="
+ + " pkg.getBaseCodePath=" + pkg.getBaseCodePath()
+ + " pkg.getSplitCodePaths="
+ (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths)));
}
@@ -211,7 +213,8 @@ public class PackageDexOptimizer {
}
}
- String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
+ String profileName = ArtManager.getProfileName(
+ i == 0 ? null : pkg.getSplitNames()[i - 1]);
String dexMetadataPath = null;
if (options.isDexoptInstallWithDexMetadata()) {
@@ -222,7 +225,7 @@ public class PackageDexOptimizer {
final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
|| packageUseInfo.isUsedByOtherApps(path);
- final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
+ final String compilerFilter = getRealCompilerFilter(pkg,
options.getCompilerFilter(), isUsedByOtherApps);
final boolean profileUpdated = options.isCheckForProfileUpdates() &&
isProfileUpdated(pkg, sharedGid, profileName, compilerFilter);
@@ -257,7 +260,7 @@ public class PackageDexOptimizer {
* DEX_OPT_SKIPPED if the path does not need to be deopt-ed.
*/
@GuardedBy("mInstallLock")
- private int dexOptPath(PackageParser.Package pkg, String path, String isa,
+ private int dexOptPath(AndroidPackage pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
String profileName, String dexMetadataPath, int compilationReason) {
@@ -270,7 +273,7 @@ public class PackageDexOptimizer {
String oatDir = getPackageOatDirIfSupported(pkg);
Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
- + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa
+ + " pkg=" + pkg.getAppInfoPackageName() + " isa=" + isa
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
+ " targetFilter=" + compilerFilter + " oatDir=" + oatDir
+ " classLoaderContext=" + classLoaderContext);
@@ -281,9 +284,9 @@ public class PackageDexOptimizer {
// TODO: Consider adding 2 different APIs for primary and secondary dexopt.
// installd only uses downgrade flag for secondary dex files and ignores it for
// primary dex files.
- mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
- compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
- false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
+ mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir,
+ dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext,
+ pkg.getSeInfo(), false /* downgrade*/, pkg.getTargetSdkVersion(),
profileName, dexMetadataPath,
getAugmentedReasonName(compilationReason, dexMetadataPath != null));
@@ -446,9 +449,10 @@ public class PackageDexOptimizer {
/**
* Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}.
*/
- void dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg,
+ void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg,
PackageDexUsage.PackageUseInfo useInfo) {
- final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+ final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+ pkg.getSecondaryCpuAbi());
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
@@ -504,7 +508,7 @@ public class PackageDexOptimizer {
// When an app or priv app is configured to run out of box, only verify it.
if (info.isEmbeddedDexUsed()
|| (info.isPrivilegedApp()
- && DexManager.isPackageSelectedToRunOob(info.packageName))) {
+ && DexManager.isPackageSelectedToRunOob(info.packageName))) {
return "verify";
}
@@ -535,12 +539,43 @@ public class PackageDexOptimizer {
}
/**
- * Computes the dex flags that needs to be pass to installd for the given package and compiler
- * filter.
+ * Returns the compiler filter that should be used to optimize the package code.
+ * The target filter will be updated if the package code is used by other apps
+ * or if it has the safe mode flag set.
*/
- private int getDexFlags(PackageParser.Package pkg, String compilerFilter,
- DexoptOptions options) {
- return getDexFlags(pkg.applicationInfo, compilerFilter, options);
+ private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
+ boolean isUsedByOtherApps) {
+ // When an app or priv app is configured to run out of box, only verify it.
+ if (pkg.isEmbeddedDexUsed()
+ || (pkg.isPrivileged()
+ && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) {
+ return "verify";
+ }
+
+ // We force vmSafeMode on debuggable apps as well:
+ // - the runtime ignores their compiled code
+ // - they generally have lots of methods that could make the compiler used run
+ // out of memory (b/130828957)
+ // Note that forcing the compiler filter here applies to all compilations (even if they
+ // are done via adb shell commands). That's ok because right now the runtime will ignore
+ // the compiled code anyway. The alternative would have been to update either
+ // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages
+ // but that would have the downside of possibly producing a big odex files which would
+ // be ignored anyway.
+ boolean vmSafeModeOrDebuggable = ((pkg.getFlags() & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0)
+ || ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+
+ if (vmSafeModeOrDebuggable) {
+ return getSafeModeCompilerFilter(targetCompilerFilter);
+ }
+
+ if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
+ // If the dex files is used by other apps, apply the shared filter.
+ return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerService.REASON_SHARED);
+ }
+
+ return targetCompilerFilter;
}
private boolean isAppImageEnabled() {
@@ -548,7 +583,24 @@ public class PackageDexOptimizer {
}
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
- int flags = info.flags;
+ return getDexFlags(info.flags, info.getHiddenApiEnforcementPolicy(),
+ info.splitDependencies, info.requestsIsolatedSplitLoading(), compilerFilter,
+ options);
+ }
+ private int getDexFlags(AndroidPackage pkg, String compilerFilter,
+ DexoptOptions options) {
+ return getDexFlags(pkg.getFlags(), pkg.getHiddenApiEnforcementPolicy(),
+ pkg.getSplitDependencies(), pkg.requestsIsolatedSplitLoading(), compilerFilter,
+ options);
+ }
+
+ /**
+ * Computes the dex flags that needs to be pass to installd for the given package and compiler
+ * filter.
+ */
+ private int getDexFlags(int flags, int hiddenApiEnforcementPolicy,
+ SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
+ String compilerFilter, DexoptOptions options) {
boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
// Profile guide compiled oat files should not be public unles they are based
// on profiles from dex metadata archives.
@@ -560,7 +612,9 @@ public class PackageDexOptimizer {
// Some apps are executed with restrictions on hidden API usage. If this app is one
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
// TODO we should pass the actual flag value to dexopt, rather than assuming blacklist
- int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_DISABLED
+ // TODO(b/135203078): This flag is no longer set as part of AndroidPackage
+ // and may not be preserved
+ int hiddenApiFlag = hiddenApiEnforcementPolicy == HIDDEN_API_ENFORCEMENT_DISABLED
? 0
: DEXOPT_ENABLE_HIDDEN_API_CHECKS;
// Avoid generating CompactDex for modes that are latency critical.
@@ -578,8 +632,8 @@ public class PackageDexOptimizer {
// declare inter-split dependencies, then all the splits will be loaded in the base
// apk class loader (in the order of their definition, otherwise disable app images
// because they are unsupported for multiple class loaders. b/7269679
- boolean generateAppImage = isProfileGuidedFilter && (info.splitDependencies == null ||
- !info.requestsIsolatedSplitLoading()) && isAppImageEnabled();
+ boolean generateAppImage = isProfileGuidedFilter && (splitDependencies == null ||
+ !requestsIsolatedSplitLoading) && isAppImageEnabled();
int dexFlags =
(isPublic ? DEXOPT_PUBLIC : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
@@ -617,7 +671,7 @@ public class PackageDexOptimizer {
* current profile and the reference profile will be merged and subsequent calls
* may return a different result.
*/
- private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName,
+ private boolean isProfileUpdated(AndroidPackage pkg, int uid, String profileName,
String compilerFilter) {
// Check if we are allowed to merge and if the compiler filter is profile guided.
if (!isProfileGuidedCompilerFilter(compilerFilter)) {
@@ -625,7 +679,7 @@ public class PackageDexOptimizer {
}
// Merge profiles. It returns whether or not there was an updated in the profile info.
try {
- return mInstaller.mergeProfiles(uid, pkg.packageName, profileName);
+ return mInstaller.mergeProfiles(uid, pkg.getPackageName(), profileName);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to merge profiles", e);
}
@@ -645,11 +699,11 @@ public class PackageDexOptimizer {
* not needed or unsupported for the package.
*/
@Nullable
- private String getPackageOatDirIfSupported(PackageParser.Package pkg) {
+ private String getPackageOatDirIfSupported(AndroidPackage pkg) {
if (!pkg.canHaveOatDir()) {
return null;
}
- File codePath = new File(pkg.codePath);
+ File codePath = new File(pkg.getCodePath());
if (!codePath.isDirectory()) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 883baf7886af..518ec5085a5e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -66,6 +66,7 @@ import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.ApkLiteParseUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Binder;
@@ -1677,7 +1678,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
for (File addedFile : addedFiles) {
final ApkLite apk;
try {
- apk = PackageParser.parseApkLite(
+ apk = ApkLiteParseUtils.parseApkLite(
addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
@@ -1776,7 +1777,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
ApplicationInfo appInfo = pkgInfo.applicationInfo;
try {
existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
- existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
+ existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index 031b5ce3d5b9..10685b06716f 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -20,6 +20,8 @@ import android.util.ArrayMap;
import com.android.internal.util.ArrayUtils;
+import java.util.Map;
+
public class PackageKeySetData {
static final long KEYSET_UNASSIGNED = -1;
@@ -90,16 +92,13 @@ public class PackageKeySetData {
/*
* Replace defined keysets with new ones.
*/
- protected void setAliases(ArrayMap<String, Long> newAliases) {
+ protected void setAliases(Map<String, Long> newAliases) {
/* remove old aliases */
removeAllDefinedKeySets();
/* add new ones */
- final int newAliasSize = newAliases.size();
- for (int i = 0; i < newAliasSize; i++) {
- mKeySetAliases.put(newAliases.keyAt(i), newAliases.valueAt(i));;
- }
+ mKeySetAliases.putAll(newAliases);
}
protected void addDefinedKeySet(long ks, String alias) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fcaf5e1d912a..642b500c5e3c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -34,7 +34,6 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
@@ -160,7 +159,6 @@ import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
-import android.content.pm.PackageBackwardCompatibility;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
@@ -170,7 +168,6 @@ import android.content.pm.PackageManager.ModuleInfoFlags;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.ParseFlags;
@@ -195,6 +192,19 @@ import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
@@ -462,20 +472,19 @@ public class PackageManagerService extends IPackageManager.Stub
static final int SCAN_REQUIRE_KNOWN = 1 << 7;
static final int SCAN_MOVE = 1 << 8;
static final int SCAN_INITIAL = 1 << 9;
- static final int SCAN_CHECK_ONLY = 1 << 10;
- static final int SCAN_DONT_KILL_APP = 1 << 11;
- static final int SCAN_IGNORE_FROZEN = 1 << 12;
- static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13;
- static final int SCAN_AS_INSTANT_APP = 1 << 14;
- static final int SCAN_AS_FULL_APP = 1 << 15;
- static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16;
- static final int SCAN_AS_SYSTEM = 1 << 17;
- static final int SCAN_AS_PRIVILEGED = 1 << 18;
- static final int SCAN_AS_OEM = 1 << 19;
- static final int SCAN_AS_VENDOR = 1 << 20;
- static final int SCAN_AS_PRODUCT = 1 << 21;
- static final int SCAN_AS_SYSTEM_EXT = 1 << 22;
- static final int SCAN_AS_ODM = 1 << 23;
+ static final int SCAN_DONT_KILL_APP = 1 << 10;
+ static final int SCAN_IGNORE_FROZEN = 1 << 11;
+ static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12;
+ static final int SCAN_AS_INSTANT_APP = 1 << 13;
+ static final int SCAN_AS_FULL_APP = 1 << 14;
+ static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15;
+ static final int SCAN_AS_SYSTEM = 1 << 16;
+ static final int SCAN_AS_PRIVILEGED = 1 << 17;
+ static final int SCAN_AS_OEM = 1 << 18;
+ static final int SCAN_AS_VENDOR = 1 << 19;
+ static final int SCAN_AS_PRODUCT = 1 << 20;
+ static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
+ static final int SCAN_AS_ODM = 1 << 22;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
@@ -486,7 +495,6 @@ public class PackageManagerService extends IPackageManager.Stub
SCAN_REQUIRE_KNOWN,
SCAN_MOVE,
SCAN_INITIAL,
- SCAN_CHECK_ONLY,
SCAN_DONT_KILL_APP,
SCAN_IGNORE_FROZEN,
SCAN_FIRST_BOOT_OR_UPGRADE,
@@ -605,11 +613,19 @@ public class PackageManagerService extends IPackageManager.Stub
public static final int REASON_LAST = REASON_SHARED;
/**
- * Whether the package parser cache is enabled.
+ * The initial enabled state of the cache before other checks are done.
*/
private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
/**
+ * Whether to skip all other checks and force the cache to be enabled.
+ *
+ * Setting this to true will cause the cache to be named "debug" to avoid eviction from
+ * build fingerprint changes.
+ */
+ private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false;
+
+ /**
* Permissions required in order to receive instant application lifecycle broadcasts.
*/
private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
@@ -666,7 +682,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Keys are String (package name), values are Package.
@GuardedBy("mLock")
- final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();
+ final ArrayMap<String, AndroidPackage> mPackages = new ArrayMap<>();
// Keys are isolated uids and values are the uid of the application
// that created the isolated proccess.
@@ -751,7 +767,7 @@ public class PackageManagerService extends IPackageManager.Stub
* specificity (the more generic, the earlier in the list a partition appears).
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
- static final List<SystemPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
+ public static final List<SystemPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
Arrays.asList(
new SystemPartition(Environment.getRootDirectory(), 0 /* scanFlag */,
false /* hasOverlays */),
@@ -990,12 +1006,12 @@ public class PackageManagerService extends IPackageManager.Stub
new ArrayMap<>();
// Mapping from instrumentation class names to info about them.
- final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
+ final ArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation =
new ArrayMap<>();
// Packages whose data we have transfered into another package, thus
// should no longer exist.
- final ArraySet<String> mTransferedPackages = new ArraySet<>();
+ final ArraySet<String> mTransferredPackages = new ArraySet<>();
// Broadcast actions that are only available to the system.
@GuardedBy("mProtectedBroadcasts")
@@ -1039,13 +1055,13 @@ public class PackageManagerService extends IPackageManager.Stub
final ActivityInfo mResolveActivity = new ActivityInfo();
final ResolveInfo mResolveInfo = new ResolveInfo();
ComponentName mResolveComponentName;
- PackageParser.Package mPlatformPackage;
+ AndroidPackage mPlatformPackage;
ComponentName mCustomResolverComponentName;
boolean mResolverReplaced = false;
private final @Nullable ComponentName mIntentFilterVerifierComponent;
- private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier;
+ private final @Nullable IntentFilterVerifier<ParsedActivityIntentInfo> mIntentFilterVerifier;
private int mIntentFilterVerificationToken = 0;
@@ -1080,14 +1096,19 @@ public class PackageManagerService extends IPackageManager.Stub
private final IncrementalManager mIncrementalManager;
private static class IFVerificationParams {
- PackageParser.Package pkg;
+ String packageName;
+ boolean hasDomainUrls;
+ List<ParsedActivity> activities;
boolean replacing;
int userId;
int verifierUid;
- public IFVerificationParams(PackageParser.Package _pkg, boolean _replacing,
+ public IFVerificationParams(String packageName, boolean hasDomainUrls,
+ List<ParsedActivity> activities, boolean _replacing,
int _userId, int _verifierUid) {
- pkg = _pkg;
+ this.packageName = packageName;
+ this.hasDomainUrls = hasDomainUrls;
+ this.activities = activities;
replacing = _replacing;
userId = _userId;
verifierUid = _verifierUid;
@@ -1101,7 +1122,7 @@ public class PackageManagerService extends IPackageManager.Stub
void receiveVerificationResponse(int verificationId);
}
- private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
+ private class IntentVerifierProxy implements IntentFilterVerifier<ParsedActivityIntentInfo> {
private Context mContext;
private ComponentName mIntentFilterVerifierComponent;
private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>();
@@ -1126,11 +1147,11 @@ public class PackageManagerService extends IPackageManager.Stub
String packageName = ivs.getPackageName();
- ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+ ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
final int filterCount = filters.size();
ArraySet<String> domainsSet = new ArraySet<>();
for (int m=0; m<filterCount; m++) {
- PackageParser.ActivityIntentInfo filter = filters.get(m);
+ ParsedActivityIntentInfo filter = filters.get(m);
domainsSet.addAll(filter.getHostsList());
}
synchronized (mLock) {
@@ -1182,14 +1203,14 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean verified = ivs.isVerified();
- ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+ ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
final int count = filters.size();
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.i(TAG, "Received verification response " + verificationId
+ " for " + count + " filters, verified=" + verified);
}
for (int n=0; n<count; n++) {
- PackageParser.ActivityIntentInfo filter = filters.get(n);
+ ParsedActivityIntentInfo filter = filters.get(n);
filter.setVerified(verified);
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "IntentFilter " + filter.toString()
@@ -1302,7 +1323,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId,
- ActivityIntentInfo filter, String packageName) {
+ ParsedActivityIntentInfo filter, String packageName) {
if (!hasValidDomains(filter)) {
return false;
}
@@ -1331,7 +1352,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private static boolean hasValidDomains(ActivityIntentInfo filter) {
+ private static boolean hasValidDomains(ParsedActivityIntentInfo filter) {
return filter.hasCategory(Intent.CATEGORY_BROWSABLE)
&& (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
@@ -1418,6 +1439,7 @@ public class PackageManagerService extends IPackageManager.Stub
static final int ENABLE_ROLLBACK_TIMEOUT = 22;
static final int DEFERRED_NO_KILL_POST_DELETE = 23;
static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24;
+ static final int INTEGRITY_VERIFICATION_COMPLETE = 25;
static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
@@ -1582,6 +1604,10 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
+ if (data != null && data.res.freezer != null) {
+ data.res.freezer.close();
+ }
+
if (data != null && data.mPostInstallRunnable != null) {
data.mPostInstallRunnable.run();
} else if (data != null) {
@@ -1598,7 +1624,7 @@ public class PackageManagerService extends IPackageManager.Stub
final List<String> whitelistedRestrictedPermissions = ((args.installFlags
& PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
&& parentRes.pkg != null)
- ? parentRes.pkg.requestedPermissions
+ ? parentRes.pkg.getRequestedPermissions()
: args.whitelistedRestrictedPermissions;
// Handle the parent package
@@ -1742,10 +1768,14 @@ public class PackageManagerService extends IPackageManager.Stub
break;
}
+ case INTEGRITY_VERIFICATION_COMPLETE: {
+ // TODO: implement this case.
+ break;
+ }
case START_INTENT_FILTER_VERIFICATIONS: {
IFVerificationParams params = (IFVerificationParams) msg.obj;
- verifyIntentFiltersIfNeeded(params.userId, params.verifierUid,
- params.replacing, params.pkg);
+ verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, params.replacing,
+ params.packageName, params.hasDomainUrls, params.activities);
break;
}
case INTENT_FILTER_VERIFIED: {
@@ -1895,20 +1925,11 @@ public class PackageManagerService extends IPackageManager.Stub
? res.removedInfo.installerPackageName
: null;
- // If this is the first time we have child packages for a disabled privileged
- // app that had no children, we grant requested runtime permissions to the new
- // children if the parent on the system image had them already granted.
- if (res.pkg.parentPackage != null) {
- final int callingUid = Binder.getCallingUid();
- mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
- res.pkg, callingUid);
- }
-
synchronized (mLock) {
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
- final String packageName = res.pkg.applicationInfo.packageName;
+ final String packageName = res.pkg.getAppInfoPackageName();
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
@@ -1917,7 +1938,7 @@ public class PackageManagerService extends IPackageManager.Stub
int[] updateUserIds = EMPTY_INT_ARRAY;
int[] instantUserIds = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
- final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
+ final PackageSetting ps = getPackageSetting(res.pkg.getPackageName());
for (int newUser : res.newUsers) {
final boolean isInstantApp = ps.getInstantApp(newUser);
if (allNewUsers) {
@@ -1951,13 +1972,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Send installed broadcasts if the package is not a static shared lib.
- if (res.pkg.staticSharedLibName == null) {
- mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
+ if (res.pkg.getStaticSharedLibName() == null) {
+ mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(
+ res.pkg.getBaseCodePath());
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.uid);
- boolean isSystem = res.pkg.applicationInfo.isSystemApp();
+ boolean isSystem = res.pkg.isSystemApp();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
@@ -2035,30 +2057,30 @@ public class PackageManagerService extends IPackageManager.Stub
final StorageManager storage = mInjector.getStorageManager();
VolumeInfo volume =
storage.findVolumeByUuid(
- res.pkg.applicationInfo.storageUuid.toString());
+ res.pkg.getStorageUuid().toString());
int packageExternalStorageType =
getPackageExternalStorageType(volume, isExternal(res.pkg));
// If the package was installed externally, log it.
if (packageExternalStorageType != StorageEnums.UNKNOWN) {
StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
- packageExternalStorageType, res.pkg.packageName);
+ packageExternalStorageType, res.pkg.getPackageName());
}
}
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
}
- final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
+ final int[] uidArray = new int[]{res.pkg.getUid()};
ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
}
} else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
for (int i = 0; i < res.libraryConsumers.size(); i++) {
- PackageParser.Package pkg = res.libraryConsumers.get(i);
+ AndroidPackage pkg = res.libraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
- sendPackageChangedBroadcast(pkg.packageName, false /* dontKillApp */,
- new ArrayList<>(Collections.singletonList(pkg.packageName)),
- pkg.applicationInfo.uid, null);
+ sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
+ new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
+ pkg.getUid(), null);
}
}
@@ -2188,7 +2210,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 observer) {
- String packageName = info.pkg.packageName;
+ String packageName = info.pkg.getPackageName();
mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
@@ -2368,7 +2390,7 @@ public class PackageManagerService extends IPackageManager.Stub
injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
packageName -> {
synchronized (m.mInstallLock) {
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
final SharedUserSetting sharedUser;
synchronized (m.mLock) {
PackageSetting ps = m.mSettings.getPackageLPr(packageName);
@@ -2387,10 +2409,10 @@ public class PackageManagerService extends IPackageManager.Stub
final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
m.mInjector.getCompatibility());
- if (!newSeInfo.equals(pkg.applicationInfo.seInfo)) {
+ if (!newSeInfo.equals(pkg.getSeInfo())) {
Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
- + pkg.applicationInfo.seInfo + " to: " + newSeInfo);
- pkg.applicationInfo.seInfo = newSeInfo;
+ + pkg.getSeInfo() + " to: " + newSeInfo);
+ pkg.mutate().setSeInfo(newSeInfo);
m.prepareAppDataAfterInstallLIF(pkg);
}
}
@@ -2453,7 +2475,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
- static class SystemPartition {
+ public static class SystemPartition {
public final File folder;
public final int scanFlag;
public final File appFolder;
@@ -2783,11 +2805,11 @@ public class PackageManagerService extends IPackageManager.Stub
final List<String> stubSystemApps = new ArrayList<>();
if (!mOnlyCore) {
// do this first before mucking with mPackages for the "expecting better" case
- final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
+ final Iterator<AndroidPackage> pkgIterator = mPackages.values().iterator();
while (pkgIterator.hasNext()) {
- final PackageParser.Package pkg = pkgIterator.next();
- if (pkg.isStub) {
- stubSystemApps.add(pkg.packageName);
+ final AndroidPackage pkg = pkgIterator.next();
+ if (pkg.isStub()) {
+ stubSystemApps.add(pkg.getPackageName());
}
}
@@ -2806,7 +2828,7 @@ public class PackageManagerService extends IPackageManager.Stub
/*
* If the package is scanned, it's not erased.
*/
- final PackageParser.Package scannedPkg = mPackages.get(ps.name);
+ final AndroidPackage scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
@@ -2883,7 +2905,7 @@ public class PackageManagerService extends IPackageManager.Stub
// app completely. Otherwise, revoke their system privileges.
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
- final PackageParser.Package pkg = mPackages.get(packageName);
+ final AndroidPackage pkg = mPackages.get(packageName);
final String msg;
// remove from the disabled system list; do this first so any future
@@ -2909,7 +2931,7 @@ public class PackageManagerService extends IPackageManager.Stub
// special privileges
removePackageLI(pkg, true);
try {
- final File codePath = new File(pkg.applicationInfo.getCodePath());
+ final File codePath = new File(pkg.getAppInfoCodePath());
scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -3006,8 +3028,7 @@ public class PackageManagerService extends IPackageManager.Stub
mWellbeingPackage = getWellbeingPackageName();
mDocumenterPackage = getDocumenterPackageName();
- mConfiguratorPackage =
- mContext.getString(R.string.config_deviceConfiguratorPackageName);
+ mConfiguratorPackage = getDeviceConfiguratorPackageName();
mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mTelephonyPackages = getTelephonyPackageNames();
@@ -3105,7 +3126,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
int count = 0;
for (String pkgName : deferPackages) {
- PackageParser.Package pkg = null;
+ AndroidPackage pkg = null;
synchronized (mLock) {
PackageSetting ps = mSettings.getPackageLPr(pkgName);
if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
@@ -3205,12 +3226,12 @@ public class PackageManagerService extends IPackageManager.Stub
// Initialize InstantAppRegistry's Instant App list for all users.
final int[] userIds = UserManagerService.getInstance().getUserIds();
- for (PackageParser.Package pkg : mPackages.values()) {
+ for (AndroidPackage pkg : mPackages.values()) {
if (pkg.isSystem()) {
continue;
}
for (int userId : userIds) {
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
continue;
}
@@ -3297,7 +3318,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
// skip if the package isn't installed (?!); this should never happen
- final PackageParser.Package pkg = mPackages.get(packageName);
+ final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
systemStubPackageNames.remove(i);
continue;
@@ -3341,43 +3362,46 @@ public class PackageManagerService extends IPackageManager.Stub
* APK will be installed and the package will be disabled. To recover from this situation,
* the user will need to go into system settings and re-enable the package.
*/
- private boolean enableCompressedPackage(PackageParser.Package stubPkg) {
+ private boolean enableCompressedPackage(AndroidPackage stubPkg) {
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE;
synchronized (mInstallLock) {
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
try (PackageFreezer freezer =
- freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+ freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
synchronized (mLock) {
prepareAppDataAfterInstallLIF(pkg);
try {
- updateSharedLibrariesLocked(pkg, null, mPackages);
+ updateSharedLibrariesLocked(pkg, null,
+ Collections.unmodifiableMap(mPackages));
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
- mPermissionManager.updatePermissions(pkg.packageName, pkg);
+ mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
mSettings.writeLPr();
}
} catch (PackageManagerException e) {
// Whoops! Something went very wrong; roll back to the stub and disable the package
try (PackageFreezer freezer =
- freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+ freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
synchronized (mLock) {
// NOTE: Ensure the system package is enabled; even for a compressed stub.
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
}
- installPackageFromSystemLIF(stubPkg.codePath,
+ installPackageFromSystemLIF(stubPkg.getCodePath(),
null /*allUserHandles*/, null /*origUserHandles*/,
null /*origPermissionsState*/, true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
- Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme);
+ Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
+ pme);
} finally {
// Disable the package; the stub by itself is not runnable
synchronized (mLock) {
- final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+ final PackageSetting stubPs = mSettings.mPackages.get(
+ stubPkg.getPackageName());
if (stubPs != null) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
@@ -3389,31 +3413,33 @@ public class PackageManagerService extends IPackageManager.Stub
}
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- mDexManager.notifyPackageUpdated(pkg.packageName,
- pkg.baseCodePath, pkg.splitCodePaths);
+ mDexManager.notifyPackageUpdated(pkg.getPackageName(),
+ pkg.getBaseCodePath(), pkg.getSplitCodePaths());
}
return true;
}
- private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg,
+ private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags)
throws PackageManagerException {
if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName);
+ Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
}
// uncompress the binary to its eventual destination on /data
- final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath);
+ final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getCodePath());
if (scanFile == null) {
- throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath);
+ throw new PackageManagerException(
+ "Unable to decompress stub at " + stubPkg.getCodePath());
}
synchronized (mLock) {
- mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/);
+ mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
}
removePackageLI(stubPkg, true /*chatty*/);
try {
return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e);
+ Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
+ e);
// Remove the failed install
removeCodePathLI(scanFile);
throw e;
@@ -3496,18 +3522,20 @@ public class PackageManagerService extends IPackageManager.Stub
}
private static @Nullable File preparePackageParserCache() {
- if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
- return null;
- }
+ if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
+ if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
+ return null;
+ }
- // Disable package parsing on eng builds to allow for faster incremental development.
- if (Build.IS_ENG) {
- return null;
- }
+ // Disable package parsing on eng builds to allow for faster incremental development.
+ if (Build.IS_ENG) {
+ return null;
+ }
- if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
- Slog.i(TAG, "Disabling package parser cache due to system property.");
- return null;
+ if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
+ Slog.i(TAG, "Disabling package parser cache due to system property.");
+ return null;
+ }
}
// The base directory for the package parser cache lives under /data/system/.
@@ -3519,10 +3547,12 @@ public class PackageManagerService extends IPackageManager.Stub
// There are several items that need to be combined together to safely
// identify cached items. In particular, changing the value of certain
// feature flags should cause us to invalidate any caches.
- final String cacheName = SystemProperties.digestOf(
- "ro.build.fingerprint",
- StorageManager.PROP_ISOLATED_STORAGE,
- StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT);
+ final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
+ : SystemProperties.digestOf(
+ "ro.build.fingerprint",
+ StorageManager.PROP_ISOLATED_STORAGE,
+ StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT
+ );
// Reconcile cache directories, keeping only what we'd actually use.
for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -3846,7 +3876,7 @@ public class PackageManagerService extends IPackageManager.Stub
ArraySet<String> packages = systemConfig.getLinkedApps();
for (String packageName : packages) {
- PackageParser.Package pkg = mPackages.get(packageName);
+ AndroidPackage pkg = mPackages.get(packageName);
if (pkg != null) {
if (!pkg.isSystem()) {
Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>");
@@ -3854,13 +3884,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
ArraySet<String> domains = null;
- for (PackageParser.Activity a : pkg.activities) {
- for (ActivityIntentInfo filter : a.intents) {
- if (hasValidDomains(filter)) {
- if (domains == null) {
- domains = new ArraySet<>();
+ if (pkg.getActivities() != null) {
+ for (ParsedActivity a : pkg.getActivities()) {
+ for (ParsedActivityIntentInfo filter : a.intents) {
+ if (hasValidDomains(filter)) {
+ if (domains == null) {
+ domains = new ArraySet<>();
+ }
+ domains.addAll(filter.getHostsList());
}
- domains.addAll(filter.getHostsList());
}
}
}
@@ -3976,7 +4008,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final PackageUserState state = ps.readUserState(userId);
- PackageParser.Package p = ps.pkg;
+ AndroidPackage p = ps.pkg;
if (p != null) {
final PermissionsState permissionsState = ps.getPermissionsState();
@@ -3984,10 +4016,10 @@ public class PackageManagerService extends IPackageManager.Stub
final int[] gids = (flags & PackageManager.GET_GIDS) == 0
? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
// Compute granted permissions only if package has requested permissions
- final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
+ final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
? Collections.emptySet() : permissionsState.getPermissions(userId);
- PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
+ PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
if (packageInfo == null) {
@@ -4050,7 +4082,7 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Package " + packageName + " is currently frozen!");
}
- if (!userKeyUnlocked && !ps.pkg.applicationInfo.isEncryptionAware()) {
+ if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) {
throw new SecurityException("Package " + packageName + " is not encryption aware!");
}
}
@@ -4063,9 +4095,9 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "is package available");
synchronized (mLock) {
- PackageParser.Package p = mPackages.get(packageName);
+ AndroidPackage p = mPackages.get(packageName);
if (p != null) {
- final PackageSetting ps = (PackageSetting) p.mExtras;
+ final PackageSetting ps = getPackageSetting(p.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return false;
}
@@ -4130,21 +4162,22 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- PackageParser.Package p = mPackages.get(packageName);
+ AndroidPackage p = mPackages.get(packageName);
if (matchFactoryOnly && p != null && !isSystemApp(p)) {
return null;
}
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
- final PackageSetting ps = (PackageSetting) p.mExtras;
+ final PackageSetting ps = getPackageSetting(p.getPackageName());
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
- return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
+
+ return generatePackageInfo(ps, flags, userId);
}
if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -4180,34 +4213,34 @@ public class PackageManagerService extends IPackageManager.Stub
private boolean isComponentVisibleToInstantApp(
@Nullable ComponentName component, @ComponentType int type) {
if (type == TYPE_ACTIVITY) {
- final PackageParser.Activity activity = mComponentResolver.getActivity(component);
+ final ParsedActivity activity = mComponentResolver.getActivity(component);
if (activity == null) {
return false;
}
final boolean visibleToInstantApp =
- (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
final boolean explicitlyVisibleToInstantApp =
- (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+ (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
return visibleToInstantApp && explicitlyVisibleToInstantApp;
} else if (type == TYPE_RECEIVER) {
- final PackageParser.Activity activity = mComponentResolver.getReceiver(component);
+ final ParsedActivity activity = mComponentResolver.getReceiver(component);
if (activity == null) {
return false;
}
final boolean visibleToInstantApp =
- (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
final boolean explicitlyVisibleToInstantApp =
- (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+ (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
return visibleToInstantApp && !explicitlyVisibleToInstantApp;
} else if (type == TYPE_SERVICE) {
- final PackageParser.Service service = mComponentResolver.getService(component);
+ final ParsedService service = mComponentResolver.getService(component);
return service != null
- ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+ ? (service.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
: false;
} else if (type == TYPE_PROVIDER) {
- final PackageParser.Provider provider = mComponentResolver.getProvider(component);
+ final ParsedProvider provider = mComponentResolver.getProvider(component);
return provider != null
- ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+ ? (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
: false;
} else if (type == TYPE_UNKNOWN) {
return isComponentVisibleToInstantApp(component);
@@ -4251,16 +4284,16 @@ public class PackageManagerService extends IPackageManager.Stub
// request for a specific component; if it hasn't been explicitly exposed through
// property or instrumentation target, filter
if (component != null) {
- final PackageParser.Instrumentation instrumentation =
+ final ParsedInstrumentation instrumentation =
mInstrumentation.get(component);
if (instrumentation != null
- && isCallerSameApp(instrumentation.info.targetPackage, callingUid)) {
+ && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) {
return false;
}
return !isComponentVisibleToInstantApp(component, componentType);
}
// request for application; if no components have been explicitly exposed, filter
- return !ps.pkg.visibleToInstantApps;
+ return !ps.pkg.isVisibleToInstantApps();
}
if (ps.getInstantApp(userId)) {
// caller can see all components of all instant applications, don't filter
@@ -4309,12 +4342,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
// No package means no static lib as it is always on internal storage
- if (ps == null || ps.pkg == null || !ps.pkg.applicationInfo.isStaticSharedLibrary()) {
+ if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) {
return false;
}
- final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ps.pkg.staticSharedLibName,
- ps.pkg.staticSharedLibVersion);
+ final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
+ ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion());
if (libraryInfo == null) {
return false;
}
@@ -4336,7 +4369,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (index < 0) {
continue;
}
- if (uidPs.pkg.usesStaticLibrariesVersions[index] == libraryInfo.getLongVersion()) {
+ if (uidPs.pkg.getUsesStaticLibrariesVersions()[index]
+ == libraryInfo.getLongVersion()) {
return false;
}
}
@@ -4410,13 +4444,13 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
- final PackageParser.Package p = mPackages.get(packageName);
+ final AndroidPackage p = mPackages.get(packageName);
if (p != null && p.isMatch(flags)) {
- PackageSetting ps = (PackageSetting) p.mExtras;
+ PackageSetting ps = getPackageSetting(p.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return -1;
}
- return UserHandle.getUid(userId, p.applicationInfo.uid);
+ return UserHandle.getUid(userId, p.getUid());
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -4440,9 +4474,9 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
- final PackageParser.Package p = mPackages.get(packageName);
+ final AndroidPackage p = mPackages.get(packageName);
if (p != null && p.isMatch(flags)) {
- PackageSetting ps = (PackageSetting) p.mExtras;
+ PackageSetting ps = getPackageSetting(p.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return null;
}
@@ -4492,7 +4526,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
return null;
}
- ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
+ ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags,
ps.readUserState(userId), userId);
if (ai != null) {
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
@@ -4530,7 +4564,7 @@ public class PackageManagerService extends IPackageManager.Stub
packageName = resolveInternalPackageNameLPr(packageName,
PackageManager.VERSION_CODE_HIGHEST);
- PackageParser.Package p = mPackages.get(packageName);
+ AndroidPackage p = mPackages.get(packageName);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getApplicationInfo " + packageName
+ ": " + p);
@@ -4544,7 +4578,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
// Note: isEnabledLP() does not apply here - always return info
- ApplicationInfo ai = PackageParser.generateApplicationInfo(
+ ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(
p, flags, ps.readUserState(userId), userId);
if (ai != null) {
ai.packageName = resolveExternalPackageNameLPr(p);
@@ -4916,17 +4950,19 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
- PackageParser.Activity a = mComponentResolver.getActivity(component);
+ ParsedActivity a = mComponentResolver.getActivity(component);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
+
+ AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
+ if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
- return PackageParser.generateActivityInfo(
+ return PackageInfoUtils.generateActivityInfo(pkg,
a, flags, ps.readUserState(userId), userId);
}
if (mResolveComponentName.equals(component)) {
@@ -4963,7 +4999,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- PackageParser.Activity a = mComponentResolver.getActivity(component);
+ ParsedActivity a = mComponentResolver.getActivity(component);
if (a == null) {
return false;
}
@@ -4993,17 +5029,27 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get receiver info");
synchronized (mLock) {
- PackageParser.Activity a = mComponentResolver.getReceiver(component);
+ ParsedActivity a = mComponentResolver.getReceiver(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getReceiverInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
+
+ if (a == null) {
+ return null;
+ }
+
+ AndroidPackage pkg = mPackages.get(a.getPackageName());
+ if (pkg == null) {
+ return null;
+ }
+
+ if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_RECEIVER, userId)) {
return null;
}
- return PackageParser.generateActivityInfo(
+ return PackageInfoUtils.generateActivityInfo(pkg,
a, flags, ps.readUserState(userId), userId);
}
}
@@ -5182,13 +5228,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
// If the dependent is a static shared lib, use the public package name
String dependentPackageName = ps.name;
- if (ps.pkg != null && ps.pkg.applicationInfo.isStaticSharedLibrary()) {
- dependentPackageName = ps.pkg.manifestPackageName;
+ if (ps.pkg != null && ps.pkg.isStaticSharedLibrary()) {
+ dependentPackageName = ps.pkg.getManifestPackageName();
}
versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode));
} else if (ps.pkg != null) {
- if (ArrayUtils.contains(ps.pkg.usesLibraries, libName)
- || ArrayUtils.contains(ps.pkg.usesOptionalLibraries, libName)) {
+ if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName)
+ || ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) {
if (versionedPackages == null) {
versionedPackages = new ArrayList<>();
}
@@ -5208,17 +5254,22 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get service info");
synchronized (mLock) {
- PackageParser.Service s = mComponentResolver.getService(component);
+ ParsedService s = mComponentResolver.getService(component);
if (DEBUG_PACKAGE_INFO) Log.v(
- TAG, "getServiceInfo " + component + ": " + s);
- if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
+ TAG, "getServiceInfo " + component + ": " + s);
+ if (s == null) {
+ return null;
+ }
+
+ AndroidPackage pkg = mPackages.get(s.getPackageName());
+ if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_SERVICE, userId)) {
return null;
}
- return PackageParser.generateServiceInfo(
+ return PackageInfoUtils.generateServiceInfo(pkg,
s, flags, ps.readUserState(userId), userId);
}
}
@@ -5233,18 +5284,27 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get provider info");
synchronized (mLock) {
- PackageParser.Provider p = mComponentResolver.getProvider(component);
+ ParsedProvider p = mComponentResolver.getProvider(component);
if (DEBUG_PACKAGE_INFO) Log.v(
- TAG, "getProviderInfo " + component + ": " + p);
- if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
+ TAG, "getProviderInfo " + component + ": " + p);
+ if (p == null) {
+ return null;
+ }
+
+ AndroidPackage pkg = mPackages.get(p.getPackageName());
+ if (pkg == null) {
+ return null;
+ }
+
+ if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_PROVIDER, userId)) {
return null;
}
- return PackageParser.generateProviderInfo(
- p, flags, ps.readUserState(userId), userId);
+ PackageUserState state = ps.readUserState(userId);
+ return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId);
}
}
return null;
@@ -5502,21 +5562,21 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public int checkSignatures(String pkg1, String pkg2) {
synchronized (mLock) {
- final PackageParser.Package p1 = mPackages.get(pkg1);
- final PackageParser.Package p2 = mPackages.get(pkg2);
- if (p1 == null || p1.mExtras == null
- || p2 == null || p2.mExtras == null) {
+ final AndroidPackage p1 = mPackages.get(pkg1);
+ final AndroidPackage p2 = mPackages.get(pkg2);
+ final PackageSetting ps1 = p1 == null ? null : getPackageSetting(p1.getPackageName());
+ final PackageSetting ps2 = p2 == null ? null : getPackageSetting(p2.getPackageName());
+ if (p1 == null || ps1 == null || p2 == null || ps2 == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageSetting ps1 = (PackageSetting) p1.mExtras;
- final PackageSetting ps2 = (PackageSetting) p2.mExtras;
if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId)
|| shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
+ return compareSignatures(p1.getSigningDetails().signatures,
+ p2.getSigningDetails().signatures);
}
}
@@ -5579,21 +5639,21 @@ public class PackageManagerService extends IPackageManager.Stub
String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
synchronized (mLock) {
- final PackageParser.Package p = mPackages.get(packageName);
- if (p == null || p.mExtras == null) {
+ final AndroidPackage p = mPackages.get(packageName);
+ final PackageSetting ps = getPackageSetting(p.getPackageName());
+ if (p == null || ps == null) {
return false;
}
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageSetting ps = (PackageSetting) p.mExtras;
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return false;
}
switch (type) {
case CERT_INPUT_RAW_X509:
- return p.mSigningDetails.hasCertificate(certificate);
+ return p.getSigningDetails().hasCertificate(certificate);
case CERT_INPUT_SHA256:
- return p.mSigningDetails.hasSha256Certificate(certificate);
+ return p.getSigningDetails().hasSha256Certificate(certificate);
default:
return false;
}
@@ -5646,16 +5706,16 @@ public class PackageManagerService extends IPackageManager.Stub
* external storage) is less than the version where package signatures
* were updated, return true.
*/
- private boolean isCompatSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
- return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
+ private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) {
+ return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
}
private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
}
- private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
- return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
+ private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) {
+ return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
}
private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
@@ -5674,24 +5734,23 @@ public class PackageManagerService extends IPackageManager.Stub
final List<String> result = new ArrayList<>();
if (instantAppPkgName != null) {
// caller is an instant application; filter unexposed applications
- for (PackageParser.Package pkg : mPackages.values()) {
- if (!pkg.visibleToInstantApps) {
+ for (AndroidPackage pkg : mPackages.values()) {
+ if (!pkg.isVisibleToInstantApps()) {
continue;
}
- result.add(pkg.packageName);
+ result.add(pkg.getPackageName());
}
} else {
// caller is a normal application; filter instant applications
- for (PackageParser.Package pkg : mPackages.values()) {
- final PackageSetting ps =
- pkg.mExtras != null ? (PackageSetting) pkg.mExtras : null;
+ for (AndroidPackage pkg : mPackages.values()) {
+ final PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (ps != null
&& ps.getInstantApp(callingUserId)
&& !mInstantAppRegistry.isInstantAccessGranted(
callingUserId, UserHandle.getAppId(callingUid), ps.appId)) {
continue;
}
- result.add(pkg.packageName);
+ result.add(pkg.getPackageName());
}
}
return result;
@@ -6535,7 +6594,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
- return isInstantApp ? ps.pkg.packageName : null;
+ return isInstantApp ? ps.pkg.getPackageName() : null;
}
}
return null;
@@ -6607,9 +6666,11 @@ public class PackageManagerService extends IPackageManager.Stub
list.add(ri);
}
}
- return applyPostResolutionFilter(
+
+ List<ResolveInfo> result = applyPostResolutionFilter(
list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent);
+ return result;
}
// reader
@@ -6686,11 +6747,11 @@ public class PackageManagerService extends IPackageManager.Stub
sortResult = true;
}
} else {
- final PackageParser.Package pkg = mPackages.get(pkgName);
+ final AndroidPackage pkg = mPackages.get(pkgName);
result = null;
if (pkg != null) {
result = filterIfNotSystemUser(mComponentResolver.queryActivities(
- intent, resolvedType, flags, pkg.activities, userId), userId);
+ intent, resolvedType, flags, pkg.getActivities(), userId), userId);
}
if (result == null || result.size() == 0) {
// the caller wants to resolve for a particular package; however, there
@@ -7584,10 +7645,10 @@ public class PackageManagerService extends IPackageManager.Stub
result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
intent);
}
- final PackageParser.Package pkg = mPackages.get(pkgName);
+ final AndroidPackage pkg = mPackages.get(pkgName);
if (pkg != null) {
final List<ResolveInfo> result = mComponentResolver.queryReceivers(
- intent, resolvedType, flags, pkg.receivers, userId);
+ intent, resolvedType, flags, pkg.getReceivers(), userId);
if (result == null) {
return Collections.emptyList();
}
@@ -7693,10 +7754,10 @@ public class PackageManagerService extends IPackageManager.Stub
resolveInfos,
instantAppPkgName);
}
- final PackageParser.Package pkg = mPackages.get(pkgName);
+ final AndroidPackage pkg = mPackages.get(pkgName);
if (pkg != null) {
final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
- resolvedType, flags, pkg.services,
+ resolvedType, flags, pkg.getServices(),
userId);
if (resolveInfos == null) {
return Collections.emptyList();
@@ -7820,11 +7881,11 @@ public class PackageManagerService extends IPackageManager.Stub
resolveInfos,
instantAppPkgName);
}
- final PackageParser.Package pkg = mPackages.get(pkgName);
+ final AndroidPackage pkg = mPackages.get(pkgName);
if (pkg != null) {
final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent,
resolvedType, flags,
- pkg.providers, userId);
+ pkg.getProviders(), userId);
if (resolveInfos == null) {
return Collections.emptyList();
}
@@ -7914,16 +7975,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
list = new ArrayList<>(mPackages.size());
- for (PackageParser.Package p : mPackages.values()) {
- final PackageSetting ps = (PackageSetting) p.mExtras;
+ for (AndroidPackage p : mPackages.values()) {
+ final PackageSetting ps = getPackageSetting(p.getPackageName());
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
- final PackageInfo pi = generatePackageInfo((PackageSetting)
- p.mExtras, flags, userId);
+ final PackageInfo pi = generatePackageInfo(ps, flags, userId);
if (pi != null) {
list.add(pi);
}
@@ -8002,8 +8062,8 @@ public class PackageManagerService extends IPackageManager.Stub
userId);
}
} else {
- for (PackageParser.Package pkg : mPackages.values()) {
- PackageSetting ps = (PackageSetting)pkg.mExtras;
+ for (AndroidPackage pkg : mPackages.values()) {
+ PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (ps != null) {
addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags,
userId);
@@ -8056,7 +8116,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
- ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
+ ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags,
ps.readUserState(userId), userId);
if (ai != null) {
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
@@ -8073,16 +8133,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
list = new ArrayList<>(mPackages.size());
- for (PackageParser.Package p : mPackages.values()) {
- if (p.mExtras != null) {
- PackageSetting ps = (PackageSetting) p.mExtras;
+ for (AndroidPackage p : mPackages.values()) {
+ final PackageSetting ps = getPackageSetting(p.getPackageName());
+ if (ps != null) {
if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
continue;
}
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
- ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+ ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
ai.packageName = resolveExternalPackageNameLPr(p);
@@ -8138,7 +8198,6 @@ public class PackageManagerService extends IPackageManager.Stub
callingUid = mIsolatedOwners.get(callingUid);
}
final PackageSetting ps = mSettings.mPackages.get(packageName);
- PackageParser.Package pkg = mPackages.get(packageName);
final boolean returnAllowed =
ps != null
&& (isCallerSameApp(packageName, callingUid)
@@ -8209,9 +8268,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
private boolean isCallerSameApp(String packageName, int uid) {
- PackageParser.Package pkg = mPackages.get(packageName);
+ AndroidPackage pkg = mPackages.get(packageName);
return pkg != null
- && UserHandle.getAppId(uid) == pkg.applicationInfo.uid;
+ && UserHandle.getAppId(uid) == pkg.getUid();
}
@Override
@@ -8227,23 +8286,22 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
- final Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ final Iterator<AndroidPackage> i = mPackages.values().iterator();
final int userId = UserHandle.getCallingUserId();
while (i.hasNext()) {
- final PackageParser.Package p = i.next();
- if (p.applicationInfo == null) continue;
+ final AndroidPackage p = i.next();
final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
- && !p.applicationInfo.isDirectBootAware();
+ && !p.isDirectBootAware();
final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
- && p.applicationInfo.isDirectBootAware();
+ && p.isDirectBootAware();
- if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+ if ((p.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0
&& (!mSafeMode || isSystemApp(p))
&& (matchesUnaware || matchesAware)) {
- PackageSetting ps = mSettings.mPackages.get(p.packageName);
+ PackageSetting ps = mSettings.mPackages.get(p.getPackageName());
if (ps != null) {
- ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+ ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
finalList.add(ai);
@@ -8341,14 +8399,16 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
- if (ps == null) return null;
+ String packageName = component.getPackageName();
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ AndroidPackage pkg = mPackages.get(packageName);
+ if (ps == null || pkg == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
return null;
}
- final PackageParser.Instrumentation i = mInstrumentation.get(component);
- return PackageParser.generateInstrumentationInfo(i, flags);
+ final ParsedInstrumentation i = mInstrumentation.get(component);
+ return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags);
}
}
@@ -8370,15 +8430,18 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
- final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
+ final Iterator<ParsedInstrumentation> i = mInstrumentation.values().iterator();
while (i.hasNext()) {
- final PackageParser.Instrumentation p = i.next();
+ final ParsedInstrumentation p = i.next();
if (targetPackage == null
- || targetPackage.equals(p.info.targetPackage)) {
- InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p,
- flags);
- if (ii != null) {
- finalList.add(ii);
+ || targetPackage.equals(p.getTargetPackage())) {
+ AndroidPackage pkg = mPackages.get(p.getPackageName());
+ if (pkg != null) {
+ InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
+ pkg, flags);
+ if (ii != null) {
+ finalList.add(ii);
+ }
}
}
}
@@ -8432,18 +8495,18 @@ public class PackageManagerService extends IPackageManager.Stub
if (throwable == null) {
// TODO(toddke): move lower in the scan chain
// Static shared libraries have synthetic package names
- if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
- renameStaticSharedLibraryPackage(parseResult.pkg);
+ if (parseResult.parsedPackage.isStaticSharedLibrary()) {
+ renameStaticSharedLibraryPackage(parseResult.parsedPackage);
}
try {
- scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
+ addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
currentTime, null);
} catch (PackageManagerException e) {
errorCode = e.error;
Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
- } else if (throwable instanceof PackageParser.PackageParserException) {
- PackageParser.PackageParserException e = (PackageParser.PackageParserException)
+ } else if (throwable instanceof PackageParserException) {
+ PackageParserException e = (PackageParserException)
throwable;
errorCode = e.error;
Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
@@ -8467,15 +8530,16 @@ public class PackageManagerService extends IPackageManager.Stub
logCriticalInfo(priority, msg);
}
- private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
+ private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
boolean forceCollect, boolean skipVerify) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
// directory and not the APK file.
final long lastModifiedTime = mIsPreNMR1Upgrade
- ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
- final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(pkg);
+ ? new File(parsedPackage.getCodePath()).lastModified()
+ : getLastModifiedTime(parsedPackage);
+ final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
if (ps != null && !forceCollect
- && ps.codePathString.equals(pkg.codePath)
+ && ps.codePathString.equals(parsedPackage.getCodePath())
&& ps.timeStamp == lastModifiedTime
&& !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
&& !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
@@ -8485,21 +8549,21 @@ public class PackageManagerService extends IPackageManager.Stub
!= SignatureSchemeVersion.UNKNOWN) {
// Optimization: reuse the existing cached signing data
// if the package appears to be unchanged.
- pkg.mSigningDetails =
- new PackageParser.SigningDetails(ps.signatures.mSigningDetails);
+ parsedPackage.setSigningDetails(
+ new PackageParser.SigningDetails(ps.signatures.mSigningDetails));
return;
}
Slog.w(TAG, "PackageSetting for " + ps.name
+ " is missing signatures. Collecting certs again to recover them.");
} else {
- Slog.i(TAG, pkg.codePath + " changed; collecting certs" +
+ Slog.i(TAG, parsedPackage.getCodePath() + " changed; collecting certs" +
(forceCollect ? " (forced)" : ""));
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
- PackageParser.collectCertificates(pkg, skipVerify);
+ ApkParseUtils.collectCertificates(parsedPackage, skipVerify);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -8513,20 +8577,20 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private void maybeClearProfilesForUpgradesLI(
@Nullable PackageSetting originalPkgSetting,
- @NonNull PackageParser.Package currentPkg) {
+ @NonNull AndroidPackage pkg) {
if (originalPkgSetting == null || !isDeviceUpgrading()) {
return;
}
- if (originalPkgSetting.versionCode == currentPkg.mVersionCode) {
+ if (originalPkgSetting.versionCode == pkg.getVersionCode()) {
return;
}
- clearAppProfilesLIF(currentPkg, UserHandle.USER_ALL);
+ clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
if (DEBUG_INSTALL) {
Slog.d(TAG, originalPkgSetting.name
+ " clear profile due to version change "
+ originalPkgSetting.versionCode + " != "
- + currentPkg.mVersionCode);
+ + pkg.getVersionCode());
}
}
@@ -8535,7 +8599,7 @@ public class PackageManagerService extends IPackageManager.Stub
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
@GuardedBy({"mInstallLock", "mLock"})
- private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
+ private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
@@ -8550,7 +8614,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
@GuardedBy({"mInstallLock", "mLock"})
- private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
+ private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
PackageParser pp = new PackageParser();
@@ -8560,9 +8624,9 @@ public class PackageManagerService extends IPackageManager.Stub
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
- final PackageParser.Package pkg;
+ final ParsedPackage parsedPackage;
try {
- pkg = pp.parsePackage(scanFile, parseFlags);
+ parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -8570,66 +8634,25 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Static shared libraries have synthetic package names
- if (pkg.applicationInfo.isStaticSharedLibrary()) {
- renameStaticSharedLibraryPackage(pkg);
- }
-
- return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
- }
-
- /**
- * Scans a package and returns the newly parsed package.
- * @throws PackageManagerException on a parse error.
- */
- @GuardedBy({"mInstallLock", "mLock"})
- private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
- final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
- @Nullable UserHandle user)
- throws PackageManagerException {
- // If the package has children and this is the first dive in the function
- // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
- // packages (parent and children) would be successfully scanned before the
- // actual scan since scanning mutates internal state and we want to atomically
- // install the package and its children.
- if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
- if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
- scanFlags |= SCAN_CHECK_ONLY;
- }
- } else {
- scanFlags &= ~SCAN_CHECK_ONLY;
+ if (parsedPackage.isStaticSharedLibrary()) {
+ renameStaticSharedLibraryPackage(parsedPackage);
}
- // Scan the parent
- PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
- scanFlags, currentTime, user);
-
- // Scan the children
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPackage = pkg.childPackages.get(i);
- addForInitLI(childPackage, parseFlags, scanFlags,
- currentTime, user);
- }
-
-
- if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
- }
-
- return scannedPkg;
+ return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
}
/**
* Returns if forced apk verification can be skipped for the whole package, including splits.
*/
- private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) {
- if (!canSkipForcedApkVerification(pkg.baseCodePath)) {
+ private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
+ if (!canSkipForcedApkVerification(pkg.getBaseCodePath())) {
return false;
}
// TODO: Allow base and splits to be verified individually.
- if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
- for (int i = 0; i < pkg.splitCodePaths.length; i++) {
- if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) {
+ String[] splitCodePaths = pkg.getSplitCodePaths();
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ for (int i = 0; i < splitCodePaths.length; i++) {
+ if (!canSkipForcedApkVerification(splitCodePaths[i])) {
return false;
}
}
@@ -8678,7 +8701,7 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>NOTE: The return value should be removed. It's the passed in package object.
*/
@GuardedBy({"mInstallLock", "mLock"})
- private PackageParser.Package addForInitLI(PackageParser.Package pkg,
+ private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
@@ -8694,25 +8717,27 @@ public class PackageManagerService extends IPackageManager.Stub
// stack [such as scanPackageOnly()]. However, we verify the application
// info prior to that [in scanPackageNew()] and thus have to setup
// the application info early.
- pkg.setApplicationVolumeUuid(pkg.volumeUuid);
- pkg.setApplicationInfoCodePath(pkg.codePath);
- pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
- pkg.setApplicationInfoResourcePath(pkg.codePath);
- pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+ // TODO(b/135203078): Remove all of these application info calls
+ parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+ .setApplicationInfoCodePath(parsedPackage.getCodePath())
+ .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+ .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+ .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
synchronized (mLock) {
- renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
- final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+ renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
+ final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
if (realPkgName != null) {
- ensurePackageRenamed(pkg, renamedPkgName);
+ ensurePackageRenamed(parsedPackage, renamedPkgName);
}
- final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
- final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName);
+ final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
+ renamedPkgName);
+ final PackageSetting installedPkgSetting = mSettings.getPackageLPr(
+ parsedPackage.getPackageName());
pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
pkgAlreadyExists = pkgSetting != null;
- final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
+ final String disabledPkgName = pkgAlreadyExists
+ ? pkgSetting.name : parsedPackage.getPackageName();
if (scanSystemPartition && !pkgAlreadyExists
&& mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
// The updated-package data for /system apk remains inconsistently
@@ -8730,49 +8755,29 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
}
- final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
- ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
+ final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
+ ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
: null;
if (DEBUG_PACKAGE_SCANNING
&& (parseFlags & PackageParser.PARSE_CHATTY) != 0
&& sharedUserSetting != null) {
- Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+ Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
+ " (uid=" + sharedUserSetting.userId + "):"
+ " packages=" + sharedUserSetting.packages);
}
if (scanSystemPartition) {
- // Potentially prune child packages. If the application on the /system
- // partition has been updated via OTA, but, is still disabled by a
- // version on /data, cycle through all of its children packages and
- // remove children that are no longer defined.
if (isSystemPkgUpdated) {
- final int scannedChildCount = (pkg.childPackages != null)
- ? pkg.childPackages.size() : 0;
- final int disabledChildCount = disabledPkgSetting.childPackageNames != null
- ? disabledPkgSetting.childPackageNames.size() : 0;
- for (int i = 0; i < disabledChildCount; i++) {
- String disabledChildPackageName =
- disabledPkgSetting.childPackageNames.get(i);
- boolean disabledPackageAvailable = false;
- for (int j = 0; j < scannedChildCount; j++) {
- PackageParser.Package childPkg = pkg.childPackages.get(j);
- if (childPkg.packageName.equals(disabledChildPackageName)) {
- disabledPackageAvailable = true;
- break;
- }
- }
- if (!disabledPackageAvailable) {
- mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
- }
- }
// we're updating the disabled package, so, scan it as the package setting
- final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, null,
- disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */,
- null /* originalPkgSetting */, null, parseFlags, scanFlags,
- (pkg == mPlatformPackage), user);
- applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
+ boolean isPlatformPackage = mPlatformPackage != null
+ && Objects.equals(mPlatformPackage.getPackageName(),
+ parsedPackage.getPackageName());
+ final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
+ null, disabledPkgSetting /* pkgSetting */,
+ null /* disabledPkgSetting */, null /* originalPkgSetting */,
+ null, parseFlags, scanFlags, isPlatformPackage, user);
+ applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
final ScanResult scanResult =
scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
@@ -8783,9 +8788,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
final boolean newPkgChangedPaths =
- pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
+ pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath());
final boolean newPkgVersionGreater =
- pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
+ pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
&& newPkgChangedPaths && newPkgVersionGreater;
if (isSystemPkgBetter) {
@@ -8801,12 +8806,13 @@ public class PackageManagerService extends IPackageManager.Stub
logCriticalInfo(Log.WARN,
"System package updated;"
+ " name: " + pkgSetting.name
- + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
- + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+ + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
+ + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath());
final InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
- pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+ pkgSetting.resourcePathString, getAppDexInstructionSets(
+ pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
args.cleanUpResourcesLI();
synchronized (mLock) {
mSettings.enableSystemPackageLPw(pkgSetting.name);
@@ -8817,9 +8823,10 @@ public class PackageManagerService extends IPackageManager.Stub
// The version of the application on the /system partition is less than or
// equal to the version on the /data partition. Throw an exception and use
// the application already installed on the /data partition.
- throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
- + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
- + " better than this " + pkg.getLongVersionCode());
+ throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+ + " at " + parsedPackage.getCodePath() + " ignored: updated version "
+ + pkgSetting.versionCode + " better than this "
+ + parsedPackage.getLongVersionCode());
}
// Verify certificates against what was last scanned. Force re-collecting certificate in two
@@ -8830,7 +8837,7 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean forceCollect = scanSystemPartition ? mIsUpgrade
: PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
if (DEBUG_VERIFY && forceCollect) {
- Slog.d(TAG, "Force collect certificate of " + pkg.packageName);
+ Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
}
// Full APK verification can be skipped during certificate collection, only if the file is
@@ -8838,11 +8845,11 @@ public class PackageManagerService extends IPackageManager.Stub
// cases, only data in Signing Block is verified instead of the whole file.
// TODO(b/136132412): skip for Incremental installation
final boolean skipVerify = scanSystemPartition
- || (forceCollect && canSkipForcedPackageVerification(pkg));
- collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
+ || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
+ collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
// Reset profile if the application version is changed
- maybeClearProfilesForUpgradesLI(pkgSetting, pkg);
+ maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
/*
* A new system app appeared, but we already had a non-system one of the
@@ -8854,17 +8861,20 @@ public class PackageManagerService extends IPackageManager.Stub
if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
&& !pkgSetting.isSystem()) {
- if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails,
+ if (!parsedPackage.getSigningDetails()
+ .checkCapability(pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
&& !pkgSetting.signatures.mSigningDetails.checkCapability(
- pkg.mSigningDetails,
+ parsedPackage.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
logCriticalInfo(Log.WARN,
"System package signature mismatch;"
+ " name: " + pkgSetting.name);
- try (PackageFreezer freezer = freezePackage(pkg.packageName,
+ try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
+ parsedPackage.getPackageName(),
"scanPackageInternalLI")) {
- deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
+ deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null,
+ false, null);
}
pkgSetting = null;
} else if (newPkgVersionGreater) {
@@ -8873,12 +8883,15 @@ public class PackageManagerService extends IPackageManager.Stub
// and replace it with the version on /system.
logCriticalInfo(Log.WARN,
"System package enabled;"
- + " name: " + pkgSetting.name
- + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
- + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+ + " name: " + pkgSetting.name
+ + "; " + pkgSetting.versionCode + " --> "
+ + parsedPackage.getLongVersionCode()
+ + "; " + pkgSetting.codePathString + " --> "
+ + parsedPackage.getCodePath());
InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
- pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+ pkgSetting.resourcePathString, getAppDexInstructionSets(
+ pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
@@ -8889,13 +8902,15 @@ public class PackageManagerService extends IPackageManager.Stub
shouldHideSystemApp = true;
logCriticalInfo(Log.INFO,
"System package disabled;"
- + " name: " + pkgSetting.name
- + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
- + "; new: " + pkg.codePath + " @ " + pkg.codePath);
+ + " name: " + pkgSetting.name
+ + "; old: " + pkgSetting.codePathString + " @ "
+ + pkgSetting.versionCode
+ + "; new: " + parsedPackage.getCodePath() + " @ "
+ + parsedPackage.getCodePath());
}
}
- final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
+ final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
if (scanResult.success) {
synchronized (mLock) {
@@ -8908,7 +8923,7 @@ public class PackageManagerService extends IPackageManager.Stub
mSharedLibraries,
mPackages,
Collections.singletonMap(
- pkgName, getSettingsVersionForPackage(pkg)),
+ pkgName, getSettingsVersionForPackage(parsedPackage)),
Collections.singletonMap(pkgName,
getSharedLibLatestVersionSetting(scanResult))),
mSettings.mKeySetManagerService);
@@ -8925,16 +8940,17 @@ public class PackageManagerService extends IPackageManager.Stub
if (shouldHideSystemApp) {
synchronized (mLock) {
- mSettings.disableSystemPackageLPw(pkg.packageName, true);
+ mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
}
}
return scanResult.pkgSetting.pkg;
}
- private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
+ // TODO:(b/135203078): Move to parsing
+ private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
// Derive the new package synthetic package name
- pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
- + pkg.staticSharedLibVersion);
+ parsedPackage.setPackageName(parsedPackage.getPackageName() + STATIC_SHARED_LIB_DELIMITER
+ + parsedPackage.getStaticSharedLibVersion());
}
static String fixProcessName(String defProcessName, String processName) {
@@ -9035,7 +9051,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
- List<PackageParser.Package> pkgs;
+ List<AndroidPackage> pkgs;
synchronized (mLock) {
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
@@ -9058,8 +9074,8 @@ public class PackageManagerService extends IPackageManager.Stub
/*
* Return the prebuilt profile path given a package base code path.
*/
- private static String getPrebuildProfilePath(PackageParser.Package pkg) {
- return pkg.baseCodePath + ".prof";
+ private static String getPrebuildProfilePath(AndroidPackage pkg) {
+ return pkg.getBaseCodePath() + ".prof";
}
/**
@@ -9068,7 +9084,7 @@ public class PackageManagerService extends IPackageManager.Stub
* which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped}
* and {@code numberOfPackagesFailed}.
*/
- private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
+ private int[] performDexOptUpgrade(List<AndroidPackage> pkgs, boolean showDialog,
final int compilationReason, boolean bootComplete) {
int numberOfPackagesVisited = 0;
@@ -9077,7 +9093,7 @@ public class PackageManagerService extends IPackageManager.Stub
int numberOfPackagesFailed = 0;
final int numberOfPackagesToDexopt = pkgs.size();
- for (PackageParser.Package pkg : pkgs) {
+ for (AndroidPackage pkg : pkgs) {
numberOfPackagesVisited++;
boolean useProfileForDexopt = false;
@@ -9093,7 +9109,7 @@ public class PackageManagerService extends IPackageManager.Stub
// PackageDexOptimizer to prevent this happening on first boot. The issue
// is that we don't have a good way to say "do this only once".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName,
+ pkg.getUid(), pkg.getPackageName(),
ArtManager.getProfileName(null))) {
Log.e(TAG, "Installer failed to copy system profile!");
} else {
@@ -9106,11 +9122,12 @@ public class PackageManagerService extends IPackageManager.Stub
e);
}
} else {
- PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+ PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(
+ pkg.getPackageName());
// Handle compressed APKs in this path. Only do this for stubs with profiles to
// minimize the number off apps being speed-profile compiled during first boot.
// The other paths will not change the filter.
- if (disabledPs != null && disabledPs.pkg.isStub) {
+ if (disabledPs != null && disabledPs.pkg.isStub()) {
// The package is the stub one, remove the stub suffix to get the normal
// package and APK names.
String systemProfilePath =
@@ -9129,7 +9146,7 @@ public class PackageManagerService extends IPackageManager.Stub
// issue is that we don't have a good way to say "do this only
// once".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName,
+ pkg.getUid(), pkg.getPackageName(),
ArtManager.getProfileName(null))) {
Log.e(TAG, "Failed to copy system profile for stub package!");
} else {
@@ -9146,7 +9163,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipping update of of non-optimizable app " + pkg.packageName);
+ Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName());
}
numberOfPackagesSkipped++;
continue;
@@ -9154,7 +9171,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_DEXOPT) {
Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " +
- numberOfPackagesToDexopt + ": " + pkg.packageName);
+ numberOfPackagesToDexopt + ": " + pkg.getPackageName());
}
if (showDialog) {
@@ -9191,7 +9208,7 @@ public class PackageManagerService extends IPackageManager.Stub
dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
}
int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
- pkg.packageName,
+ pkg.getPackageName(),
pkgCompilationReason,
dexoptFlags));
@@ -9235,11 +9252,11 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
private void notifyPackageUseLocked(String packageName, int reason) {
- final PackageParser.Package p = mPackages.get(packageName);
+ final AndroidPackage p = mPackages.get(packageName);
if (p == null) {
return;
}
- p.mLastPackageUsageTimeInMills[reason] = System.currentTimeMillis();
+ p.mutate().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis());
}
@Override
@@ -9319,7 +9336,7 @@ public class PackageManagerService extends IPackageManager.Stub
*/
@Override
public boolean compileLayouts(String packageName) {
- PackageParser.Package pkg;
+ AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
@@ -9366,7 +9383,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
// if the package can now be considered up to date for the given filter.
private int performDexOptInternal(DexoptOptions options) {
- PackageParser.Package p;
+ AndroidPackage p;
synchronized (mLock) {
p = mPackages.get(options.getPackageName());
if (p == null) {
@@ -9389,16 +9406,16 @@ public class PackageManagerService extends IPackageManager.Stub
public ArraySet<String> getOptimizablePackages() {
ArraySet<String> pkgs = new ArraySet<>();
synchronized (mLock) {
- for (PackageParser.Package p : mPackages.values()) {
+ for (AndroidPackage p : mPackages.values()) {
if (PackageDexOptimizer.canOptimizePackage(p)) {
- pkgs.add(p.packageName);
+ pkgs.add(p.getPackageName());
}
}
}
return pkgs;
}
- private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
+ private int performDexOptInternalWithDependenciesLI(AndroidPackage p,
DexoptOptions options) {
// Select the dex optimizer based on the force parameter.
// Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
@@ -9415,14 +9432,15 @@ public class PackageManagerService extends IPackageManager.Stub
// and the first package that uses the library will dexopt it. The
// others will see that the compiled code for the library is up to date.
Collection<SharedLibraryInfo> deps = findSharedLibraries(p);
- final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
+ final String[] instructionSets = getAppDexInstructionSets(p.getPrimaryCpuAbi(),
+ p.getSecondaryCpuAbi());
if (!deps.isEmpty()) {
DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
options.getCompilationReason(), options.getCompilerFilter(),
options.getSplitName(),
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (SharedLibraryInfo info : deps) {
- PackageParser.Package depPackage = null;
+ AndroidPackage depPackage = null;
synchronized (mLock) {
depPackage = mPackages.get(info.getPackageName());
}
@@ -9430,7 +9448,7 @@ public class PackageManagerService extends IPackageManager.Stub
// TODO: Analyze and investigate if we (should) profile libraries.
pdo.performDexOpt(depPackage, instructionSets,
getOrCreateCompilerPackageStats(depPackage),
- mDexManager.getPackageUseInfoOrDefault(depPackage.packageName),
+ mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()),
libraryOptions);
} else {
// TODO(ngeoffray): Support dexopting system shared libraries.
@@ -9439,7 +9457,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
return pdo.performDexOpt(p, instructionSets,
getOrCreateCompilerPackageStats(p),
- mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
+ mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options);
}
/**
@@ -9480,11 +9498,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) {
- if (p.usesLibraryInfos != null) {
+ private static List<SharedLibraryInfo> findSharedLibraries(AndroidPackage p) {
+ if (p.getUsesLibraryInfos() != null) {
ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
Set<String> collectedNames = new HashSet<>();
- for (SharedLibraryInfo info : p.usesLibraryInfos) {
+ for (SharedLibraryInfo info : p.getUsesLibraryInfos()) {
findSharedLibrariesRecursive(info, retValue, collectedNames);
}
return retValue;
@@ -9507,13 +9525,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) {
+ List<AndroidPackage> findSharedNonSystemLibraries(AndroidPackage pkg) {
List<SharedLibraryInfo> deps = findSharedLibraries(pkg);
if (!deps.isEmpty()) {
- ArrayList<PackageParser.Package> retValue = new ArrayList<>();
+ ArrayList<AndroidPackage> retValue = new ArrayList<>();
synchronized (mLock) {
for (SharedLibraryInfo info : deps) {
- PackageParser.Package depPackage = mPackages.get(info.getPackageName());
+ AndroidPackage depPackage = mPackages.get(info.getPackageName());
if (depPackage != null) {
retValue.add(depPackage);
}
@@ -9551,9 +9569,9 @@ public class PackageManagerService extends IPackageManager.Stub
return versionedLib.get(version);
}
- private SharedLibraryInfo getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
+ private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
- pkg.staticSharedLibName);
+ pkg.getStaticSharedLibName());
if (versionedLib == null) {
return null;
}
@@ -9561,7 +9579,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
final long libVersion = versionedLib.keyAt(i);
- if (libVersion < pkg.staticSharedLibVersion) {
+ if (libVersion < pkg.getStaticSharedLibVersion()) {
previousLibVersion = Math.max(previousLibVersion, libVersion);
}
}
@@ -9577,7 +9595,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageSetting sharedLibPackage = null;
synchronized (mLock) {
final SharedLibraryInfo latestSharedLibraVersionLPr =
- getLatestSharedLibraVersionLPr(scanResult.pkgSetting.pkg);
+ getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage);
if (latestSharedLibraVersionLPr != null) {
sharedLibPackage = mSettings.getPackageLPr(
latestSharedLibraVersionLPr.getPackageName());
@@ -9606,7 +9624,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void dumpProfiles(String packageName) {
- PackageParser.Package pkg;
+ AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
@@ -9617,7 +9635,7 @@ public class PackageManagerService extends IPackageManager.Stub
int callingUid = Binder.getCallingUid();
if (callingUid != Process.SHELL_UID &&
callingUid != Process.ROOT_UID &&
- callingUid != pkg.applicationInfo.uid) {
+ callingUid != pkg.getUid()) {
throw new SecurityException("dumpProfiles");
}
@@ -9632,7 +9650,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void forceDexOpt(String packageName) {
enforceSystemOrRoot("forceDexOpt");
- PackageParser.Package pkg;
+ AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
@@ -9659,15 +9677,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy("mLock")
- private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
+ private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, AndroidPackage newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
- + " to " + newPkg.packageName
+ + " to " + newPkg.getPackageName()
+ ": old package not in system partition");
return false;
} else if (mPackages.get(oldPkg.name) != null) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
- + " to " + newPkg.packageName
+ + " to " + newPkg.getPackageName()
+ ": old package still exists");
return false;
}
@@ -9691,122 +9709,86 @@ public class PackageManagerService extends IPackageManager.Stub
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
- private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+ private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
clearAppDataLeafLIF(pkg, userId, flags);
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
- }
if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
}
}
- private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+ private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.packageName);
+ ps = mSettings.mPackages.get(pkg.getPackageName());
}
for (int realUserId : resolveUserIds(userId)) {
final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
try {
- mInstaller.clearAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
- ceDataInode);
+ mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+ flags, ceDataInode);
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
}
}
- private void destroyAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+ private void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
destroyAppDataLeafLIF(pkg, userId, flags);
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- destroyAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
- }
}
- private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+ private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.packageName);
+ ps = mSettings.mPackages.get(pkg.getPackageName());
}
for (int realUserId : resolveUserIds(userId)) {
final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
try {
- mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
- ceDataInode);
+ mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+ flags, ceDataInode);
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
- mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
+ mDexManager.notifyPackageDataDestroyed(pkg.getPackageName(), userId);
}
}
- private void destroyAppProfilesLIF(PackageParser.Package pkg) {
+ private void destroyAppProfilesLIF(AndroidPackage pkg) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
destroyAppProfilesLeafLIF(pkg);
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- destroyAppProfilesLeafLIF(pkg.childPackages.get(i));
- }
}
- private void destroyAppProfilesLeafLIF(PackageParser.Package pkg) {
+ private void destroyAppProfilesLeafLIF(AndroidPackage pkg) {
try {
- mInstaller.destroyAppProfiles(pkg.packageName);
+ mInstaller.destroyAppProfiles(pkg.getPackageName());
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
}
- private void clearAppProfilesLIF(PackageParser.Package pkg, int userId) {
+ private void clearAppProfilesLIF(AndroidPackage pkg, int userId) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
mArtManagerService.clearAppProfiles(pkg);
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- mArtManagerService.clearAppProfiles(pkg.childPackages.get(i));
- }
- }
-
- private void setInstallAndUpdateTime(PackageParser.Package pkg, long firstInstallTime,
- long lastUpdateTime) {
- // Set parent install/update time
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps != null) {
- ps.firstInstallTime = firstInstallTime;
- ps.lastUpdateTime = lastUpdateTime;
- }
- // Set children install/update time
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- ps = (PackageSetting) childPkg.mExtras;
- if (ps != null) {
- ps.firstInstallTime = firstInstallTime;
- ps.lastUpdateTime = lastUpdateTime;
- }
- }
}
@GuardedBy("mLock")
private void applyDefiningSharedLibraryUpdateLocked(
- PackageParser.Package pkg, SharedLibraryInfo libInfo,
+ AndroidPackage pkg, SharedLibraryInfo libInfo,
BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
// Note that libraries defined by this package may be null if:
// - Package manager was unable to create the shared library. The package still
@@ -9815,14 +9797,14 @@ public class PackageManagerService extends IPackageManager.Stub
// - Package manager is in a state where package isn't scanned yet. This will
// get called again after scanning to fix the dependencies.
if (pkg.isLibrary()) {
- if (pkg.staticSharedLibName != null) {
+ if (pkg.getStaticSharedLibName() != null) {
SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
- pkg.staticSharedLibName, pkg.staticSharedLibVersion);
+ pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
if (definedLibrary != null) {
action.accept(definedLibrary, libInfo);
}
} else {
- for (String libraryName : pkg.libraryNames) {
+ for (String libraryName : pkg.getLibraryNames()) {
SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
if (definedLibrary != null) {
@@ -9834,19 +9816,19 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy("mLock")
- private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
- SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
+ private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles,
+ SharedLibraryInfo libInfo, AndroidPackage changingLib) {
if (libInfo.getPath() != null) {
usesLibraryFiles.add(libInfo.getPath());
return;
}
- PackageParser.Package p = mPackages.get(libInfo.getPackageName());
- if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) {
+ AndroidPackage p = mPackages.get(libInfo.getPackageName());
+ if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
// If we are doing this while in the middle of updating a library apk,
// then we need to make sure to use that new apk for determining the
// dependencies here. (We haven't yet finished committing the new apk
// to the package manager state.)
- if (p == null || p.packageName.equals(changingLib.packageName)) {
+ if (p == null || p.getPackageName().equals(changingLib.getPackageName())) {
p = changingLib;
}
}
@@ -9856,23 +9838,23 @@ public class PackageManagerService extends IPackageManager.Stub
applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
definingLibrary.addDependency(dependency);
});
- if (p.usesLibraryFiles != null) {
- Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
+ if (p.getUsesLibraryFiles() != null) {
+ Collections.addAll(usesLibraryFiles, p.getUsesLibraryFiles());
}
}
}
@GuardedBy("mLock")
- private void updateSharedLibrariesLocked(PackageParser.Package pkg,
- PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
+ private void updateSharedLibrariesLocked(AndroidPackage pkg,
+ AndroidPackage changingLib, Map<String, AndroidPackage> availablePackages)
throws PackageManagerException {
final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
}
- private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(PackageParser.Package pkg,
- Map<String, PackageParser.Package> availablePackages,
+ private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(AndroidPackage pkg,
+ Map<String, AndroidPackage> availablePackages,
@NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
@Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
throws PackageManagerException {
@@ -9883,44 +9865,45 @@ public class PackageManagerService extends IPackageManager.Stub
// that libraries are searched in the correct order) and must have no
// duplicates.
ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
- if (pkg.usesLibraries != null) {
- usesLibraryInfos = collectSharedLibraryInfos(pkg.usesLibraries, null, null,
- pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, null,
+ if (pkg.getUsesLibraries() != null) {
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null,
+ pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null,
availablePackages, existingLibraries, newLibraries);
}
- if (pkg.usesStaticLibraries != null) {
- usesLibraryInfos = collectSharedLibraryInfos(pkg.usesStaticLibraries,
- pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests,
- pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, usesLibraryInfos,
+ if (pkg.getUsesStaticLibraries() != null) {
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
+ pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
+ pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos,
availablePackages, existingLibraries, newLibraries);
}
- if (pkg.usesOptionalLibraries != null) {
- usesLibraryInfos = collectSharedLibraryInfos(pkg.usesOptionalLibraries,
- null, null, pkg.packageName, false, pkg.applicationInfo.targetSdkVersion,
+ if (pkg.getUsesOptionalLibraries() != null) {
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(),
+ null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
}
return usesLibraryInfos;
}
- private void executeSharedLibrariesUpdateLPr(PackageParser.Package pkg,
- PackageParser.Package changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
+ private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg,
+ AndroidPackage changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
// If the package provides libraries, clear their old dependencies.
// This method will set them up again.
applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
definingLibrary.clearDependencies();
});
if (usesLibraryInfos != null) {
- pkg.usesLibraryInfos = usesLibraryInfos;
+ pkg.mutate().setUsesLibraryInfos(usesLibraryInfos);
// Use LinkedHashSet to preserve the order of files added to
// usesLibraryFiles while eliminating duplicates.
Set<String> usesLibraryFiles = new LinkedHashSet<>();
for (SharedLibraryInfo libInfo : usesLibraryInfos) {
addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib);
}
- pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
+ pkg.mutate().setUsesLibraryFiles(usesLibraryFiles.toArray(
+ new String[usesLibraryFiles.size()]));
} else {
- pkg.usesLibraryInfos = null;
- pkg.usesLibraryFiles = null;
+ pkg.mutate().setUsesLibraryInfos(null)
+ .setUsesLibraryFiles(null);
}
}
@@ -9930,7 +9913,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
@NonNull String packageName, boolean required, int targetSdk,
@Nullable ArrayList<SharedLibraryInfo> outUsedLibraries,
- @NonNull final Map<String, PackageParser.Package> availablePackages,
+ @NonNull final Map<String, AndroidPackage> availablePackages,
@NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
@Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
throws PackageManagerException {
@@ -9959,8 +9942,8 @@ public class PackageManagerService extends IPackageManager.Stub
+ " library " + libName + " version "
+ libraryInfo.getLongVersion() + "; failing!");
}
- PackageParser.Package libPkg =
- availablePackages.get(libraryInfo.getPackageName());
+ AndroidPackage pkg = availablePackages.get(libraryInfo.getPackageName());
+ SigningDetails libPkg = pkg == null ? null : pkg.getSigningDetails();
if (libPkg == null) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires unavailable static shared"
@@ -9971,9 +9954,9 @@ public class PackageManagerService extends IPackageManager.Stub
// For apps targeting O MR1 we require explicit enumeration of all certs.
final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
? PackageUtils.computeSignaturesSha256Digests(
- libPkg.mSigningDetails.signatures)
+ libPkg.signatures)
: PackageUtils.computeSignaturesSha256Digests(
- new Signature[]{libPkg.mSigningDetails.signatures[0]});
+ new Signature[]{libPkg.signatures[0]});
// Take a shortcut if sizes don't match. Note that if an app doesn't
// target O we don't parse the "additional-certificate" tags similarly
@@ -10003,7 +9986,7 @@ public class PackageManagerService extends IPackageManager.Stub
// if the new one has been blessed by the old
byte[] digestBytes = HexEncoding.decode(
expectedCertDigests[0], false /* allowSingleChar */);
- if (!libPkg.mSigningDetails.hasSha256Certificate(digestBytes)) {
+ if (!libPkg.hasSha256Certificate(digestBytes)) {
throw new PackageManagerException(
INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires differently signed" +
@@ -10035,28 +10018,28 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy("mLock")
- private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
- PackageParser.Package updatedPkg,
- Map<String, PackageParser.Package> availablePackages) {
- ArrayList<PackageParser.Package> resultList = null;
+ private ArrayList<AndroidPackage> updateAllSharedLibrariesLocked(
+ AndroidPackage updatedPkg,
+ Map<String, AndroidPackage> availablePackages) {
+ ArrayList<AndroidPackage> resultList = null;
// Set of all descendants of a library; used to eliminate cycles
ArraySet<String> descendants = null;
// The current list of packages that need updating
- ArrayList<PackageParser.Package> needsUpdating = null;
+ ArrayList<AndroidPackage> needsUpdating = null;
if (updatedPkg != null) {
needsUpdating = new ArrayList<>(1);
needsUpdating.add(updatedPkg);
}
do {
- final PackageParser.Package changingPkg =
+ final AndroidPackage changingPkg =
(needsUpdating == null) ? null : needsUpdating.remove(0);
for (int i = mPackages.size() - 1; i >= 0; --i) {
- final PackageParser.Package pkg = mPackages.valueAt(i);
+ final AndroidPackage pkg = mPackages.valueAt(i);
if (changingPkg != null
- && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
- && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
- && !ArrayUtils.contains(pkg.usesStaticLibraries,
- changingPkg.staticSharedLibName)) {
+ && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
+ && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
+ && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
+ changingPkg.getStaticSharedLibName())) {
continue;
}
if (resultList == null) {
@@ -10068,8 +10051,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (descendants == null) {
descendants = new ArraySet<>();
}
- if (!descendants.contains(pkg.packageName)) {
- descendants.add(pkg.packageName);
+ if (!descendants.contains(pkg.getPackageName())) {
+ descendants.add(pkg.getPackageName());
needsUpdating.add(pkg);
}
}
@@ -10084,8 +10067,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
final int flags = pkg.isUpdatedSystemApp()
? PackageManager.DELETE_KEEP_DATA : 0;
- deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(),
- flags , null, true, null);
+ deletePackageLIF(pkg.getPackageName(), null, true,
+ mUserManager.getUserIds(), flags, null,
+ true, null);
}
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
@@ -10095,43 +10079,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy({"mInstallLock", "mLock"})
- private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg,
+ private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
- // If the package has children and this is the first dive in the function
- // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see
- // whether all packages (parent and children) would be successfully scanned
- // before the actual scan since scanning mutates internal state and we want
- // to atomically install the package and its children.
- if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
- if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
- scanFlags |= SCAN_CHECK_ONLY;
- }
- } else {
- scanFlags &= ~SCAN_CHECK_ONLY;
- }
-
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- final List<ScanResult> scanResults = new ArrayList<>(1 + childCount);
try {
- // Scan the parent
- scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user));
- // Scan the children
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- scanResults.add(scanPackageNewLI(childPkg, parseFlags,
- scanFlags, currentTime, user));
- }
+ return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
-
- if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user);
- }
-
- return scanResults;
}
/** The result of a package scan. */
@@ -10178,9 +10134,9 @@ public class PackageManagerService extends IPackageManager.Stub
@VisibleForTesting
static class ScanRequest {
/** The parsed package */
- @NonNull public final PackageParser.Package pkg;
+ @NonNull public final ParsedPackage parsedPackage;
/** The package this package replaces */
- @Nullable public final PackageParser.Package oldPkg;
+ @Nullable public final AndroidPackage oldPkg;
/** Shared user settings, if the package has a shared user */
@Nullable public final SharedUserSetting sharedUserSetting;
/**
@@ -10204,9 +10160,9 @@ public class PackageManagerService extends IPackageManager.Stub
/** Whether or not the platform package is being scanned */
public final boolean isPlatformPackage;
public ScanRequest(
- @NonNull PackageParser.Package pkg,
+ @NonNull ParsedPackage parsedPackage,
@Nullable SharedUserSetting sharedUserSetting,
- @Nullable PackageParser.Package oldPkg,
+ @Nullable AndroidPackage oldPkg,
@Nullable PackageSetting pkgSetting,
@Nullable PackageSetting disabledPkgSetting,
@Nullable PackageSetting originalPkgSetting,
@@ -10215,7 +10171,7 @@ public class PackageManagerService extends IPackageManager.Stub
@ScanFlags int scanFlags,
boolean isPlatformPackage,
@Nullable UserHandle user) {
- this.pkg = pkg;
+ this.parsedPackage = parsedPackage;
this.oldPkg = oldPkg;
this.pkgSetting = pkgSetting;
this.sharedUserSetting = sharedUserSetting;
@@ -10248,7 +10204,7 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
- PackageParser.Package pkg) {
+ AndroidPackage pkg) {
// TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain
// the correct isSystem value now that we don't disable system packages before scan.
@@ -10300,12 +10256,14 @@ public class PackageManagerService extends IPackageManager.Stub
&& SystemProperties.getInt("ro.vndk.version", 28) < 28;
if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
&& !pkg.isPrivileged()
- && (pkg.mSharedUserId != null)
+ && (pkg.getSharedUserId() != null)
&& !skipVendorPrivilegeScan) {
SharedUserSetting sharedUserSetting = null;
try {
- sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
- } catch (PackageManagerException ignore) {}
+ sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), 0,
+ 0, false);
+ } catch (PackageManagerException ignore) {
+ }
if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
// Exempt SharedUsers signed with the platform key.
// TODO(b/72378145) Fix this exemption. Force signature apps
@@ -10314,7 +10272,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) {
+ pkg.getSigningDetails().signatures)
+ != PackageManager.SIGNATURE_MATCH)) {
scanFlags |= SCAN_AS_PRIVILEGED;
}
}
@@ -10329,46 +10288,50 @@ public class PackageManagerService extends IPackageManager.Stub
// method. Also, we need to solve the problem of potentially creating a new shared user
// setting. That can probably be done later and patch things up after the fact.
@GuardedBy({"mInstallLock", "mLock"})
- private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
+ private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user) throws PackageManagerException {
- final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
- final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+ final String renamedPkgName = mSettings.getRenamedPackageLPr(
+ parsedPackage.getRealPackage());
+ final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
if (realPkgName != null) {
- ensurePackageRenamed(pkg, renamedPkgName);
+ ensurePackageRenamed(parsedPackage, renamedPkgName);
}
- final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
- final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName);
+ final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
+ renamedPkgName);
+ final PackageSetting pkgSetting = mSettings.getPackageLPr(parsedPackage.getPackageName());
final PackageSetting disabledPkgSetting =
- mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+ mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName());
- if (mTransferedPackages.contains(pkg.packageName)) {
- Slog.w(TAG, "Package " + pkg.packageName
+ if (mTransferredPackages.contains(parsedPackage.getPackageName())) {
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ " was transferred to another, but its .apk remains");
}
- scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
+ scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage);
synchronized (mLock) {
- applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
- assertPackageIsValid(pkg, parseFlags, scanFlags);
+ applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
+ assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
SharedUserSetting sharedUserSetting = null;
- if (pkg.mSharedUserId != null) {
+ if (parsedPackage.getSharedUserId() != null) {
// SIDE EFFECTS; may potentially allocate a new shared user
- sharedUserSetting = mSettings.getSharedUserLPw(
- pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
+ sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
+ 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
- Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+ Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
+ " (uid=" + sharedUserSetting.userId + "):"
+ " packages=" + sharedUserSetting.packages);
}
}
- final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
+ String platformPackageName = mPlatformPackage == null
+ ? null : mPlatformPackage.getPackageName();
+ final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
originalPkgSetting, realPkgName, parseFlags, scanFlags,
- (pkg == mPlatformPackage), user);
+ Objects.equals(parsedPackage.getPackageName(), platformPackageName), user);
return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
}
}
@@ -10411,11 +10374,18 @@ public class PackageManagerService extends IPackageManager.Stub
* possible and the system is not left in an inconsistent state.
*/
@GuardedBy({"mLock", "mInstallLock"})
- private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
+ private AndroidPackage commitReconciledScanResultLocked(
+ @NonNull ReconciledPackage reconciledPkg) {
final ScanResult result = reconciledPkg.scanResult;
final ScanRequest request = result.request;
- final PackageParser.Package pkg = request.pkg;
- final PackageParser.Package oldPkg = request.oldPkg;
+ // TODO(b/135203078): Move this even further away
+ ParsedPackage parsedPackage = request.parsedPackage;
+ if ("android".equals(parsedPackage.getPackageName())) {
+ // TODO(b/135203078): Move this to initial parse
+ parsedPackage.setVersionCode(mSdkVersion)
+ .setVersionCodeMajor(0);
+ }
+ final AndroidPackage oldPkg = request.oldPkg;
final @ParseFlags int parseFlags = request.parseFlags;
final @ScanFlags int scanFlags = request.scanFlags;
final PackageSetting oldPkgSetting = request.oldPkgSetting;
@@ -10432,14 +10402,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (result.existingSettingCopied) {
pkgSetting = request.pkgSetting;
pkgSetting.updateFrom(result.pkgSetting);
- pkg.mExtras = pkgSetting;
} else {
pkgSetting = result.pkgSetting;
if (originalPkgSetting != null) {
- mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
- }
- if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) {
- mTransferedPackages.add(originalPkgSetting.name);
+ mSettings.addRenamedPackageLPw(parsedPackage.getPackageName(),
+ originalPkgSetting.name);
+ mTransferredPackages.add(originalPkgSetting.name);
}
}
if (pkgSetting.sharedUser != null) {
@@ -10451,12 +10419,13 @@ public class PackageManagerService extends IPackageManager.Stub
// We need to have this here because addUserToSettingLPw() is sometimes responsible
// for creating the application ID. If we did this earlier, we would be saving the
// correct ID.
- pkg.applicationInfo.uid = pkgSetting.appId;
+ parsedPackage.setUid(pkgSetting.appId);
+ final AndroidPackage pkg = parsedPackage.hideAsFinal();
mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
- if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) {
- mTransferedPackages.add(pkg.packageName);
+ if (realPkgName != null) {
+ mTransferredPackages.add(pkg.getPackageName());
}
if (reconciledPkg.collectedSharedLibraryInfos != null) {
@@ -10465,7 +10434,7 @@ public class PackageManagerService extends IPackageManager.Stub
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (reconciledPkg.removeAppKeySetData) {
- ksms.removeAppKeySetDataLPw(pkg.packageName);
+ ksms.removeAppKeySetDataLPw(pkg.getPackageName());
}
if (reconciledPkg.sharedUserSignaturesChanged) {
pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
@@ -10473,17 +10442,17 @@ public class PackageManagerService extends IPackageManager.Stub
}
pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
- if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
+ if (pkg.getAdoptPermissions() != null) {
// This package wants to adopt ownership of permissions from
// another package.
- for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
- final String origName = pkg.mAdoptPermissions.get(i);
+ for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) {
+ final String origName = pkg.getAdoptPermissions().get(i);
final PackageSetting orig = mSettings.getPackageLPr(origName);
if (orig != null) {
if (verifyPackageUpdateLPr(orig, pkg)) {
Slog.i(TAG, "Adopting permissions from " + origName + " to "
- + pkg.packageName);
- mSettings.mPermissions.transferPermissions(origName, pkg.packageName);
+ + pkg.getPackageName());
+ mSettings.mPermissions.transferPermissions(origName, pkg.getPackageName());
}
}
}
@@ -10500,21 +10469,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- if (oldPkgSetting != null) {
- synchronized (mLock) {
- mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting);
- }
- }
- } else {
- final int userId = user == null ? 0 : user.getIdentifier();
- // Modify state for the given package setting
- commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
- (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
- if (pkgSetting.getInstantApp(userId)) {
- mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
- }
+ final int userId = user == null ? 0 : user.getIdentifier();
+ // Modify state for the given package setting
+ commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
+ (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
+ if (pkgSetting.getInstantApp(userId)) {
+ mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
}
+
+ return pkg;
}
/**
@@ -10522,18 +10485,19 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>This may differ from the package's actual name if the application has already
* been installed under one of this package's original names.
*/
- private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg,
+ private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg,
@Nullable String renamedPkgName) {
if (isPackageRenamed(pkg, renamedPkgName)) {
- return pkg.mRealPackage;
+ return pkg.getRealPackage();
}
return null;
}
/** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */
- private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg,
+ private static boolean isPackageRenamed(@NonNull AndroidPackage pkg,
@Nullable String renamedPkgName) {
- return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName);
+ return pkg.getOriginalPackages() != null
+ && pkg.getOriginalPackages().contains(renamedPkgName);
}
/**
@@ -10544,14 +10508,14 @@ public class PackageManagerService extends IPackageManager.Stub
* shared user [if any].
*/
@GuardedBy("mLock")
- private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg,
+ private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
@Nullable String renamedPkgName) {
if (!isPackageRenamed(pkg, renamedPkgName)) {
return null;
}
- for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) {
+ for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) {
final PackageSetting originalPs =
- mSettings.getPackageLPr(pkg.mOriginalPackages.get(i));
+ mSettings.getPackageLPr(pkg.getOriginalPackages().get(i));
if (originalPs != null) {
// the package is already installed under its original name...
// but, should we use it?
@@ -10559,18 +10523,18 @@ public class PackageManagerService extends IPackageManager.Stub
// the new package is incompatible with the original
continue;
} else if (originalPs.sharedUser != null) {
- if (!originalPs.sharedUser.name.equals(pkg.mSharedUserId)) {
+ if (!originalPs.sharedUser.name.equals(pkg.getSharedUserId())) {
// the shared user id is incompatible with the original
Slog.w(TAG, "Unable to migrate data from " + originalPs.name
- + " to " + pkg.packageName + ": old uid "
+ + " to " + pkg.getPackageName() + ": old uid "
+ originalPs.sharedUser.name
- + " differs from " + pkg.mSharedUserId);
+ + " differs from " + pkg.getSharedUserId());
continue;
}
// TODO: Add case when shared user id is added [b/28144775]
} else {
if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
- + pkg.packageName + " to old name " + originalPs.name);
+ + pkg.getPackageName() + " to old name " + originalPs.name);
}
return originalPs;
}
@@ -10583,19 +10547,19 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>When we've already installed the package under an original name, update
* the new package so we can continue to have the old name.
*/
- private static void ensurePackageRenamed(@NonNull PackageParser.Package pkg,
+ private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
@NonNull String renamedPackageName) {
- if (pkg.mOriginalPackages == null
- || !pkg.mOriginalPackages.contains(renamedPackageName)
- || pkg.packageName.equals(renamedPackageName)) {
+ if (parsedPackage.getOriginalPackages() == null
+ || !parsedPackage.getOriginalPackages().contains(renamedPackageName)
+ || parsedPackage.getPackageName().equals(renamedPackageName)) {
return;
}
- pkg.setPackageName(renamedPackageName);
+ parsedPackage.setPackageName(renamedPackageName);
}
/**
* Applies the adjusted ABI calculated by
- * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
+ * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all
* relevant packages and settings.
* @param sharedUserSetting The {@code SharedUserSetting} to adjust
* @param scannedPackage the package being scanned or null
@@ -10603,22 +10567,20 @@ public class PackageManagerService extends IPackageManager.Stub
* @return the list of code paths that belong to packages that had their ABIs adjusted.
*/
private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
- PackageParser.Package scannedPackage, String adjustedAbi) {
+ ParsedPackage scannedPackage, String adjustedAbi) {
if (scannedPackage != null) {
- scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+ scannedPackage.setPrimaryCpuAbi(adjustedAbi);
}
List<String> changedAbiCodePath = null;
for (PackageSetting ps : sharedUserSetting.packages) {
- if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+ if (scannedPackage == null || !scannedPackage.getPackageName().equals(ps.name)) {
if (ps.primaryCpuAbiString != null) {
continue;
}
ps.primaryCpuAbiString = adjustedAbi;
- if (ps.pkg != null && ps.pkg.applicationInfo != null
- && !TextUtils.equals(
- adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
- ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+ if (ps.pkg != null && !TextUtils.equals(adjustedAbi, ps.pkg.getPrimaryCpuAbi())) {
+ ps.pkg.mutate().setPrimaryCpuAbi(adjustedAbi);
if (DEBUG_ABI_SELECTION) {
Slog.i(TAG,
"Adjusting ABI for " + ps.name + " to " + adjustedAbi
@@ -10640,42 +10602,42 @@ public class PackageManagerService extends IPackageManager.Stub
* Sets the enabled state of components configured through {@link SystemConfig}.
* This modifies the {@link PackageSetting} object.
**/
- static void configurePackageComponents(PackageParser.Package pkg) {
+ static void configurePackageComponents(AndroidPackage pkg) {
final ArrayMap<String, Boolean> componentsEnabledStates = SystemConfig.getInstance()
- .getComponentsEnabledStates(pkg.packageName);
+ .getComponentsEnabledStates(pkg.getPackageName());
if (componentsEnabledStates == null) {
return;
}
- for (int i = pkg.activities.size() - 1; i >= 0; i--) {
- final PackageParser.Activity component = pkg.activities.get(i);
+ for (int i = ArrayUtils.size(pkg.getActivities()) - 1; i >= 0; i--) {
+ final ParsedActivity component = pkg.getActivities().get(i);
final Boolean enabled = componentsEnabledStates.get(component.className);
if (enabled != null) {
- component.info.enabled = enabled;
+ component.setEnabled(enabled);
}
}
- for (int i = pkg.receivers.size() - 1; i >= 0; i--) {
- final PackageParser.Activity component = pkg.receivers.get(i);
+ for (int i = ArrayUtils.size(pkg.getReceivers()) - 1; i >= 0; i--) {
+ final ParsedActivity component = pkg.getReceivers().get(i);
final Boolean enabled = componentsEnabledStates.get(component.className);
if (enabled != null) {
- component.info.enabled = enabled;
+ component.setEnabled(enabled);
}
}
- for (int i = pkg.providers.size() - 1; i >= 0; i--) {
- final PackageParser.Provider component = pkg.providers.get(i);
+ for (int i = ArrayUtils.size(pkg.getProviders()) - 1; i >= 0; i--) {
+ final ParsedProvider component = pkg.getProviders().get(i);
final Boolean enabled = componentsEnabledStates.get(component.className);
if (enabled != null) {
- component.info.enabled = enabled;
+ component.setEnabled(enabled);
}
}
- for (int i = pkg.services.size() - 1; i >= 0; i--) {
- final PackageParser.Service component = pkg.services.get(i);
+ for (int i = ArrayUtils.size(pkg.getServices()) - 1; i >= 0; i--) {
+ final ParsedService component = pkg.getServices().get(i);
final Boolean enabled = componentsEnabledStates.get(component.className);
if (enabled != null) {
- component.info.enabled = enabled;
+ component.setEnabled(enabled);
}
}
}
@@ -10702,7 +10664,7 @@ public class PackageManagerService extends IPackageManager.Stub
throws PackageManagerException {
final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
final UserManagerInternal userManager = injector.getUserManagerInternal();
- final PackageParser.Package pkg = request.pkg;
+ ParsedPackage parsedPackage = request.parsedPackage;
PackageSetting pkgSetting = request.pkgSetting;
final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
final PackageSetting originalPkgSetting = request.originalPkgSetting;
@@ -10717,13 +10679,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
- Log.d(TAG, "Scanning package " + pkg.packageName);
+ Log.d(TAG, "Scanning package " + parsedPackage.getPackageName());
}
// Initialize package source and resource directories
- final File scanFile = new File(pkg.codePath);
- final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
- final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
+ final File destCodeFile = new File(parsedPackage.getAppInfoCodePath());
+ final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath());
// We keep references to the derived CPU Abis from settings in oder to reuse
// them in the case where we're not upgrading or booting for the first time.
@@ -10742,7 +10703,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
PackageManagerService.reportSettingsProblem(Log.WARN,
- "Package " + pkg.packageName + " shared user changed from "
+ "Package " + parsedPackage.getPackageName() + " shared user changed from "
+ (pkgSetting.sharedUser != null
? pkgSetting.sharedUser.name : "<nothing>")
+ " to "
@@ -10752,30 +10713,28 @@ public class PackageManagerService extends IPackageManager.Stub
}
String[] usesStaticLibraries = null;
- if (pkg.usesStaticLibraries != null) {
- usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
- pkg.usesStaticLibraries.toArray(usesStaticLibraries);
+ if (parsedPackage.getUsesStaticLibraries() != null) {
+ usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
+ parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
}
final boolean createNewPackage = (pkgSetting == null);
if (createNewPackage) {
- final String parentPackageName = (pkg.parentPackage != null)
- ? pkg.parentPackage.packageName : null;
final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;
// REMOVE SharedUserSetting from method; update in a separate call
- pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting,
- disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile,
- destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
- pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
- pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
- user, true /*allowInstall*/, instantApp, virtualPreload,
- parentPackageName, pkg.getChildPackageNames(),
- UserManagerService.getInstance(), usesStaticLibraries,
- pkg.usesStaticLibrariesVersions);
+ pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
+ originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
+ destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(),
+ parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
+ parsedPackage.getVersionCode(), parsedPackage.getFlags(),
+ parsedPackage.getPrivateFlags(), user, true /*allowInstall*/, instantApp,
+ virtualPreload, UserManagerService.getInstance(), usesStaticLibraries,
+ parsedPackage.getUsesStaticLibrariesVersions());
} else {
// make a deep copy to avoid modifying any existing system state.
pkgSetting = new PackageSetting(pkgSetting);
- pkgSetting.pkg = pkg;
+ // TODO(b/135203078): Remove entirely. Set package directly.
+ parsedPackage.setPackageSettingCallback(pkgSetting);
// REMOVE SharedUserSetting from method; update in a separate call.
//
@@ -10783,18 +10742,18 @@ public class PackageManagerService extends IPackageManager.Stub
// secondaryCpuAbi are not known at this point so we always update them
// to null here, only to reset them at a later point.
Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
- destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir,
- pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
- pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
- pkg.getChildPackageNames(), UserManagerService.getInstance(),
- usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+ destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(),
+ parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
+ parsedPackage.getFlags(), parsedPackage.getPrivateFlags(),
+ UserManagerService.getInstance(),
+ usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions());
}
if (createNewPackage && originalPkgSetting != null) {
// This is the initial transition from the original package, so,
// fix up the new package's name now. We must do this after looking
// up the package under its new name, so getPackageLP takes care of
// fiddling things correctly.
- pkg.setPackageName(originalPkgSetting.name);
+ parsedPackage.setPackageName(originalPkgSetting.name);
// File a report about this.
String msg = "New package " + pkgSetting.realName
@@ -10813,68 +10772,69 @@ public class PackageManagerService extends IPackageManager.Stub
if (disabledPkgSetting != null
|| (0 != (scanFlags & SCAN_NEW_INSTALL)
&& pkgSetting != null && pkgSetting.isSystem())) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ parsedPackage.mutate().setUpdatedSystemApp(true);
}
- pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, sharedUserSetting,
- injector.getCompatibility());
- pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
- userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId));
-
- pkg.mExtras = pkgSetting;
- pkg.applicationInfo.processName = fixProcessName(
- pkg.applicationInfo.packageName,
- pkg.applicationInfo.processName);
+ parsedPackage
+ .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
+ injector.getCompatibility()))
+ .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
+ userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)))
+ .setProcessName(fixProcessName(parsedPackage.getPackageName(),
+ parsedPackage.getProcessName()));
if (!isPlatformPackage) {
// Get all of our default paths setup
- pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
+ parsedPackage.initForUser(UserHandle.USER_SYSTEM);
}
- if (pkg.isSystem()) {
- configurePackageComponents(pkg);
+ if (parsedPackage.isSystem()) {
+ configurePackageComponents(parsedPackage);
}
- final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
+ final String cpuAbiOverride = deriveAbiOverride(parsedPackage.getCpuAbiOverride(),
+ pkgSetting);
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
- final boolean extractNativeLibs = !pkg.isLibrary();
+ final boolean extractNativeLibs = !parsedPackage.isLibrary();
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
- packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
- derivedAbi.first.applyTo(pkg);
- derivedAbi.second.applyTo(pkg);
+ packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride,
+ extractNativeLibs);
+ derivedAbi.first.applyTo(parsedPackage);
+ derivedAbi.second.applyTo(parsedPackage);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Some system apps still use directory structure for native libraries
// in which case we might end up not detecting abi solely based on apk
// structure. Try to detect abi based on directory structure.
- if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
- pkg.applicationInfo.primaryCpuAbi == null) {
+ if (isSystemApp(parsedPackage) && !parsedPackage.isUpdatedSystemApp() &&
+ parsedPackage.getPrimaryCpuAbi() == null) {
final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
- pkg);
- abis.applyTo(pkg);
+ parsedPackage);
+ abis.applyTo(parsedPackage);
abis.applyTo(pkgSetting);
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
- packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
- nativeLibraryPaths.applyTo(pkg);
+ packageAbiHelper.getNativeLibraryPaths(parsedPackage,
+ sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(parsedPackage);
}
} else {
// This is not a first boot or an upgrade, don't bother deriving the
// ABI during the scan. Instead, trust the value that was stored in the
// package setting.
- pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
- pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
+ parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings)
+ .setSecondaryCpuAbi(secondaryCpuAbiFromSettings);
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
- packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
- nativeLibraryPaths.applyTo(pkg);
+ packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(parsedPackage);
if (DEBUG_ABI_SELECTION) {
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
- pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
- pkg.applicationInfo.secondaryCpuAbi);
+ parsedPackage.getPackageName() + " " + parsedPackage.getPrimaryCpuAbi()
+ + ", " + parsedPackage.getSecondaryCpuAbi());
}
}
} else {
@@ -10882,8 +10842,8 @@ public class PackageManagerService extends IPackageManager.Stub
// We haven't run dex-opt for this move (since we've moved the compiled output too)
// but we already have this packages package info in the PackageSetting. We just
// use that and derive the native library path based on the new codepath.
- pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString;
- pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString;
+ parsedPackage.setPrimaryCpuAbi(pkgSetting.primaryCpuAbiString)
+ .setSecondaryCpuAbi(pkgSetting.secondaryCpuAbiString);
}
// Set native library paths again. For moves, the path will be updated based on the
@@ -10891,8 +10851,8 @@ public class PackageManagerService extends IPackageManager.Stub
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
- packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
- nativeLibraryPaths.applyTo(pkg);
+ packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(parsedPackage);
}
// This is a special case for the "system" package, where the ABI is
@@ -10900,8 +10860,8 @@ public class PackageManagerService extends IPackageManager.Stub
// of this ABI so that we can deal with "normal" applications that run under
// the same UID correctly.
if (isPlatformPackage) {
- pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
- Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
+ parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() ?
+ Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]);
}
// If there's a mismatch between the abi-override in the package setting
@@ -10909,34 +10869,34 @@ public class PackageManagerService extends IPackageManager.Stub
// would've already compiled the app without taking the package setting into
// account.
if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
- if (cpuAbiOverride == null && pkg.packageName != null) {
+ if (cpuAbiOverride == null && parsedPackage.getPackageName() != null) {
Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
- " for package " + pkg.packageName);
+ " for package " + parsedPackage.getPackageName());
}
}
- pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
- pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+ pkgSetting.primaryCpuAbiString = parsedPackage.getPrimaryCpuAbi();
+ pkgSetting.secondaryCpuAbiString = parsedPackage.getSecondaryCpuAbi();
pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
// Copy the derived override back to the parsed package, so that we can
// update the package settings accordingly.
- pkg.cpuAbiOverride = cpuAbiOverride;
+ parsedPackage.setCpuAbiOverride(cpuAbiOverride);
if (DEBUG_ABI_SELECTION) {
- Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName
- + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
- + pkg.applicationInfo.nativeLibraryRootRequiresIsa);
+ Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName()
+ + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa="
+ + parsedPackage.isNativeLibraryRootRequiresIsa());
}
// Push the derived path down into PackageSettings so we know what to
// clean up at uninstall time.
- pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir;
+ pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir();
if (DEBUG_ABI_SELECTION) {
- Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" +
- " primary=" + pkg.applicationInfo.primaryCpuAbi +
- " secondary=" + pkg.applicationInfo.secondaryCpuAbi);
+ Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" +
+ " primary=" + parsedPackage.getPrimaryCpuAbi() +
+ " secondary=" + parsedPackage.getSecondaryCpuAbi());
}
if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
@@ -10946,22 +10906,20 @@ public class PackageManagerService extends IPackageManager.Stub
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
- changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
+ changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, parsedPackage,
packageAbiHelper.getAdjustedAbiForSharedUser(
- pkgSetting.sharedUser.packages, pkg));
+ pkgSetting.sharedUser.packages, parsedPackage));
}
- if (isUnderFactoryTest && pkg.requestedPermissions.contains(
- android.Manifest.permission.FACTORY_TEST)) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
- }
+ parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions()
+ .contains(android.Manifest.permission.FACTORY_TEST));
- if (isSystemApp(pkg)) {
+ if (parsedPackage.isSystem()) {
pkgSetting.setIsOrphaned(true);
}
// Take care of first install / last update times.
- final long scanFileTime = getLastModifiedTime(pkg);
+ final long scanFileTime = getLastModifiedTime(parsedPackage);
if (currentTime != 0) {
if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
@@ -10979,32 +10937,33 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
pkgSetting.setTimeStamp(scanFileTime);
-
- pkgSetting.pkg = pkg;
- pkgSetting.pkgFlags = pkg.applicationInfo.flags;
- if (pkg.getLongVersionCode() != pkgSetting.versionCode) {
- pkgSetting.versionCode = pkg.getLongVersionCode();
+ // TODO(b/135203078): Remove, move to constructor
+ parsedPackage.setPackageSettingCallback(pkgSetting);
+ pkgSetting.pkgFlags = parsedPackage.getFlags();
+ if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
+ pkgSetting.versionCode = parsedPackage.getLongVersionCode();
}
// Update volume if needed
- final String volumeUuid = pkg.applicationInfo.volumeUuid;
+ final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid();
if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
Slog.i(PackageManagerService.TAG,
"Update" + (pkgSetting.isSystem() ? " system" : "")
- + " package " + pkg.packageName
+ + " package " + parsedPackage.getPackageName()
+ " volume from " + pkgSetting.volumeUuid
+ " to " + volumeUuid);
pkgSetting.volumeUuid = volumeUuid;
}
SharedLibraryInfo staticSharedLibraryInfo = null;
- if (!TextUtils.isEmpty(pkg.staticSharedLibName)) {
- staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(pkg);
+ if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
+ staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage);
}
List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
- if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
- dynamicSharedLibraryInfos = new ArrayList<>(pkg.libraryNames.size());
- for (String name : pkg.libraryNames) {
- dynamicSharedLibraryInfos.add(SharedLibraryInfo.createForDynamic(pkg, name));
+ if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
+ dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
+ for (String name : parsedPackage.getLibraryNames()) {
+ dynamicSharedLibraryInfos.add(
+ SharedLibraryInfo.createForDynamic(parsedPackage, name));
}
}
@@ -11040,22 +10999,21 @@ public class PackageManagerService extends IPackageManager.Stub
*
* @throws PackageManagerException If bytecode could not be found when it should exist
*/
- private static void assertCodePolicy(PackageParser.Package pkg)
+ private static void assertCodePolicy(AndroidPackage pkg)
throws PackageManagerException {
- final boolean shouldHaveCode =
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
- if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) {
+ final boolean shouldHaveCode = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Package " + pkg.baseCodePath + " code is missing");
+ "Package " + pkg.getBaseCodePath() + " code is missing");
}
- if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
- for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+ if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) {
+ for (int i = 0; i < pkg.getSplitCodePaths().length; i++) {
final boolean splitShouldHaveCode =
- (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
- if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) {
+ (pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ if (splitShouldHaveCode && !apkHasCode(pkg.getSplitCodePaths()[i])) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Package " + pkg.splitCodePaths[i] + " code is missing");
+ "Package " + pkg.getSplitCodePaths()[i] + " code is missing");
}
}
}
@@ -11068,118 +11026,59 @@ public class PackageManagerService extends IPackageManager.Stub
* Implementation detail: This method must NOT have any side effect. It would
* ideally be static, but, it requires locks to read system state.
*/
- private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int parseFlags,
- final @ScanFlags int scanFlags, PackageParser.Package platformPkg) {
+ private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags,
+ final @ScanFlags int scanFlags, AndroidPackage platformPkg) {
if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- if (pkg.applicationInfo.isDirectBootAware()) {
- // we're direct boot aware; set for all components
- for (PackageParser.Service s : pkg.services) {
- s.info.directBootAware = true;
- }
- for (PackageParser.Provider p : pkg.providers) {
- p.info.directBootAware = true;
- }
- for (PackageParser.Activity a : pkg.activities) {
- a.info.directBootAware = true;
- }
- for (PackageParser.Activity r : pkg.receivers) {
- r.info.directBootAware = true;
- }
+ parsedPackage.setSystem(true);
+ // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag
+ // is set during parse.
+ if (parsedPackage.isDirectBootAware()) {
+ parsedPackage.setAllComponentsDirectBootAware(true);
}
- if (compressedFileExists(pkg.codePath)) {
- pkg.isStub = true;
+ if (compressedFileExists(parsedPackage.getCodePath())) {
+ parsedPackage.setIsStub(true);
}
} else {
- // non system apps can't be flagged as core
- pkg.coreApp = false;
- // clear flags not applicable to regular apps
- pkg.applicationInfo.flags &=
- ~ApplicationInfo.FLAG_PERSISTENT;
- pkg.applicationInfo.privateFlags &=
- ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
- pkg.applicationInfo.privateFlags &=
- ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
- // cap permission priorities
- if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
- for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
- pkg.permissionGroups.get(i).info.priority = 0;
- }
- }
+ parsedPackage
+ // non system apps can't be flagged as core
+ .setCoreApp(false)
+ // clear flags not applicable to regular apps
+ .setPersistent(false)
+ .setDefaultToDeviceProtectedStorage(false)
+ .setDirectBootAware(false)
+ // non system apps can't have permission priority
+ .capPermissionPriorities();
}
if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
- // clear protected broadcasts
- pkg.protectedBroadcasts = null;
- // ignore export request for single user receivers
- if (pkg.receivers != null) {
- for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
- final PackageParser.Activity receiver = pkg.receivers.get(i);
- if ((receiver.info.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
- receiver.info.exported = false;
- }
- }
- }
- // ignore export request for single user services
- if (pkg.services != null) {
- for (int i = pkg.services.size() - 1; i >= 0; --i) {
- final PackageParser.Service service = pkg.services.get(i);
- if ((service.info.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
- service.info.exported = false;
- }
- }
- }
- // ignore export request for single user providers
- if (pkg.providers != null) {
- for (int i = pkg.providers.size() - 1; i >= 0; --i) {
- final PackageParser.Provider provider = pkg.providers.get(i);
- if ((provider.info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
- provider.info.exported = false;
- }
- }
- }
- }
-
- if ((scanFlags & SCAN_AS_PRIVILEGED) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ parsedPackage
+ .clearProtectedBroadcasts()
+ .markNotActivitiesAsNotExportedIfSingleUser();
}
- if ((scanFlags & SCAN_AS_OEM) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
- }
-
- if ((scanFlags & SCAN_AS_VENDOR) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
- }
-
- if ((scanFlags & SCAN_AS_PRODUCT) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
- }
-
- if ((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
- }
-
- if ((scanFlags & SCAN_AS_ODM) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM;
- }
+ parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0)
+ .setOem((scanFlags & SCAN_AS_OEM) != 0)
+ .setVendor((scanFlags & SCAN_AS_VENDOR) != 0)
+ .setProduct((scanFlags & SCAN_AS_PRODUCT) != 0)
+ .setSystemExt((scanFlags & SCAN_AS_SYSTEM_EXT) != 0)
+ .setOdm((scanFlags & SCAN_AS_ODM) != 0);
// Check if the package is signed with the same key as the platform package.
- if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) ||
- (platformPkg != null && compareSignatures(
- platformPkg.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH)) {
- pkg.applicationInfo.privateFlags |=
- ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
- }
-
- if (!isSystemApp(pkg)) {
+ parsedPackage.setSignedWithPlatformKey(
+ (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())
+ || (platformPkg != null && compareSignatures(
+ platformPkg.getSigningDetails().signatures,
+ parsedPackage.getSigningDetails().signatures
+ ) == PackageManager.SIGNATURE_MATCH))
+ );
+
+ if (!isSystemApp(parsedPackage)) {
// Only system apps can use these features.
- pkg.mOriginalPackages = null;
- pkg.mRealPackage = null;
- pkg.mAdoptPermissions = null;
+ parsedPackage.clearOriginalPackages()
+ .setRealPackage(null)
+ .clearAdoptPermissions();
}
- PackageBackwardCompatibility.modifySharedLibraries(pkg);
+ PackageBackwardCompatibility.modifySharedLibraries(parsedPackage);
}
private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
@@ -11199,15 +11098,15 @@ public class PackageManagerService extends IPackageManager.Stub
*
* @throws PackageManagerException If the package fails any of the validation checks
*/
- private void assertPackageIsValid(PackageParser.Package pkg, final @ParseFlags int parseFlags,
+ private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags,
final @ScanFlags int scanFlags)
throws PackageManagerException {
if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
assertCodePolicy(pkg);
}
- if (pkg.applicationInfo.getCodePath() == null ||
- pkg.applicationInfo.getResourcePath() == null) {
+ if (pkg.getAppInfoCodePath() == null ||
+ pkg.getAppInfoResourcePath() == null) {
// Bail out. The resource and code paths haven't been set.
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Code and resource paths haven't been set correctly");
@@ -11218,9 +11117,10 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
if ((isUserInstall || isFirstBootOrUpgrade)
- && mApexManager.isApexPackage(pkg.packageName)) {
+ && mApexManager.isApexPackage(pkg.getPackageName())) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- pkg.packageName + " is an APEX package and can't be installed as an APK.");
+ pkg.getPackageName()
+ + " is an APEX package and can't be installed as an APK.");
}
// Make sure we're not adding any bogus keyset info
@@ -11229,11 +11129,11 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
// The special "android" package can only be defined once
- if (pkg.packageName.equals("android")) {
+ if (pkg.getPackageName().equals("android")) {
if (mAndroidApplication != null) {
Slog.w(TAG, "*************************************************");
Slog.w(TAG, "Core android package being redefined. Skipping.");
- Slog.w(TAG, " codePath=" + pkg.codePath);
+ Slog.w(TAG, " codePath=" + pkg.getCodePath());
Slog.w(TAG, "*************************************************");
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
"Core android package being redefined. Skipping.");
@@ -11241,23 +11141,24 @@ public class PackageManagerService extends IPackageManager.Stub
}
// A package name must be unique; don't allow duplicates
- if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) {
+ if ((scanFlags & SCAN_NEW_INSTALL) == 0
+ && mPackages.containsKey(pkg.getPackageName())) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Application package " + pkg.packageName
+ "Application package " + pkg.getPackageName()
+ " already installed. Skipping duplicate.");
}
- if (pkg.applicationInfo.isStaticSharedLibrary()) {
+ if (pkg.isStaticSharedLibrary()) {
// Static libs have a synthetic package name containing the version
// but we still want the base name to be unique.
if ((scanFlags & SCAN_NEW_INSTALL) == 0
- && mPackages.containsKey(pkg.manifestPackageName)) {
+ && mPackages.containsKey(pkg.getManifestPackageName())) {
throw new PackageManagerException(
"Duplicate static shared lib provider package");
}
// Static shared libraries should have at least O target SDK
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
throw new PackageManagerException(
"Packages declaring static-shared libs must target O SDK or higher");
}
@@ -11270,73 +11171,67 @@ public class PackageManagerService extends IPackageManager.Stub
// Package declaring static a shared lib cannot be renamed since the package
// name is synthetic and apps can't code around package manager internals.
- if (!ArrayUtils.isEmpty(pkg.mOriginalPackages)) {
+ if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) {
throw new PackageManagerException(
"Packages declaring static-shared libs cannot be renamed");
}
- // Package declaring static a shared lib cannot declare child packages
- if (!ArrayUtils.isEmpty(pkg.childPackages)) {
- throw new PackageManagerException(
- "Packages declaring static-shared libs cannot have child packages");
- }
-
// Package declaring static a shared lib cannot declare dynamic libs
- if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
+ if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) {
throw new PackageManagerException(
"Packages declaring static-shared libs cannot declare dynamic libs");
}
// Package declaring static a shared lib cannot declare shared users
- if (pkg.mSharedUserId != null) {
+ if (pkg.getSharedUserId() != null) {
throw new PackageManagerException(
"Packages declaring static-shared libs cannot declare shared users");
}
// Static shared libs cannot declare activities
- if (!pkg.activities.isEmpty()) {
+ if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare activities");
}
// Static shared libs cannot declare services
- if (!pkg.services.isEmpty()) {
+ if (pkg.getServices() != null && !pkg.getServices().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare services");
}
// Static shared libs cannot declare providers
- if (!pkg.providers.isEmpty()) {
+ if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare content providers");
}
// Static shared libs cannot declare receivers
- if (!pkg.receivers.isEmpty()) {
+ if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare broadcast receivers");
}
// Static shared libs cannot declare permission groups
- if (!pkg.permissionGroups.isEmpty()) {
+ if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare permission groups");
}
// Static shared libs cannot declare permissions
- if (!pkg.permissions.isEmpty()) {
+ if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare permissions");
}
// Static shared libs cannot declare protected broadcasts
- if (pkg.protectedBroadcasts != null) {
+ if (pkg.getProtectedBroadcasts() != null) {
throw new PackageManagerException(
"Static shared libs cannot declare protected broadcasts");
}
// Static shared libs cannot be overlay targets
- if (pkg.mOverlayTarget != null) {
+ if (pkg.getOverlayTarget() != null) {
throw new PackageManagerException(
"Static shared libs cannot be overlay targets");
}
@@ -11346,16 +11241,17 @@ public class PackageManagerService extends IPackageManager.Stub
long maxVersionCode = Long.MAX_VALUE;
LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
- pkg.staticSharedLibName);
+ pkg.getStaticSharedLibName());
if (versionedLib != null) {
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
SharedLibraryInfo libInfo = versionedLib.valueAt(i);
final long libVersionCode = libInfo.getDeclaringPackage()
.getLongVersionCode();
- if (libInfo.getLongVersion() < pkg.staticSharedLibVersion) {
+ if (libInfo.getLongVersion() < pkg.getStaticSharedLibVersion()) {
minVersionCode = Math.max(minVersionCode, libVersionCode + 1);
- } else if (libInfo.getLongVersion() > pkg.staticSharedLibVersion) {
+ } else if (libInfo.getLongVersion()
+ > pkg.getStaticSharedLibVersion()) {
maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1);
} else {
minVersionCode = maxVersionCode = libVersionCode;
@@ -11370,23 +11266,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- // Only privileged apps and updated privileged apps can add child packages.
- if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
- if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
- throw new PackageManagerException("Only privileged apps can add child "
- + "packages. Ignoring package " + pkg.packageName);
- }
- final int childCount = pkg.childPackages.size();
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName,
- childPkg.packageName)) {
- throw new PackageManagerException("Can't override child of "
- + "another disabled app. Ignoring package " + pkg.packageName);
- }
- }
- }
-
// If we're only installing presumed-existing packages, require that the
// scanned APK is both already known and at the path previously established
// for it. Previously unknown packages we pick up normally, but if we have an
@@ -11396,29 +11275,30 @@ public class PackageManagerService extends IPackageManager.Stub
// to the user-installed location. If we don't allow this change, any newer,
// user-installed version of the application will be ignored.
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
- if (mExpectingBetter.containsKey(pkg.packageName)) {
+ if (mExpectingBetter.containsKey(pkg.getPackageName())) {
logCriticalInfo(Log.WARN,
- "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
+ "Relax SCAN_REQUIRE_KNOWN requirement for package "
+ + pkg.getPackageName());
} else {
- PackageSetting known = mSettings.getPackageLPr(pkg.packageName);
+ PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName());
if (known != null) {
if (DEBUG_PACKAGE_SCANNING) {
- Log.d(TAG, "Examining " + pkg.codePath
+ Log.d(TAG, "Examining " + pkg.getCodePath()
+ " and requiring known paths " + known.codePathString
+ " & " + known.resourcePathString);
}
- if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
- || !pkg.applicationInfo.getResourcePath().equals(
+ if (!pkg.getAppInfoCodePath().equals(known.codePathString)
+ || !pkg.getAppInfoResourcePath().equals(
known.resourcePathString)) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
- "Application package " + pkg.packageName
- + " found at " + pkg.applicationInfo.getCodePath()
+ "Application package " + pkg.getPackageName()
+ + " found at " + pkg.getAppInfoCodePath()
+ " but expected at " + known.codePathString
+ "; ignoring.");
}
} else {
throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- "Application package " + pkg.packageName
+ "Application package " + pkg.getPackageName()
+ " not found; ignoring.");
}
}
@@ -11433,11 +11313,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Verify that packages sharing a user with a privileged app are marked as privileged.
- if (!pkg.isPrivileged() && (pkg.mSharedUserId != null)) {
+ if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) {
SharedUserSetting sharedUserSetting = null;
try {
- sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
- } catch (PackageManagerException ignore) {}
+ sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(),
+ 0, 0, false);
+ } catch (PackageManagerException ignore) {
+ }
if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
// Exempt SharedUsers signed with the platform key.
PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
@@ -11445,18 +11327,18 @@ public class PackageManagerService extends IPackageManager.Stub
!= PackageParser.SigningDetails.UNKNOWN)
&& (compareSignatures(
platformPkgSetting.signatures.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures)
+ pkg.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH)) {
throw new PackageManagerException("Apps that share a user with a " +
"privileged app must themselves be marked as privileged. " +
- pkg.packageName + " shares privileged user " +
- pkg.mSharedUserId + ".");
+ pkg.getPackageName() + " shares privileged user " +
+ pkg.getSharedUserId() + ".");
}
}
}
// Apply policies specific for runtime resource overlays (RROs).
- if (pkg.mOverlayTarget != null) {
+ if (pkg.getOverlayTarget() != null) {
// System overlays have some restrictions on their use of the 'static' state.
if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
// We are scanning a system overlay. This can be the first scan of the
@@ -11464,54 +11346,62 @@ public class PackageManagerService extends IPackageManager.Stub
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
// This must be an update to a system overlay.
final PackageSetting previousPkg = assertNotNull(
- mSettings.getPackageLPr(pkg.packageName),
+ mSettings.getPackageLPr(pkg.getPackageName()),
"previous package state not present");
// previousPkg.pkg may be null: the package will be not be scanned if the
// package manager knows there is a newer version on /data.
// TODO[b/79435695]: Find a better way to keep track of the "static"
// property for RROs instead of having to parse packages on /system
- PackageParser.Package ppkg = previousPkg.pkg;
+ AndroidPackage ppkg = previousPkg.pkg;
if (ppkg == null) {
try {
final PackageParser pp = new PackageParser();
- ppkg = pp.parsePackage(previousPkg.codePath,
- parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR);
+ // TODO(b/135203078): Do we really need to parse here? Maybe use
+ // a shortened path?
+ ppkg = pp.parseParsedPackage(previousPkg.codePath,
+ parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR,
+ false)
+ .hideAsFinal();
} catch (PackageParserException e) {
Slog.w(TAG, "failed to parse " + previousPkg.codePath, e);
}
}
// Static overlays cannot be updated.
- if (ppkg != null && ppkg.mOverlayIsStatic) {
- throw new PackageManagerException("Overlay " + pkg.packageName +
- " is static and cannot be upgraded.");
+ if (ppkg != null && ppkg.isOverlayIsStatic()) {
+ throw new PackageManagerException("Overlay "
+ + pkg.getPackageName()
+ + " is static and cannot be upgraded.");
// Non-static overlays cannot be converted to static overlays.
- } else if (pkg.mOverlayIsStatic) {
- throw new PackageManagerException("Overlay " + pkg.packageName +
- " cannot be upgraded into a static overlay.");
+ } else if (pkg.isOverlayIsStatic()) {
+ throw new PackageManagerException("Overlay "
+ + pkg.getPackageName()
+ + " cannot be upgraded into a static overlay.");
}
}
} else {
// The overlay is a non-system overlay. Non-system overlays cannot be static.
- if (pkg.mOverlayIsStatic) {
- throw new PackageManagerException("Overlay " + pkg.packageName +
- " is static but not pre-installed.");
+ if (pkg.isOverlayIsStatic()) {
+ throw new PackageManagerException("Overlay "
+ + pkg.getPackageName()
+ + " is static but not pre-installed.");
}
// A non-preloaded overlay packages must have targetSdkVersion >= Q, or be
// signed with the platform certificate. Check this in increasing order of
// computational cost.
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) {
final PackageSetting platformPkgSetting =
mSettings.getPackageLPr("android");
if ((platformPkgSetting.signatures.mSigningDetails
!= PackageParser.SigningDetails.UNKNOWN)
&& (compareSignatures(
platformPkgSetting.signatures.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures)
+ pkg.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH)) {
- throw new PackageManagerException("Overlay " + pkg.packageName
+ throw new PackageManagerException("Overlay "
+ + pkg.getPackageName()
+ " must target Q or later, "
+ "or be signed with the platform certificate");
}
@@ -11521,18 +11411,19 @@ public class PackageManagerService extends IPackageManager.Stub
// only be used if it is signed with the same certificate as its target. If the
// target is already installed, check this here to augment the last line of
// defence which is OMS.
- if (pkg.mOverlayTargetName == null) {
+ if (pkg.getOverlayTargetName() == null) {
final PackageSetting targetPkgSetting =
- mSettings.getPackageLPr(pkg.mOverlayTarget);
+ mSettings.getPackageLPr(pkg.getOverlayTarget());
if (targetPkgSetting != null) {
if ((targetPkgSetting.signatures.mSigningDetails
!= PackageParser.SigningDetails.UNKNOWN)
&& (compareSignatures(
targetPkgSetting.signatures.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures)
+ pkg.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH)) {
- throw new PackageManagerException("Overlay " + pkg.packageName
- + " and target " + pkg.mOverlayTarget + " signed with"
+ throw new PackageManagerException("Overlay "
+ + pkg.getPackageName() + " and target "
+ + pkg.getOverlayTarget() + " signed with"
+ " different certificates, and the overlay lacks"
+ " <overlay android:targetName>");
}
@@ -11612,71 +11503,67 @@ public class PackageManagerService extends IPackageManager.Stub
* Adds a scanned package to the system. When this method is finished, the package will
* be available for query, resolution, etc...
*/
- private void commitPackageSettings(PackageParser.Package pkg,
- @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting,
+ private void commitPackageSettings(AndroidPackage pkg,
+ @Nullable AndroidPackage oldPkg, PackageSetting pkgSetting,
final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
- final String pkgName = pkg.packageName;
+ final String pkgName = pkg.getPackageName();
if (mCustomResolverComponentName != null &&
- mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
+ mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
setUpCustomResolverActivity(pkg);
}
- if (pkg.packageName.equals("android")) {
+ if (pkg.getPackageName().equals("android")) {
synchronized (mLock) {
- if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
- // Set up information for our fall-back user intent resolution activity.
- mPlatformPackage = pkg;
- pkg.mVersionCode = mSdkVersion;
- pkg.mVersionCodeMajor = 0;
- mAndroidApplication = pkg.applicationInfo;
- if (!mResolverReplaced) {
- mResolveActivity.applicationInfo = mAndroidApplication;
- mResolveActivity.name = ResolverActivity.class.getName();
- mResolveActivity.packageName = mAndroidApplication.packageName;
- mResolveActivity.processName = "system:ui";
- mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
- mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
- mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
- mResolveActivity.exported = true;
- mResolveActivity.enabled = true;
- mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_ORIENTATION
- | ActivityInfo.CONFIG_KEYBOARD
- | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
- mResolveInfo.activityInfo = mResolveActivity;
- mResolveInfo.priority = 0;
- mResolveInfo.preferredOrder = 0;
- mResolveInfo.match = 0;
- mResolveComponentName = new ComponentName(
- mAndroidApplication.packageName, mResolveActivity.name);
- }
- }
- }
- }
-
- ArrayList<PackageParser.Package> clientLibPkgs = null;
+ // Set up information for our fall-back user intent resolution activity.
+ mPlatformPackage = pkg;
+ mAndroidApplication = pkg.toAppInfoWithoutState();
+ if (!mResolverReplaced) {
+ mResolveActivity.applicationInfo = mAndroidApplication;
+ mResolveActivity.name = ResolverActivity.class.getName();
+ mResolveActivity.packageName = mAndroidApplication.packageName;
+ mResolveActivity.processName = "system:ui";
+ mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
+ mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+ mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
+ mResolveActivity.exported = true;
+ mResolveActivity.enabled = true;
+ mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+ mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_ORIENTATION
+ | ActivityInfo.CONFIG_KEYBOARD
+ | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+ mResolveInfo.activityInfo = mResolveActivity;
+ mResolveInfo.priority = 0;
+ mResolveInfo.preferredOrder = 0;
+ mResolveInfo.match = 0;
+ mResolveComponentName = new ComponentName(
+ mAndroidApplication.packageName, mResolveActivity.name);
+ }
+ }
+ }
+
+ ArrayList<AndroidPackage> clientLibPkgs = null;
// writer
synchronized (mLock) {
if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
commitSharedLibraryInfoLocked(info);
}
- final Map<String, PackageParser.Package> combinedPackages =
- reconciledPkg.getCombinedPackages();
+ final Map<String, AndroidPackage> combinedSigningDetails =
+ reconciledPkg.getCombinedAvailablePackages();
try {
// Shared libraries for the package need to be updated.
- updateSharedLibrariesLocked(pkg, null, combinedPackages);
+ updateSharedLibrariesLocked(pkg, null, combinedSigningDetails);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
}
// Update all applications that use this library. Skip when booting
// since this will be done after all packages are scaned.
if ((scanFlags & SCAN_BOOTING) == 0) {
- clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
+ clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedSigningDetails);
}
}
}
@@ -11700,9 +11587,9 @@ public class PackageManagerService extends IPackageManager.Stub
// Also need to kill any apps that are dependent on the library.
if (clientLibPkgs != null) {
for (int i=0; i<clientLibPkgs.size(); i++) {
- PackageParser.Package clientPkg = clientLibPkgs.get(i);
- killApplication(clientPkg.applicationInfo.packageName,
- clientPkg.applicationInfo.uid, "update lib");
+ AndroidPackage clientPkg = clientLibPkgs.get(i);
+ killApplication(clientPkg.getAppInfoPackageName(),
+ clientPkg.getUid(), "update lib");
}
}
@@ -11715,7 +11602,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
- mPackages.put(pkg.applicationInfo.packageName, pkg);
+ mPackages.put(pkg.getAppInfoPackageName(), pkg);
// Add the package's KeySets to the global KeySetManagerService
KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -11726,7 +11613,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Don't allow ephemeral applications to define new permissions groups.
if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
- Slog.w(TAG, "Permission groups from package " + pkg.packageName
+ Slog.w(TAG, "Permission groups from package " + pkg.getPackageName()
+ " ignored: instant apps cannot define new permission groups.");
} else {
mPermissionManager.addAllPermissionGroups(pkg, chatty);
@@ -11734,31 +11621,18 @@ public class PackageManagerService extends IPackageManager.Stub
// Don't allow ephemeral applications to define new permissions.
if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
- Slog.w(TAG, "Permissions from package " + pkg.packageName
+ Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
+ " ignored: instant apps cannot define new permissions.");
} else {
mPermissionManager.addAllPermissions(pkg, chatty);
}
- int collectionSize = pkg.instrumentation.size();
+ int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
StringBuilder r = null;
int i;
for (i = 0; i < collectionSize; i++) {
- PackageParser.Instrumentation a = pkg.instrumentation.get(i);
- a.info.packageName = pkg.applicationInfo.packageName;
- a.info.sourceDir = pkg.applicationInfo.sourceDir;
- a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
- a.info.splitNames = pkg.splitNames;
- a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
- a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
- a.info.splitDependencies = pkg.applicationInfo.splitDependencies;
- a.info.dataDir = pkg.applicationInfo.dataDir;
- a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
- a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
- a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
- a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
- a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
- a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
+ ParsedInstrumentation a = pkg.getInstrumentations().get(i);
+ a.setPackageName(pkg.getPackageName());
mInstrumentation.put(a.getComponentName(), a);
if (chatty) {
if (r == null) {
@@ -11766,19 +11640,16 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(a.getName());
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);
}
- if (pkg.protectedBroadcasts != null) {
- collectionSize = pkg.protectedBroadcasts.size();
+ if (pkg.getProtectedBroadcasts() != null) {
synchronized (mProtectedBroadcasts) {
- for (i = 0; i < collectionSize; i++) {
- mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
- }
+ mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
}
}
@@ -11802,14 +11673,14 @@ public class PackageManagerService extends IPackageManager.Stub
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private void setUpCustomResolverActivity(PackageParser.Package pkg) {
+ private void setUpCustomResolverActivity(AndroidPackage pkg) {
synchronized (mLock) {
mResolverReplaced = true;
// Set up information for custom user intent resolution activity.
- mResolveActivity.applicationInfo = pkg.applicationInfo;
+ mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState();
mResolveActivity.name = mCustomResolverComponentName.getClassName();
- mResolveActivity.packageName = pkg.applicationInfo.packageName;
- mResolveActivity.processName = pkg.applicationInfo.packageName;
+ mResolveActivity.packageName = pkg.getAppInfoPackageName();
+ mResolveActivity.processName = pkg.getAppInfoProcessName();
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
@@ -11876,22 +11747,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private void removePackageLI(PackageParser.Package pkg, boolean chatty) {
+ private void removePackageLI(AndroidPackage pkg, boolean chatty) {
// Remove the parent package setting
- PackageSetting ps = (PackageSetting) pkg.mExtras;
+ PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (ps != null) {
removePackageLI(ps.name, chatty);
} else if (DEBUG_REMOVE && chatty) {
- Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null");
- }
- // Remove the child package setting
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- ps = (PackageSetting) childPkg.mExtras;
- if (ps != null) {
- removePackageLI(ps.name, chatty);
- }
+ Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null");
}
}
@@ -11903,24 +11765,24 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
synchronized (mLock) {
- final PackageParser.Package removedPackage = mPackages.remove(packageName);
+ final AndroidPackage removedPackage = mPackages.remove(packageName);
if (removedPackage != null) {
cleanPackageDataStructuresLILPw(removedPackage, chatty);
}
}
}
- void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
+ void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) {
mComponentResolver.removeAllComponents(pkg, chatty);
- mAppsFilter.removePackage((PackageSetting) pkg.mExtras,
+ mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()),
mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages);
mPermissionManager.removeAllPermissions(pkg, chatty);
- final int instrumentationSize = pkg.instrumentation.size();
+ final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
StringBuilder r = null;
int i;
for (i = 0; i < instrumentationSize; i++) {
- PackageParser.Instrumentation a = pkg.instrumentation.get(i);
+ ParsedInstrumentation a = pkg.getInstrumentations().get(i);
mInstrumentation.remove(a.getComponentName());
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -11928,7 +11790,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(a.getName());
}
}
if (r != null) {
@@ -11936,12 +11798,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
r = null;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
// Only system apps can hold shared libraries.
- if (pkg.libraryNames != null) {
- final int libraryNamesSize = pkg.libraryNames.size();
+ if (pkg.getLibraryNames() != null) {
+ final int libraryNamesSize = pkg.getLibraryNames().size();
for (i = 0; i < libraryNamesSize; i++) {
- String name = pkg.libraryNames.get(i);
+ String name = pkg.getLibraryNames().get(i);
if (removeSharedLibraryLPw(name, 0)) {
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -11959,15 +11821,16 @@ public class PackageManagerService extends IPackageManager.Stub
r = null;
// Any package can hold static shared libraries.
- if (pkg.staticSharedLibName != null) {
- if (removeSharedLibraryLPw(pkg.staticSharedLibName, pkg.staticSharedLibVersion)) {
+ if (pkg.getStaticSharedLibName() != null) {
+ if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
+ pkg.getStaticSharedLibVersion())) {
if (DEBUG_REMOVE && chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
- r.append(pkg.staticSharedLibName);
+ r.append(pkg.getStaticSharedLibName());
}
}
}
@@ -12308,11 +12171,11 @@ public class PackageManagerService extends IPackageManager.Stub
// Cannot hide static shared libs as they are considered
// a part of the using app (emulating static linking). Also
// static libs are installed always on internal storage.
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null && pkg.staticSharedLibName != null) {
+ AndroidPackage pkg = mPackages.get(packageName);
+ if (pkg != null && pkg.getStaticSharedLibName() != null) {
Slog.w(TAG, "Cannot hide package: " + packageName
+ " providing static shared library: "
- + pkg.staticSharedLibName);
+ + pkg.getStaticSharedLibName());
return false;
}
// Only allow protected packages to hide themselves.
@@ -12358,17 +12221,17 @@ public class PackageManagerService extends IPackageManager.Stub
if (pkgSetting == null || !pkgSetting.isSystem()) {
return;
}
- PackageParser.Package pkg = pkgSetting.pkg;
- if (pkg != null && pkg.applicationInfo != null) {
- pkg.applicationInfo.hiddenUntilInstalled = hidden;
+ AndroidPackage pkg = pkgSetting.pkg;
+ if (pkg != null) {
+ pkg.mutate().setHiddenUntilInstalled(hidden);
}
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName);
if (disabledPs == null) {
return;
}
pkg = disabledPs.pkg;
- if (pkg != null && pkg.applicationInfo != null) {
- pkg.applicationInfo.hiddenUntilInstalled = hidden;
+ if (pkg != null) {
+ pkg.mutate().setHiddenUntilInstalled(hidden);
}
}
}
@@ -12560,7 +12423,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (installed) {
if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
!= 0 && pkgSetting.pkg != null) {
- whiteListedPermissions = pkgSetting.pkg.requestedPermissions;
+ whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions();
}
mPermissionManager.setWhitelistedRestrictedPermissions(packageName,
whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
@@ -12990,11 +12853,11 @@ public class PackageManagerService extends IPackageManager.Stub
// Cannot suspend static shared libs as they are considered
// a part of the using app (emulating static linking). Also
// static libs are installed always on internal storage.
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+ AndroidPackage pkg = mPackages.get(packageName);
+ if (pkg != null && pkg.isStaticSharedLibrary()) {
Slog.w(TAG, "Cannot suspend package: " + packageName
+ " providing static shared library: "
- + pkg.staticSharedLibName);
+ + pkg.getStaticSharedLibName());
continue;
}
}
@@ -13139,10 +13002,10 @@ public class PackageManagerService extends IPackageManager.Stub
private int getUidForVerifier(VerifierInfo verifierInfo) {
synchronized (mLock) {
- final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
+ final AndroidPackage pkg = mPackages.get(verifierInfo.packageName);
if (pkg == null) {
return -1;
- } else if (pkg.mSigningDetails.signatures.length != 1) {
+ } else if (pkg.getSigningDetails().signatures.length != 1) {
Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ " has more than one signature; ignoring");
return -1;
@@ -13156,7 +13019,7 @@ public class PackageManagerService extends IPackageManager.Stub
final byte[] expectedPublicKey;
try {
- final Signature verifierSig = pkg.mSigningDetails.signatures[0];
+ final Signature verifierSig = pkg.getSigningDetails().signatures[0];
final PublicKey publicKey = verifierSig.getPublicKey();
expectedPublicKey = publicKey.getEncoded();
} catch (CertificateException e) {
@@ -13171,7 +13034,7 @@ public class PackageManagerService extends IPackageManager.Stub
return -1;
}
- return pkg.applicationInfo.uid;
+ return pkg.getUid();
}
}
@@ -13347,26 +13210,33 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mLock) {
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null || pkg.activities == null) {
+ AndroidPackage pkg = mPackages.get(packageName);
+ if (pkg == null || ArrayUtils.isEmpty(pkg.getActivities())) {
return ParceledListSlice.emptyList();
}
- if (pkg.mExtras == null) {
+ final PackageSetting ps = getPackageSetting(pkg.getPackageName());
+ if (ps == null) {
return ParceledListSlice.emptyList();
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return ParceledListSlice.emptyList();
}
- final int count = pkg.activities.size();
+ final int count = ArrayUtils.size(pkg.getActivities());
ArrayList<IntentFilter> result = new ArrayList<>();
for (int n=0; n<count; n++) {
- PackageParser.Activity activity = pkg.activities.get(n);
+ ParsedActivity activity = pkg.getActivities().get(n);
if (activity.intents != null && activity.intents.size() > 0) {
result.addAll(activity.intents);
}
}
- return new ParceledListSlice<>(result);
+ return new ParceledListSlice<IntentFilter>(result) {
+ @Override
+ protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) {
+ // IntentFilter has final Parcelable methods, so redirect to the subclass
+ ((ParsedActivityIntentInfo) parcelable).writeIntentInfoToParcel(dest,
+ callFlags);
+ }
+ };
}
}
@@ -13549,7 +13419,7 @@ public class PackageManagerService extends IPackageManager.Stub
// package has not opted out of backup participation.
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
- final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
+ final int flags = (res.pkg == null) ? 0 : res.pkg.getFlags();
boolean doRestore = !update
&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
@@ -13572,35 +13442,10 @@ public class PackageManagerService extends IPackageManager.Stub
// restore if appropriate, then pass responsibility back to the
// Package Manager to run the post-install observer callbacks
// and broadcasts.
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (bm != null) {
- // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
- // in the BackupManager. USER_ALL is used in compatibility tests.
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
- if (DEBUG_INSTALL) {
- Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
- }
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- try {
- if (bm.isBackupServiceActive(userId)) {
- bm.restoreAtInstallForUser(
- userId, res.pkg.applicationInfo.packageName, token);
- } else {
- doRestore = false;
- }
- } catch (RemoteException e) {
- // can't happen; the backup manager is local
- } catch (Exception e) {
- Slog.e(TAG, "Exception trying to enqueue restore", e);
- doRestore = false;
- }
- } else {
- Slog.e(TAG, "Backup Manager not found!");
- doRestore = false;
+ if (res.freezer != null) {
+ res.freezer.close();
}
+ doRestore = performBackupManagerRestore(userId, token, res);
}
// If this is an update to a package that might be potentially downgraded, then we
@@ -13609,42 +13454,7 @@ public class PackageManagerService extends IPackageManager.Stub
//
// TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
- IRollbackManager rm = IRollbackManager.Stub.asInterface(
- ServiceManager.getService(Context.ROLLBACK_SERVICE));
-
- final String packageName = res.pkg.applicationInfo.packageName;
- final String seInfo = res.pkg.applicationInfo.seInfo;
- final int[] allUsers = mUserManager.getUserIds();
- final int[] installedUsers;
-
- final PackageSetting ps;
- int appId = -1;
- long ceDataInode = -1;
- synchronized (mSettings) {
- ps = mSettings.getPackageLPr(packageName);
- if (ps != null) {
- appId = ps.appId;
- ceDataInode = ps.getCeDataInode(userId);
- }
-
- // NOTE: We ignore the user specified in the InstallParam because we know this is
- // an update, and hence need to restore data for all installed users.
- installedUsers = ps.queryInstalledUsers(allUsers, true);
- }
-
- boolean doSnapshotOrRestore = data != null && data.args != null
- && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
- || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
-
- if (ps != null && doSnapshotOrRestore) {
- try {
- rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
- seInfo, token);
- } catch (RemoteException re) {
- Log.e(TAG, "Error snapshotting/restoring user data: " + re);
- }
- doRestore = true;
- }
+ doRestore = performRollbackManagerRestore(userId, token, res, data);
}
if (!doRestore) {
@@ -13660,6 +13470,89 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
+ * Perform Backup Manager restore for a given {@link PackageInstalledInfo}.
+ * Returns whether the restore successfully completed.
+ */
+ private boolean performBackupManagerRestore(int userId, int token, PackageInstalledInfo res) {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
+ // in the BackupManager. USER_ALL is used in compatibility tests.
+ if (userId == UserHandle.USER_ALL) {
+ userId = UserHandle.USER_SYSTEM;
+ }
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
+ }
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
+ try {
+ if (bm.isBackupServiceActive(userId)) {
+ bm.restoreAtInstallForUser(
+ userId, res.pkg.getAppInfoPackageName(), token);
+ } else {
+ return false;
+ }
+ } catch (RemoteException e) {
+ // can't happen; the backup manager is local
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception trying to enqueue restore", e);
+ return false;
+ }
+ } else {
+ Slog.e(TAG, "Backup Manager not found!");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Perform Rollback Manager restore for a given {@link PackageInstalledInfo}.
+ * Returns whether the restore successfully completed.
+ */
+ private boolean performRollbackManagerRestore(int userId, int token, PackageInstalledInfo res,
+ PostInstallData data) {
+ IRollbackManager rm = IRollbackManager.Stub.asInterface(
+ ServiceManager.getService(Context.ROLLBACK_SERVICE));
+
+ final String packageName = res.pkg.getAppInfoPackageName();
+ final String seInfo = res.pkg.getSeInfo();
+ final int[] allUsers = mUserManager.getUserIds();
+ final int[] installedUsers;
+
+ final PackageSetting ps;
+ int appId = -1;
+ long ceDataInode = -1;
+ synchronized (mSettings) {
+ ps = mSettings.getPackageLPr(packageName);
+ if (ps != null) {
+ appId = ps.appId;
+ ceDataInode = ps.getCeDataInode(userId);
+ }
+
+ // NOTE: We ignore the user specified in the InstallParam because we know this is
+ // an update, and hence need to restore data for all installed users.
+ installedUsers = ps.queryInstalledUsers(allUsers, true);
+ }
+
+ boolean doSnapshotOrRestore = data != null && data.args != null
+ && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
+ || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
+
+ if (ps != null && doSnapshotOrRestore) {
+ try {
+ rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
+ seInfo, token);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Error snapshotting/restoring user data: " + re);
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Callback from PackageSettings whenever an app is first transitioned out of the
* 'stopped' state. Normally we just issue the broadcast, but we can't do that if
* the app was "launched" for a restoreAtInstall operation. Therefore we check
@@ -13682,7 +13575,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
continue;
}
- if (packageName.equals(data.res.pkg.applicationInfo.packageName)) {
+ if (packageName.equals(data.res.pkg.getAppInfoPackageName())) {
// right package; but is it for the right user?
for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
if (userId == data.res.newUsers[uIndex]) {
@@ -14025,12 +13918,12 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
// Currently installed package which the new package is attempting to replace or
// null if no such package is installed.
- PackageParser.Package installedPkg = mPackages.get(packageName);
+ AndroidPackage installedPkg = mPackages.get(packageName);
// Package which currently owns the data which the new package will own if installed.
// If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg
// will be null whereas dataOwnerPkg will contain information about the package
// which was uninstalled while keeping its data.
- PackageParser.Package dataOwnerPkg = installedPkg;
+ AndroidPackage dataOwnerPkg = installedPkg;
if (dataOwnerPkg == null) {
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
@@ -14057,7 +13950,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (dataOwnerPkg != null) {
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
- dataOwnerPkg.applicationInfo.flags)) {
+ dataOwnerPkg.getFlags())) {
try {
checkDowngrade(dataOwnerPkg, pkgLite);
} catch (PackageManagerException e) {
@@ -14070,7 +13963,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (installedPkg != null) {
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// Check for updated system application.
- if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if ((installedPkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else {
// If current upgrade specifies particular preference
@@ -14543,7 +14436,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Rename package into final resting place. All paths on the given
* scanned package should be updated to reflect the rename.
*/
- abstract boolean doRename(int status, PackageParser.Package pkg);
+ abstract boolean doRename(int status, ParsedPackage parsedPackage);
abstract int doPostInstall(int status, int uid);
/** @see PackageSettingBase#codePathString */
@@ -14687,7 +14580,8 @@ public class PackageManagerService extends IPackageManager.Stub
return status;
}
- boolean doRename(int status, PackageParser.Package pkg) {
+ @Override
+ boolean doRename(int status, ParsedPackage parsedPackage) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
return false;
@@ -14695,7 +14589,7 @@ public class PackageManagerService extends IPackageManager.Stub
final File targetDir = codeFile.getParentFile();
final File beforeCodeFile = codeFile;
- final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
+ final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName());
if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
final boolean onIncremental = mIncrementalManager != null
@@ -14723,24 +14617,23 @@ public class PackageManagerService extends IPackageManager.Stub
// Reflect the rename in scanned details
try {
- pkg.setCodePath(afterCodeFile.getCanonicalPath());
+ parsedPackage.setCodePath(afterCodeFile.getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
return false;
}
- pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, pkg.baseCodePath));
- pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, pkg.splitCodePaths));
+ parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
+ afterCodeFile, parsedPackage.getBaseCodePath()));
+ parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
+ afterCodeFile, parsedPackage.getSplitCodePaths()));
// Reflect the rename in app info
- pkg.setApplicationVolumeUuid(pkg.volumeUuid);
- pkg.setApplicationInfoCodePath(pkg.codePath);
- pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
- pkg.setApplicationInfoResourcePath(pkg.codePath);
- pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+ // TODO(b/135203078): Remove all of these application info calls
+ parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+ .setApplicationInfoCodePath(parsedPackage.getCodePath())
+ .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+ .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+ .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
return true;
}
@@ -14843,20 +14736,20 @@ public class PackageManagerService extends IPackageManager.Stub
return status;
}
- boolean doRename(int status, PackageParser.Package pkg) {
+ @Override
+ boolean doRename(int status, ParsedPackage parsedPackage) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp(move.toUuid);
return false;
}
// Reflect the move in app info
- pkg.setApplicationVolumeUuid(pkg.volumeUuid);
- pkg.setApplicationInfoCodePath(pkg.codePath);
- pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
- pkg.setApplicationInfoResourcePath(pkg.codePath);
- pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+ // TODO(b/135203078): Remove all of these application info calls
+ parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+ .setApplicationInfoCodePath(parsedPackage.getCodePath())
+ .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+ .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+ .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
return true;
}
@@ -14932,14 +14825,15 @@ public class PackageManagerService extends IPackageManager.Stub
int[] origUsers;
// The set of users that now have this package installed.
int[] newUsers;
- PackageParser.Package pkg;
+ AndroidPackage pkg;
int returnCode;
String returnMsg;
String installerPackageName;
PackageRemovedInfo removedInfo;
ArrayMap<String, PackageInstalledInfo> addedChildPackages;
// The set of packages consuming this shared library or null if no consumers exist.
- ArrayList<PackageParser.Package> libraryConsumers;
+ ArrayList<AndroidPackage> libraryConsumers;
+ PackageFreezer freezer;
public void setError(int code, String msg) {
setReturnCode(code);
@@ -14995,107 +14889,37 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- /**
- * Checks whether the parent or any of the child packages have a change shared
- * user. For a package to be a valid update the shred users of the parent and
- * the children should match. We may later support changing child shared users.
- * @param oldPkg The updated package.
- * @param newPkg The update package.
- * @return The shared user that change between the versions.
- */
- private String getParentOrChildPackageChangedSharedUser(PackageParser.Package oldPkg,
- PackageParser.Package newPkg) {
- // Check parent shared user
- if (!Objects.equals(oldPkg.mSharedUserId, newPkg.mSharedUserId)) {
- return newPkg.packageName;
- }
- // Check child shared users
- final int oldChildCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0;
- final int newChildCount = (newPkg.childPackages != null) ? newPkg.childPackages.size() : 0;
- for (int i = 0; i < newChildCount; i++) {
- PackageParser.Package newChildPkg = newPkg.childPackages.get(i);
- // If this child was present, did it have the same shared user?
- for (int j = 0; j < oldChildCount; j++) {
- PackageParser.Package oldChildPkg = oldPkg.childPackages.get(j);
- if (newChildPkg.packageName.equals(oldChildPkg.packageName)
- && !Objects.equals(newChildPkg.mSharedUserId, oldChildPkg.mSharedUserId)) {
- return newChildPkg.packageName;
- }
- }
- }
- return null;
- }
-
private void removeNativeBinariesLI(PackageSetting ps) {
- // Remove the lib path for the parent package
if (ps != null) {
NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
- // Remove the lib path for the child packages
- final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageSetting childPs = null;
- synchronized (mLock) {
- childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
- }
- if (childPs != null) {
- NativeLibraryHelper.removeNativeBinariesLI(childPs
- .legacyNativeLibraryPathString);
- }
- }
}
}
@GuardedBy("mLock")
- private void enableSystemPackageLPw(PackageParser.Package pkg) {
- // Enable the parent package
- mSettings.enableSystemPackageLPw(pkg.packageName);
- // Enable the child packages
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- mSettings.enableSystemPackageLPw(childPkg.packageName);
- }
+ private void enableSystemPackageLPw(AndroidPackage pkg) {
+ mSettings.enableSystemPackageLPw(pkg.getPackageName());
}
@GuardedBy("mLock")
- private boolean disableSystemPackageLPw(PackageParser.Package oldPkg,
- PackageParser.Package newPkg) {
- // Disable the parent package (parent always replaced)
- boolean disabled = mSettings.disableSystemPackageLPw(oldPkg.packageName, true);
- // Disable the child packages
- final int childCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = oldPkg.childPackages.get(i);
- final boolean replace = newPkg.hasChildPackage(childPkg.packageName);
- disabled |= mSettings.disableSystemPackageLPw(childPkg.packageName, replace);
- }
- return disabled;
- }
-
- private void updateSettingsLI(PackageParser.Package newPackage,
- InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) {
- // Update the parent package setting
+ private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
+ return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
+ }
+
+ private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs,
+ int[] allUsers, PackageInstalledInfo res) {
updateSettingsInternalLI(newPackage, installArgs, allUsers, res);
- // Update the child packages setting
- final int childCount = (newPackage.childPackages != null)
- ? newPackage.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPackage = newPackage.childPackages.get(i);
- PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName);
- updateSettingsInternalLI(childPackage, installArgs, allUsers, childRes);
- }
}
- private void updateSettingsInternalLI(PackageParser.Package pkg,
- InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) {
+ private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,
+ int[] allUsers, PackageInstalledInfo res) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
- final String pkgName = pkg.packageName;
+ final String pkgName = pkg.getPackageName();
final String installerPackageName = installArgs.installSource.installerPackageName;
final int[] installedForUsers = res.origUsers;
final int installReason = installArgs.installReason;
- if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
+ if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath());
synchronized (mLock) {
// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
mPermissionManager.updatePermissions(pkgName, pkg);
@@ -15168,7 +14992,7 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.writeKernelMappingLPr(ps);
}
res.name = pkgName;
- res.uid = pkg.applicationInfo.uid;
+ res.uid = pkg.getUid();
res.pkg = pkg;
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
@@ -15226,7 +15050,7 @@ public class PackageManagerService extends IPackageManager.Stub
private static class ReconcileRequest {
public final Map<String, ScanResult> scannedPackages;
- public final Map<String, PackageParser.Package> allPackages;
+ public final Map<String, AndroidPackage> allPackages;
public final Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource;
public final Map<String, InstallArgs> installArgs;
public final Map<String, PackageInstalledInfo> installResults;
@@ -15239,7 +15063,7 @@ public class PackageManagerService extends IPackageManager.Stub
Map<String, PackageInstalledInfo> installResults,
Map<String, PrepareResult> preparedPackages,
Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
- Map<String, PackageParser.Package> allPackages,
+ Map<String, AndroidPackage> allPackages,
Map<String, VersionInfo> versionInfos,
Map<String, PackageSetting> lastStaticSharedLibSettings) {
this.scannedPackages = scannedPackages;
@@ -15254,7 +15078,7 @@ public class PackageManagerService extends IPackageManager.Stub
private ReconcileRequest(Map<String, ScanResult> scannedPackages,
Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
- Map<String, PackageParser.Package> allPackages,
+ Map<String, AndroidPackage> allPackages,
Map<String, VersionInfo> versionInfos,
Map<String, PackageSetting> lastStaticSharedLibSettings) {
this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
@@ -15322,15 +15146,17 @@ public class PackageManagerService extends IPackageManager.Stub
* with the package(s) currently being installed. The to-be installed packages take
* precedence and may shadow already installed packages.
*/
- private Map<String, PackageParser.Package> getCombinedPackages() {
- final ArrayMap<String, PackageParser.Package> combinedPackages =
+ private Map<String, AndroidPackage> getCombinedAvailablePackages() {
+ final ArrayMap<String, AndroidPackage> combined =
new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
- combinedPackages.putAll(request.allPackages);
+ combined.putAll(request.allPackages);
+
for (ScanResult scanResult : request.scannedPackages.values()) {
- combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+ combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
}
- return combinedPackages;
+
+ return combined;
}
}
@@ -15343,8 +15169,9 @@ public class PackageManagerService extends IPackageManager.Stub
final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
// make a copy of the existing set of packages so we can combine them with incoming packages
- final ArrayMap<String, PackageParser.Package> combinedPackages =
+ final ArrayMap<String, AndroidPackage> combinedPackages =
new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
+
combinedPackages.putAll(request.allPackages);
final Map<String, LongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
@@ -15354,7 +15181,7 @@ public class PackageManagerService extends IPackageManager.Stub
final ScanResult scanResult = scannedPackages.get(installPackageName);
// add / replace existing with incoming packages
- combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+ combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
// in the first pass, we'll build up the set of incoming shared libraries
final List<SharedLibraryInfo> allowedSharedLibInfos =
@@ -15387,7 +15214,7 @@ public class PackageManagerService extends IPackageManager.Stub
| (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
deletePackageAction = mayDeletePackageLocked(res.removedInfo,
prepareResult.originalPs, prepareResult.disabledPs,
- prepareResult.childPackageSettings, deleteFlags, null /* all users */);
+ deleteFlags, null /* all users */);
if (deletePackageAction == null) {
throw new ReconcileFailure(
PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,
@@ -15399,7 +15226,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int scanFlags = scanResult.request.scanFlags;
final int parseFlags = scanResult.request.parseFlags;
- final PackageParser.Package pkg = scanResult.request.pkg;
+ final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting;
final PackageSetting lastStaticSharedLibSetting =
@@ -15412,35 +15239,37 @@ public class PackageManagerService extends IPackageManager.Stub
boolean sharedUserSignaturesChanged = false;
SigningDetails signingDetails = null;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
- if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+ if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
} else {
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "Package " + pkg.packageName + " upgrade keys do not match the "
- + "previously installed version");
+ "Package " + parsedPackage.getPackageName()
+ + " upgrade keys do not match the previously installed"
+ + " version");
} else {
- String msg = "System package " + pkg.packageName
+ String msg = "System package " + parsedPackage.getPackageName()
+ " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
}
}
- signingDetails = pkg.mSigningDetails;
+ signingDetails = parsedPackage.getSigningDetails();
} else {
try {
final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
final boolean compatMatch = verifySignatures(signatureCheckPs,
- disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover);
+ disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
+ compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
removeAppKeySetData = true;
}
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
- signingDetails = pkg.mSigningDetails;
+ signingDetails = parsedPackage.getSigningDetails();
// if this is is a sharedUser, check to see if the new package is signed by a
@@ -15448,10 +15277,10 @@ public class PackageManagerService extends IPackageManager.Stub
// signing certificate than the existing one, and if so, copy over the new
// details
if (signatureCheckPs.sharedUser != null) {
- if (pkg.mSigningDetails.hasAncestor(
+ if (parsedPackage.getSigningDetails().hasAncestor(
signatureCheckPs.sharedUser.signatures.mSigningDetails)) {
signatureCheckPs.sharedUser.signatures.mSigningDetails =
- pkg.mSigningDetails;
+ parsedPackage.getSigningDetails();
}
if (signatureCheckPs.sharedUser.signaturesChanged == null) {
signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE;
@@ -15461,7 +15290,7 @@ public class PackageManagerService extends IPackageManager.Stub
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw new ReconcileFailure(e);
}
- signingDetails = pkg.mSigningDetails;
+ signingDetails = parsedPackage.getSigningDetails();
// If the system app is part of a shared user we allow that shared user to
// change
@@ -15476,7 +15305,7 @@ public class PackageManagerService extends IPackageManager.Stub
signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures;
if (signatureCheckPs.sharedUser.signaturesChanged != null
&& compareSignatures(sharedUserSignatures,
- pkg.mSigningDetails.signatures)
+ parsedPackage.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH) {
if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
// Mismatched signatures is an error and silently skipping system
@@ -15496,18 +15325,19 @@ public class PackageManagerService extends IPackageManager.Stub
// whichever package happened to be scanned later.
throw new IllegalStateException(
"Signature mismatch on system package "
- + pkg.packageName + " for shared user "
+ + parsedPackage.getPackageName()
+ + " for shared user "
+ scanResult.pkgSetting.sharedUser);
}
}
sharedUserSignaturesChanged = true;
signatureCheckPs.sharedUser.signatures.mSigningDetails =
- pkg.mSigningDetails;
+ parsedPackage.getSigningDetails();
signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE;
}
// File a report about this.
- String msg = "System package " + pkg.packageName
+ String msg = "System package " + parsedPackage.getPackageName()
+ " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
} catch (IllegalArgumentException e) {
@@ -15541,8 +15371,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
try {
result.get(installPackageName).collectedSharedLibraryInfos =
- collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages,
- request.sharedLibrarySource, incomingSharedLibraries);
+ collectSharedLibraryInfos(scanResult.request.parsedPackage,
+ combinedPackages, request.sharedLibrarySource,
+ incomingSharedLibraries);
} catch (PackageManagerException e) {
throw new ReconcileFailure(e.error, e.getMessage());
@@ -15560,7 +15391,7 @@ public class PackageManagerService extends IPackageManager.Stub
ScanResult scanResult,
Map<String, LongSparseArray<SharedLibraryInfo>> existingSharedLibraries) {
// Let's used the parsed package as scanResult.pkgSetting may be null
- final PackageParser.Package pkg = scanResult.request.pkg;
+ final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
if (scanResult.staticSharedLibraryInfo == null
&& scanResult.dynamicSharedLibraryInfos == null) {
return null;
@@ -15571,12 +15402,12 @@ public class PackageManagerService extends IPackageManager.Stub
return Collections.singletonList(scanResult.staticSharedLibraryInfo);
}
final boolean hasDynamicLibraries =
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+ (parsedPackage.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0
&& scanResult.dynamicSharedLibraryInfos != null;
if (!hasDynamicLibraries) {
return null;
}
- final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp();
+ final boolean isUpdatedSystemApp = parsedPackage.isUpdatedSystemApp();
// We may not yet have disabled the updated package yet, so be sure to grab the
// current setting if that's the case.
final PackageSetting updatedSystemPs = isUpdatedSystemApp
@@ -15585,9 +15416,9 @@ public class PackageManagerService extends IPackageManager.Stub
: scanResult.request.disabledPkgSetting
: null;
if (isUpdatedSystemApp && (updatedSystemPs.pkg == null
- || updatedSystemPs.pkg.libraryNames == null)) {
- Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not "
- + "declared on the system image; skipping");
+ || updatedSystemPs.pkg.getLibraryNames() == null)) {
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ + " declares libraries that are not declared on the system image; skipping");
return null;
}
final ArrayList<SharedLibraryInfo> infos =
@@ -15605,16 +15436,17 @@ public class PackageManagerService extends IPackageManager.Stub
// with it. Better to just have the restriction here, be
// conservative, and create many fewer cases that can negatively
// impact the user experience.
- if (!updatedSystemPs.pkg.libraryNames.contains(name)) {
- Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
+ if (!updatedSystemPs.pkg.getLibraryNames().contains(name)) {
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ + " declares library " + name
+ " that is not declared on system image; skipping");
continue;
}
}
if (sharedLibExists(
name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) {
- Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
- + " that already exists; skipping");
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library "
+ + name + " that already exists; skipping");
continue;
}
infos.add(info);
@@ -15652,68 +15484,38 @@ public class PackageManagerService extends IPackageManager.Stub
for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
final ScanResult scanResult = reconciledPkg.scanResult;
final ScanRequest scanRequest = scanResult.request;
- final PackageParser.Package pkg = scanRequest.pkg;
- final String packageName = pkg.packageName;
+ final ParsedPackage parsedPackage = scanRequest.parsedPackage;
+ final String packageName = parsedPackage.getPackageName();
final PackageInstalledInfo res = reconciledPkg.installResult;
if (reconciledPkg.prepareResult.replace) {
- PackageParser.Package oldPackage = mPackages.get(packageName);
+ AndroidPackage oldPackage = mPackages.get(packageName);
// Set the update and install times
- PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
- setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
- System.currentTimeMillis());
+ PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName());
+ reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
+ reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
if (reconciledPkg.prepareResult.system) {
// Remove existing system package
removePackageLI(oldPackage, true);
- if (!disableSystemPackageLPw(oldPackage, pkg)) {
+ if (!disableSystemPackageLPw(oldPackage)) {
// We didn't need to disable the .apk as a current system package,
// which means we are replacing another update that is already
// installed. We need to make sure to delete the older one's .apk.
res.removedInfo.args = createInstallArgsForExisting(
- oldPackage.applicationInfo.getCodePath(),
- oldPackage.applicationInfo.getResourcePath(),
- getAppDexInstructionSets(oldPackage.applicationInfo));
+ oldPackage.getAppInfoCodePath(),
+ oldPackage.getAppInfoResourcePath(),
+ getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
+ oldPackage.getSecondaryCpuAbi()));
} else {
res.removedInfo.args = null;
}
-
- // Update the package dynamic state if succeeded
- // Now that the install succeeded make sure we remove data
- // directories for any child package the update removed.
- final int deletedChildCount = (oldPackage.childPackages != null)
- ? oldPackage.childPackages.size() : 0;
- final int newChildCount = (pkg.childPackages != null)
- ? pkg.childPackages.size() : 0;
- for (int i = 0; i < deletedChildCount; i++) {
- PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
- boolean childPackageDeleted = true;
- for (int j = 0; j < newChildCount; j++) {
- PackageParser.Package newChildPkg = pkg.childPackages.get(j);
- if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
- childPackageDeleted = false;
- break;
- }
- }
- if (childPackageDeleted) {
- PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
- deletedChildPkg.packageName);
- if (ps1 != null && res.removedInfo.removedChildPackages != null) {
- PackageRemovedInfo removedChildRes = res.removedInfo
- .removedChildPackages.get(deletedChildPkg.packageName);
- removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
- false);
- removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
- == null;
- }
- }
- }
} else {
try {
// Settings will be written during the call to updateSettingsLI().
executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
- true, request.mAllUsers, false, pkg);
+ true, request.mAllUsers, false, parsedPackage);
} catch (SystemDeleteException e) {
if (Build.IS_ENG) {
throw new RuntimeException("Unexpected failure", e);
@@ -15729,62 +15531,40 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.i(TAG, "upgrading pkg " + oldPackage
+ " is ASEC-hosted -> UNAVAILABLE");
}
- final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
+ final int[] uidArray = new int[]{oldPackage.getUid()};
final ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(oldPackage.applicationInfo.packageName);
+ pkgList.add(oldPackage.getAppInfoPackageName());
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
// Update the in-memory copy of the previous code paths.
PackageSetting ps1 = mSettings.mPackages.get(
- reconciledPkg.prepareResult.existingPackage.packageName);
+ reconciledPkg.prepareResult.existingPackage.getPackageName());
if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
== 0) {
if (ps1.mOldCodePaths == null) {
ps1.mOldCodePaths = new ArraySet<>();
}
- Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
- if (oldPackage.splitCodePaths != null) {
- Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
+ Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseCodePath());
+ if (oldPackage.getSplitCodePaths() != null) {
+ Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
}
} else {
ps1.mOldCodePaths = null;
}
- if (ps1.childPackageNames != null) {
- for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
- final String childPkgName = ps1.childPackageNames.get(i);
- final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
- childPs.mOldCodePaths = ps1.mOldCodePaths;
- }
- }
if (reconciledPkg.installResult.returnCode
== PackageManager.INSTALL_SUCCEEDED) {
- PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
+ PackageSetting ps2 = mSettings.getPackageLPr(
+ parsedPackage.getPackageName());
if (ps2 != null) {
res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
- if (res.removedInfo.removedChildPackages != null) {
- final int childCount1 = res.removedInfo.removedChildPackages.size();
- // Iterate in reverse as we may modify the collection
- for (int i = childCount1 - 1; i >= 0; i--) {
- String childPackageName =
- res.removedInfo.removedChildPackages.keyAt(i);
- if (res.addedChildPackages.containsKey(childPackageName)) {
- res.removedInfo.removedChildPackages.removeAt(i);
- } else {
- PackageRemovedInfo childInfo = res.removedInfo
- .removedChildPackages.valueAt(i);
- childInfo.removedForAllUsers = mPackages.get(
- childInfo.removedPackage) == null;
- }
- }
- }
}
}
}
}
- commitReconciledScanResultLocked(reconciledPkg);
+ AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg);
updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res);
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -15792,16 +15572,6 @@ public class PackageManagerService extends IPackageManager.Stub
res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
ps.setUpdateAvailable(false /*updateAvailable*/);
}
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
- PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
- if (childPs != null) {
- childRes.newUsers = childPs.queryInstalledUsers(
- mUserManager.getUserIds(), true);
- }
- }
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
updateSequenceNumberLP(ps, res.newUsers);
updateInstantAppInstallerLocked(packageName);
@@ -15862,33 +15632,31 @@ public class PackageManagerService extends IPackageManager.Stub
request.installResult.installerPackageName =
request.args.installSource.installerPackageName;
- final String packageName = prepareResult.packageToScan.packageName;
+ final String packageName = prepareResult.packageToScan.getPackageName();
prepareResults.put(packageName, prepareResult);
installResults.put(packageName, request.installResult);
installArgs.put(packageName, request.args);
try {
- final List<ScanResult> scanResults = scanPackageTracedLI(
+ final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user);
- for (ScanResult result : scanResults) {
- if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
- request.installResult.setError(
- PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Duplicate package " + result.pkgSetting.pkg.packageName
- + " in multi-package install request.");
- return;
- }
- createdAppId.put(packageName, optimisticallyRegisterAppId(result));
- versionInfos.put(result.pkgSetting.pkg.packageName,
- getSettingsVersionForPackage(result.pkgSetting.pkg));
- if (result.staticSharedLibraryInfo != null) {
- final PackageSetting sharedLibLatestVersionSetting =
- getSharedLibLatestVersionSetting(result);
- if (sharedLibLatestVersionSetting != null) {
- lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
- sharedLibLatestVersionSetting);
- }
+ if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
+ request.installResult.setError(
+ PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Duplicate package " + result.pkgSetting.pkg.getPackageName()
+ + " in multi-package install request.");
+ return;
+ }
+ createdAppId.put(packageName, optimisticallyRegisterAppId(result));
+ versionInfos.put(result.pkgSetting.pkg.getPackageName(),
+ getSettingsVersionForPackage(result.pkgSetting.pkg));
+ if (result.staticSharedLibraryInfo != null) {
+ final PackageSetting sharedLibLatestVersionSetting =
+ getSharedLibLatestVersionSetting(result);
+ if (sharedLibLatestVersionSetting != null) {
+ lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
+ sharedLibLatestVersionSetting);
}
}
} catch (PackageManagerException e) {
@@ -15931,23 +15699,20 @@ public class PackageManagerService extends IPackageManager.Stub
} finally {
if (!success) {
for (ScanResult result : preparedScans.values()) {
- if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
+ if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
+ false)) {
cleanUpAppIdCreation(result);
}
}
// TODO(patb): create a more descriptive reason than unknown in future release
// mark all non-failure installs as UNKNOWN so we do not treat them as success
for (InstallRequest request : requests) {
+ request.installResult.freezer.close();
if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
}
}
}
- for (PrepareResult result : prepareResults.values()) {
- if (result.freezer != null) {
- result.freezer.close();
- }
- }
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
@@ -15961,18 +15726,18 @@ public class PackageManagerService extends IPackageManager.Stub
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
& PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
- final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
- final String packageName = pkg.packageName;
+ final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
+ final String packageName = pkg.getPackageName();
final boolean onIncremental = mIncrementalManager != null
- && isIncrementalPath(pkg.codePath);
+ && isIncrementalPath(pkg.getCodePath());
prepareAppDataAfterInstallLIF(pkg);
if (reconciledPkg.prepareResult.clearCodeCache) {
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
if (reconciledPkg.prepareResult.replace) {
- mDexManager.notifyPackageUpdated(pkg.packageName,
- pkg.baseCodePath, pkg.splitCodePaths);
+ mDexManager.notifyPackageUpdated(pkg.getPackageName(),
+ pkg.getBaseCodePath(), pkg.getSplitCodePaths());
}
// Prepare the application profiles for the new code paths.
@@ -15986,7 +15751,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Check whether we need to dexopt the app.
//
// NOTE: it is IMPORTANT to call dexopt:
- // - after doRename which will sync the package data from PackageParser.Package and
+ // - after doRename which will sync the package data from AndroidPackage and
// its corresponding ApplicationInfo.
// - after installNewPackageLIF or replacePackageLIF which will update result with the
// uid of the application (pkg.applicationInfo.uid).
@@ -16006,7 +15771,7 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean performDexopt =
(!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
- && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0)
+ && ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) == 0)
&& (!onIncremental);
if (performDexopt) {
@@ -16051,20 +15816,17 @@ public class PackageManagerService extends IPackageManager.Stub
public final int scanFlags;
public final int parseFlags;
@Nullable /* The original Package if it is being replaced, otherwise {@code null} */
- public final PackageParser.Package existingPackage;
- public final PackageParser.Package packageToScan;
+ public final AndroidPackage existingPackage;
+ public final ParsedPackage packageToScan;
public final boolean clearCodeCache;
public final boolean system;
- public final PackageFreezer freezer;
public final PackageSetting originalPs;
public final PackageSetting disabledPs;
- public final PackageSetting[] childPackageSettings;
private PrepareResult(boolean replace, int scanFlags,
- int parseFlags, PackageParser.Package existingPackage,
- PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
- PackageFreezer freezer, PackageSetting originalPs,
- PackageSetting disabledPs, PackageSetting[] childPackageSettings) {
+ int parseFlags, AndroidPackage existingPackage,
+ ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
+ PackageSetting originalPs, PackageSetting disabledPs) {
this.replace = replace;
this.scanFlags = scanFlags;
this.parseFlags = parseFlags;
@@ -16072,10 +15834,8 @@ public class PackageManagerService extends IPackageManager.Stub
this.packageToScan = packageToScan;
this.clearCodeCache = clearCodeCache;
this.system = system;
- this.freezer = freezer;
this.originalPs = originalPs;
this.disabledPs = disabledPs;
- this.childPackageSettings = childPackageSettings;
}
}
@@ -16154,10 +15914,10 @@ public class PackageManagerService extends IPackageManager.Stub
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
- final PackageParser.Package pkg;
+ ParsedPackage parsedPackage;
try {
- pkg = pp.parsePackage(tmpPackageFile, parseFlags);
- DexMetadataHelper.validatePackageDexMetadata(pkg);
+ parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false);
+ DexMetadataHelper.validatePackageDexMetadata(parsedPackage);
} catch (PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
@@ -16166,23 +15926,23 @@ public class PackageManagerService extends IPackageManager.Stub
// Instant apps have several additional install-time checks.
if (instantApp) {
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
- Slog.w(TAG,
- "Instant app package " + pkg.packageName + " does not target at least O");
+ if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
+ Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+ + " does not target at least O");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must target at least O");
}
- if (pkg.mSharedUserId != null) {
- Slog.w(TAG, "Instant app package " + pkg.packageName
+ if (parsedPackage.getSharedUserId() != null) {
+ Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+ " may not declare sharedUserId.");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package may not declare a sharedUserId");
}
}
- if (pkg.applicationInfo.isStaticSharedLibrary()) {
+ if (parsedPackage.isStaticSharedLibrary()) {
// Static shared libraries have synthetic package names
- renameStaticSharedLibraryPackage(pkg);
+ renameStaticSharedLibraryPackage(parsedPackage);
// No static shared libs on external storage
if (onExternal) {
@@ -16192,43 +15952,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- // If we are installing a clustered package add results for the children
- if (pkg.childPackages != null) {
- synchronized (mLock) {
- final int childCount = pkg.childPackages.size();
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- PackageInstalledInfo childRes = new PackageInstalledInfo();
- childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- childRes.pkg = childPkg;
- childRes.name = childPkg.packageName;
- PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
- if (childPs != null) {
- childRes.origUsers = childPs.queryInstalledUsers(
- mUserManager.getUserIds(), true);
- }
- if ((mPackages.containsKey(childPkg.packageName))) {
- childRes.removedInfo = new PackageRemovedInfo(this);
- childRes.removedInfo.removedPackage = childPkg.packageName;
- childRes.removedInfo.installerPackageName =
- childPs.installSource.installerPackageName;
- }
- if (res.addedChildPackages == null) {
- res.addedChildPackages = new ArrayMap<>();
- }
- res.addedChildPackages.put(childPkg.packageName, childRes);
- }
- }
- }
-
// If package doesn't declare API override, mark that we have an install
// time CPU ABI override.
- if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
- pkg.cpuAbiOverride = args.abiOverride;
+ // TODO(b/135203078): Isn't this always true because cpuAbiOverride isn't assigned during
+ // parsing?
+ if (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())) {
+ parsedPackage.setCpuAbiOverride(args.abiOverride);
}
- String pkgName = res.name = pkg.packageName;
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+ String pkgName = res.name = parsedPackage.getPackageName();
+ if ((parsedPackage.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
}
@@ -16237,18 +15970,18 @@ public class PackageManagerService extends IPackageManager.Stub
try {
// either use what we've been given or parse directly from the APK
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
- pkg.setSigningDetails(args.signingDetails);
+ parsedPackage.setSigningDetails(args.signingDetails);
} else {
// TODO(b/136132412): skip for Incremental installation
- PackageParser.collectCertificates(pkg, false /* skipVerify */);
+ ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */);
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
}
- if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
+ if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion
< SignatureSchemeVersion.SIGNING_BLOCK_V2) {
- Slog.w(TAG, "Instant app package " + pkg.packageName
+ Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+ " is not signed with at least APK Signature Scheme v2");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must be signed with APK Signature Scheme v2 or greater");
@@ -16262,15 +15995,15 @@ public class PackageManagerService extends IPackageManager.Stub
// Check if installing already existing package
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
String oldName = mSettings.getRenamedPackageLPr(pkgName);
- if (pkg.mOriginalPackages != null
- && pkg.mOriginalPackages.contains(oldName)
+ if (parsedPackage.getOriginalPackages() != null
+ && parsedPackage.getOriginalPackages().contains(oldName)
&& mPackages.containsKey(oldName)) {
// This package is derived from an original package,
// and this device has been updating from that original
// name. We must continue using the original name, so
// rename the new package here.
- pkg.setPackageName(oldName);
- pkgName = pkg.packageName;
+ parsedPackage.setPackageName(oldName);
+ pkgName = parsedPackage.getPackageName();
replace = true;
if (DEBUG_INSTALL) {
Slog.d(TAG, "Replacing existing renamed package: oldName="
@@ -16283,43 +16016,27 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
}
- // Child packages are installed through the parent package
- if (pkg.parentPackage != null) {
- throw new PrepareFailure(
- PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
- "Package " + pkg.packageName + " is child of package "
- + pkg.parentPackage.parentPackage + ". Child packages "
- + "can be updated only through the parent package.");
- }
-
if (replace) {
// Prevent apps opting out from runtime permissions
- PackageParser.Package oldPackage = mPackages.get(pkgName);
- final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
- final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
+ AndroidPackage oldPackage = mPackages.get(pkgName);
+ final int oldTargetSdk = oldPackage.getTargetSdkVersion();
+ final int newTargetSdk = parsedPackage.getTargetSdkVersion();
if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
&& newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
throw new PrepareFailure(
PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
- "Package " + pkg.packageName + " new target SDK " + newTargetSdk
+ "Package " + parsedPackage.getPackageName()
+ + " new target SDK " + newTargetSdk
+ " doesn't support runtime permissions but the old"
+ " target SDK " + oldTargetSdk + " does.");
}
// Prevent persistent apps from being updated
- if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
+ if (((oldPackage.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0)
&& ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
- "Package " + oldPackage.packageName + " is a persistent app. "
+ "Package " + oldPackage.getPackageName() + " is a persistent app. "
+ "Persistent apps are not updateable.");
}
- // Prevent installing of child packages
- if (oldPackage.parentPackage != null) {
- throw new PrepareFailure(
- PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
- "Package " + pkg.packageName + " is child of package "
- + oldPackage.parentPackage + ". Child packages "
- + "can be updated only through the parent package.");
- }
}
}
@@ -16332,8 +16049,8 @@ public class PackageManagerService extends IPackageManager.Stub
// of the same package, therefore we need to compare signatures against
// the package setting for the latest library version.
PackageSetting signatureCheckPs = ps;
- if (pkg.applicationInfo.isStaticSharedLibrary()) {
- SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
+ if (parsedPackage.isStaticSharedLibrary()) {
+ SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage);
if (libraryInfo != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
}
@@ -16344,23 +16061,23 @@ public class PackageManagerService extends IPackageManager.Stub
// bail early here before tripping over redefined permissions.
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
- if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+ if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
- + pkg.packageName + " upgrade keys do not match the "
+ + parsedPackage.getPackageName() + " upgrade keys do not match the "
+ "previously installed version");
}
} else {
try {
- final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
- final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+ final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage);
+ final boolean compareRecover = isRecoverSignatureUpdateNeeded(
+ parsedPackage);
// We don't care about disabledPkgSetting on install for now.
- final boolean compatMatch = verifySignatures(
- signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
- compareRecover);
+ final boolean compatMatch = verifySignatures(signatureCheckPs, null,
+ parsedPackage.getSigningDetails(), compareCompat, compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mLock) {
- ksms.removeAppKeySetDataLPw(pkg.packageName);
+ ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
}
}
} catch (PackageManagerException e) {
@@ -16368,27 +16085,25 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (ps.pkg != null && ps.pkg.applicationInfo != null) {
- systemApp = (ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SYSTEM) != 0;
+ if (ps.pkg != null) {
+ systemApp = (ps.pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
}
res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
}
- int N = pkg.permissions.size();
+ int N = ArrayUtils.size(parsedPackage.getPermissions());
for (int i = N - 1; i >= 0; i--) {
- final PackageParser.Permission perm = pkg.permissions.get(i);
- final BasePermission bp =
- (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
+ final ParsedPermission perm = parsedPackage.getPermissions().get(i);
+ final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName());
// Don't allow anyone but the system to define ephemeral permissions.
- if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
+ if ((perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
&& !systemApp) {
- Slog.w(TAG, "Non-System package " + pkg.packageName
+ Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
+ " attempting to delcare ephemeral permission "
- + perm.info.name + "; Removing ephemeral.");
- perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
+ + perm.getName() + "; Removing ephemeral.");
+ perm.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
}
// Check whether the newly-scanned package wants to define an already-defined perm
@@ -16400,26 +16115,27 @@ public class PackageManagerService extends IPackageManager.Stub
final String sourcePackageName = bp.getSourcePackageName();
final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
- if (sourcePackageName.equals(pkg.packageName)
+ if (sourcePackageName.equals(parsedPackage.getPackageName())
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
- sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
+ sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
} else {
// in the event of signing certificate rotation, we need to see if the
// package's certificate has rotated from the current one, or if it is an
// older certificate with which the current is ok with sharing permissions
if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
- pkg.mSigningDetails,
+ parsedPackage.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
sigsOk = true;
- } else if (pkg.mSigningDetails.checkCapability(
+ } else if (parsedPackage.getSigningDetails().checkCapability(
sourcePackageSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
// the scanned package checks out, has signing certificate rotation
// history, and is newer; bring it over
- sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
+ sourcePackageSetting.signatures.mSigningDetails =
+ parsedPackage.getSigningDetails();
sigsOk = true;
} else {
sigsOk = false;
@@ -16431,30 +16147,31 @@ public class PackageManagerService extends IPackageManager.Stub
// redefinitions.
if (!sourcePackageName.equals("android")) {
throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
- + pkg.packageName
+ + parsedPackage.getPackageName()
+ " attempting to redeclare permission "
- + perm.info.name + " already owned by "
+ + perm.getName() + " already owned by "
+ sourcePackageName)
- .conflictsWithExistingPermission(perm.info.name,
+ .conflictsWithExistingPermission(perm.getName(),
sourcePackageName);
} else {
- Slog.w(TAG, "Package " + pkg.packageName
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ " attempting to redeclare system permission "
- + perm.info.name + "; ignoring new declaration");
- pkg.permissions.remove(i);
+ + perm.getName() + "; ignoring new declaration");
+ parsedPackage.removePermission(i);
}
- } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
+ } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
// Prevent apps to change protection level to dangerous from any other
// type as this would allow a privilege escalation where an app adds a
// normal/signature permission in other app's group and later redefines
// it as dangerous leading to the group auto-grant.
- if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS) {
if (bp != null && !bp.isRuntime()) {
- Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
- + "non-runtime permission " + perm.info.name
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ + " trying to change a non-runtime permission "
+ + perm.getName()
+ " to runtime; keeping old protection level");
- perm.info.protectionLevel = bp.getProtectionLevel();
+ perm.protectionLevel = bp.getProtectionLevel();
}
}
}
@@ -16488,8 +16205,8 @@ public class PackageManagerService extends IPackageManager.Stub
// We moved the entire application as-is, so bring over the
// previously derived ABI information.
- pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
- pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
+ parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString)
+ .setSecondaryCpuAbi(ps.secondaryCpuAbiString);
}
} else {
@@ -16497,14 +16214,14 @@ public class PackageManagerService extends IPackageManager.Stub
scanFlags |= SCAN_NO_DEX;
try {
- String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
- args.abiOverride : pkg.cpuAbiOverride);
- final boolean extractNativeLibs = !pkg.isLibrary();
+ String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
+ ? args.abiOverride : parsedPackage.getCpuAbiOverride());
+ final boolean extractNativeLibs = !parsedPackage.isLibrary();
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
- pkg, abiOverride, extractNativeLibs);
- derivedAbi.first.applyTo(pkg);
- derivedAbi.second.applyTo(pkg);
+ parsedPackage, abiOverride, extractNativeLibs);
+ derivedAbi.first.applyTo(parsedPackage);
+ derivedAbi.second.applyTo(parsedPackage);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -16512,19 +16229,19 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!args.doRename(res.returnCode, pkg)) {
+ if (!args.doRename(res.returnCode, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
}
try {
- setUpFsVerityIfPossible(pkg);
+ setUpFsVerityIfPossible(parsedPackage);
} catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
"Failed to set up verity: " + e);
}
if (!instantApp) {
- startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
+ startIntentFilterVerifications(args.user.getIdentifier(), replace, parsedPackage);
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
@@ -16534,7 +16251,7 @@ public class PackageManagerService extends IPackageManager.Stub
freezePackageForInstall(pkgName, installFlags, "installPackageLI");
boolean shouldCloseFreezerBeforeReturn = true;
try {
- final PackageParser.Package existingPackage;
+ final AndroidPackage existingPackage;
String renamedPackage = null;
boolean sysPkg = false;
int targetScanFlags = scanFlags;
@@ -16543,14 +16260,15 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageSetting disabledPs;
final PackageSetting[] childPackages;
if (replace) {
- if (pkg.applicationInfo.isStaticSharedLibrary()) {
+ if (parsedPackage.isStaticSharedLibrary()) {
// Static libs have a synthetic package name containing the version
// and cannot be updated as an update would get a new package name,
// unless this is the exact same version code which is useful for
// development.
- PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
+ AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName());
if (existingPkg != null
- && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
+ && existingPkg.getLongVersionCode()
+ != parsedPackage.getLongVersionCode()) {
throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
"Packages declaring "
+ "static-shared libs cannot be updated");
@@ -16559,8 +16277,8 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
- final PackageParser.Package oldPackage;
- final String pkgName11 = pkg.packageName;
+ final AndroidPackage oldPackage;
+ final String pkgName11 = parsedPackage.getPackageName();
final int[] allUsers;
final int[] installedUsers;
@@ -16568,8 +16286,9 @@ public class PackageManagerService extends IPackageManager.Stub
oldPackage = mPackages.get(pkgName11);
existingPackage = oldPackage;
if (DEBUG_INSTALL) {
+ // TODO(b/135203078): PackageImpl.toString()
Slog.d(TAG,
- "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
+ "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
}
ps = mSettings.mPackages.get(pkgName11);
@@ -16578,17 +16297,18 @@ public class PackageManagerService extends IPackageManager.Stub
// verify signatures are valid
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
- if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
+ if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"New package not signed by keys specified by upgrade-keysets: "
+ pkgName11);
}
} else {
// default to original signature matching
- if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
+ if (!parsedPackage.getSigningDetails().checkCapability(
+ oldPackage.getSigningDetails(),
SigningDetails.CertCapabilities.INSTALLED_DATA)
- && !oldPackage.mSigningDetails.checkCapability(
- pkg.mSigningDetails,
+ && !oldPackage.getSigningDetails().checkCapability(
+ parsedPackage.getSigningDetails(),
SigningDetails.CertCapabilities.ROLLBACK)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"New package has a different signature: " + pkgName11);
@@ -16596,13 +16316,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
// don't allow a system upgrade unless the upgrade hash matches
- if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
+ if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
final byte[] digestBytes;
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-512");
- updateDigest(digest, new File(pkg.baseCodePath));
- if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
- for (String path : pkg.splitCodePaths) {
+ updateDigest(digest, new File(parsedPackage.getBaseCodePath()));
+ if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
+ for (String path : parsedPackage.getSplitCodePaths()) {
updateDigest(digest, new File(path));
}
}
@@ -16611,21 +16331,25 @@ public class PackageManagerService extends IPackageManager.Stub
throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
"Could not compute hash: " + pkgName11);
}
- if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
+ if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) {
throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
"New package fails restrict-update check: " + pkgName11);
}
// retain upgrade restriction
- pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
+ parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
}
// Check for shared user id changes
- String invalidPackageName =
- getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
+ String invalidPackageName = null;
+ if (!Objects.equals(oldPackage.getSharedUserId(),
+ parsedPackage.getSharedUserId())) {
+ invalidPackageName = parsedPackage.getPackageName();
+ }
+
if (invalidPackageName != null) {
throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + invalidPackageName + " tried to change user "
- + oldPackage.mSharedUserId);
+ + oldPackage.getSharedUserId());
}
// In case of rollback, remember per-user/profile install state
@@ -16658,10 +16382,10 @@ public class PackageManagerService extends IPackageManager.Stub
// Update what is removed
res.removedInfo = new PackageRemovedInfo(this);
- res.removedInfo.uid = oldPackage.applicationInfo.uid;
- res.removedInfo.removedPackage = oldPackage.packageName;
+ res.removedInfo.uid = oldPackage.getUid();
+ res.removedInfo.removedPackage = oldPackage.getPackageName();
res.removedInfo.installerPackageName = ps.installSource.installerPackageName;
- res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
+ res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null;
res.removedInfo.isUpdate = true;
res.removedInfo.origUsers = installedUsers;
res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
@@ -16670,53 +16394,6 @@ public class PackageManagerService extends IPackageManager.Stub
res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
}
- childPackages = mSettings.getChildSettingsLPr(ps);
- if (childPackages != null) {
- for (PackageSetting childPs : childPackages) {
- boolean childPackageUpdated = false;
- PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg;
- if (res.addedChildPackages != null) {
- PackageInstalledInfo childRes = res.addedChildPackages.get(
- childPkg.packageName);
- if (childRes != null) {
- childRes.removedInfo.uid = childPkg.applicationInfo.uid;
- childRes.removedInfo.removedPackage = childPkg.packageName;
- if (childPs != null) {
- childRes.removedInfo.installerPackageName =
- childPs.installSource.installerPackageName;
- }
- childRes.removedInfo.isUpdate = true;
- childRes.removedInfo.installReasons =
- res.removedInfo.installReasons;
- childPackageUpdated = true;
- }
- }
- if (!childPackageUpdated) {
- PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
- childRemovedRes.removedPackage = childPkg.packageName;
- if (childPs != null) {
- childRemovedRes.installerPackageName =
- childPs.installSource.installerPackageName;
- }
- childRemovedRes.isUpdate = false;
- childRemovedRes.dataRemoved = true;
- synchronized (mLock) {
- if (childPs != null) {
- childRemovedRes.origUsers = childPs.queryInstalledUsers(
- allUsers,
- true);
- }
- }
- if (res.removedInfo.removedChildPackages == null) {
- res.removedInfo.removedChildPackages = new ArrayMap<>();
- }
- res.removedInfo.removedChildPackages.put(childPkg.packageName,
- childRemovedRes);
- }
- }
- }
-
-
sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
// Set the system/privileged/oem/vendor/product flags as needed
@@ -16735,41 +16412,30 @@ public class PackageManagerService extends IPackageManager.Stub
| (odm ? SCAN_AS_ODM : 0);
if (DEBUG_INSTALL) {
- Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
+ ", old=" + oldPackage);
}
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+ parsedPackage.setUpdatedSystemApp(true);
targetParseFlags = systemParseFlags;
targetScanFlags = systemScanFlags;
} else { // non system replace
replace = true;
if (DEBUG_INSTALL) {
Slog.d(TAG,
- "replaceNonSystemPackageLI: new=" + pkg + ", old="
+ "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
+ oldPackage);
}
-
- String pkgName1 = oldPackage.packageName;
- boolean deletedPkg = true;
- boolean addedPkg = false;
- boolean updatedSettings = false;
-
- final long origUpdateTime = (pkg.mExtras != null)
- ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;
-
}
} else { // new package install
ps = null;
- childPackages = null;
disabledPs = null;
replace = false;
existingPackage = null;
// Remember this for later, in case we need to rollback this install
- String pkgName1 = pkg.packageName;
+ String pkgName1 = parsedPackage.getPackageName();
- if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+ if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage);
// TODO(patb): MOVE TO RECONCILE
synchronized (mLock) {
@@ -16796,9 +16462,10 @@ public class PackageManagerService extends IPackageManager.Stub
shouldCloseFreezerBeforeReturn = false;
return new PrepareResult(replace, targetScanFlags, targetParseFlags,
- existingPackage, pkg, replace /* clearCodeCache */, sysPkg, freezer,
- ps, disabledPs, childPackages);
+ existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
+ ps, disabledPs);
} finally {
+ res.freezer = freezer;
if (shouldCloseFreezerBeforeReturn) {
freezer.close();
}
@@ -16812,7 +16479,7 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
* kernel patches). In normal mode, all file format can be supported.
*/
- private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException,
+ private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException,
PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
@@ -16824,11 +16491,11 @@ public class PackageManagerService extends IPackageManager.Stub
ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
if (legacyMode) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+ final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
if (ps != null && ps.isPrivileged()) {
- fsverityCandidates.put(pkg.baseCodePath, null);
- if (pkg.splitCodePaths != null) {
- for (String splitPath : pkg.splitCodePaths) {
+ fsverityCandidates.put(pkg.getBaseCodePath(), null);
+ if (pkg.getSplitCodePaths() != null) {
+ for (String splitPath : pkg.getSplitCodePaths()) {
fsverityCandidates.put(splitPath, null);
}
}
@@ -16837,16 +16504,17 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
// NB: These files will become only accessible if the signing key is loaded in kernel's
// .fs-verity keyring.
- fsverityCandidates.put(pkg.baseCodePath,
- VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath));
+ fsverityCandidates.put(pkg.getBaseCodePath(),
+ VerityUtils.getFsveritySignatureFilePath(pkg.getBaseCodePath()));
- final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath);
+ final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
+ pkg.getBaseCodePath());
if (new File(dmPath).exists()) {
fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
}
- if (pkg.splitCodePaths != null) {
- for (String path : pkg.splitCodePaths) {
+ if (pkg.getSplitCodePaths() != null) {
+ for (String path : pkg.getSplitCodePaths()) {
fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
@@ -16900,8 +16568,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private void startIntentFilterVerifications(int userId, boolean replacing,
- PackageParser.Package pkg) {
+ private void startIntentFilterVerifications(int userId, boolean replacing, AndroidPackage pkg) {
if (mIntentFilterVerifierComponent == null) {
Slog.w(TAG, "No IntentFilter verification will not be done as "
+ "there is no IntentFilterVerifier available!");
@@ -16914,29 +16581,29 @@ public class PackageManagerService extends IPackageManager.Stub
(userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
- msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid);
+ msg.obj = new IFVerificationParams(
+ pkg.getPackageName(),
+ hasDomainURLs(pkg),
+ pkg.getActivities(),
+ replacing,
+ userId,
+ verifierUid
+ );
mHandler.sendMessage(msg);
-
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
- msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid);
- mHandler.sendMessage(msg);
- }
}
private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing,
- PackageParser.Package pkg) {
- int size = pkg.activities.size();
+ String packageName,
+ boolean hasDomainUrls,
+ List<ParsedActivity> activities) {
+ int size = activities.size();
if (size == 0) {
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"No activity, so no need to verify any IntentFilter!");
return;
}
- final boolean hasDomainURLs = hasDomainURLs(pkg);
- if (!hasDomainURLs) {
+ if (!hasDomainUrls) {
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"No domain URLs, so no need to verify any IntentFilter!");
return;
@@ -16947,7 +16614,6 @@ public class PackageManagerService extends IPackageManager.Stub
+ " Activities needs verification ...");
int count = 0;
- final String packageName = pkg.packageName;
synchronized (mLock) {
// If this is a new install and we see that we've already run verification for this
@@ -16966,8 +16632,8 @@ public class PackageManagerService extends IPackageManager.Stub
// If any filters need to be verified, then all need to be.
boolean needToVerify = false;
- for (PackageParser.Activity a : pkg.activities) {
- for (ActivityIntentInfo filter : a.intents) {
+ for (ParsedActivity a : activities) {
+ for (ParsedActivityIntentInfo filter : a.intents) {
if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG,
@@ -16981,8 +16647,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (needToVerify) {
final int verificationId = mIntentFilterVerificationToken++;
- for (PackageParser.Activity a : pkg.activities) {
- for (ActivityIntentInfo filter : a.intents) {
+ for (ParsedActivity a : activities) {
+ for (ParsedActivityIntentInfo filter : a.intents) {
if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) {
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"Verification needed for IntentFilter:" + filter.toString());
@@ -17008,9 +16674,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy("mLock")
- private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
- final ComponentName cn = filter.activity.getComponentName();
- final String packageName = cn.getPackageName();
+ private boolean needsNetworkVerificationLPr(ParsedActivityIntentInfo filter) {
+ final String packageName = filter.getPackageName();
IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
packageName);
@@ -17030,45 +16695,45 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private static boolean isExternal(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
+ private static boolean isExternal(AndroidPackage pkg) {
+ return (pkg.getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
private static boolean isExternal(PackageSetting ps) {
return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
- static boolean isSystemApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ static boolean isSystemApp(AndroidPackage pkg) {
+ return (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
}
- private static boolean isPrivilegedApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ private static boolean isPrivilegedApp(AndroidPackage pkg) {
+ return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
- private static boolean isOemApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+ private static boolean isOemApp(AndroidPackage pkg) {
+ return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
}
- private static boolean isVendorApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+ private static boolean isVendorApp(AndroidPackage pkg) {
+ return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
}
- private static boolean isProductApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+ private static boolean isProductApp(AndroidPackage pkg) {
+ return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
}
- private static boolean isSystemExtApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags
+ private static boolean isSystemExtApp(AndroidPackage pkg) {
+ return (pkg.getPrivateFlags()
& ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
}
- private static boolean isOdmApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
+ private static boolean isOdmApp(AndroidPackage pkg) {
+ return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
}
- private static boolean hasDomainURLs(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
+ private static boolean hasDomainURLs(AndroidPackage pkg) {
+ return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
}
private static boolean isSystemApp(PackageSetting ps) {
@@ -17079,12 +16744,12 @@ public class PackageManagerService extends IPackageManager.Stub
return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
- private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) {
+ private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
if (isExternal(pkg)) {
- if (TextUtils.isEmpty(pkg.volumeUuid)) {
+ if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
return mSettings.getExternalVersion();
} else {
- return mSettings.findOrCreateVersion(pkg.volumeUuid);
+ return mSettings.findOrCreateVersion(pkg.getVolumeUuid());
}
} else {
return mSettings.getInternalVersion();
@@ -17092,6 +16757,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private void deleteTempPackageFiles() {
+ // TODO: Is this used?
final FilenameFilter filter =
(dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp");
}
@@ -17225,11 +16891,11 @@ public class PackageManagerService extends IPackageManager.Stub
});
}
- private String resolveExternalPackageNameLPr(PackageParser.Package pkg) {
- if (pkg.staticSharedLibName != null) {
- return pkg.manifestPackageName;
+ private String resolveExternalPackageNameLPr(AndroidPackage pkg) {
+ if (pkg.getStaticSharedLibName() != null) {
+ return pkg.getManifestPackageName();
}
- return pkg.packageName;
+ return pkg.getPackageName();
}
@GuardedBy("mLock")
@@ -17436,7 +17102,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageSetting uninstalledPs;
final PackageSetting disabledSystemPs;
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
// for the uninstall-updates case and restricted profiles, remember the per-
// user handle installed state
@@ -17468,9 +17134,9 @@ public class PackageManagerService extends IPackageManager.Stub
allUsers = mUserManager.getUserIds();
- if (pkg != null && pkg.staticSharedLibName != null) {
- SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName,
- pkg.staticSharedLibVersion);
+ if (pkg != null && pkg.getStaticSharedLibName() != null) {
+ SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
+ pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
if (libraryInfo != null) {
for (int currUserId : allUsers) {
if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) {
@@ -17479,7 +17145,7 @@ public class PackageManagerService extends IPackageManager.Stub
List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
libraryInfo, MATCH_KNOWN_PACKAGES, currUserId);
if (!ArrayUtils.isEmpty(libClientPackages)) {
- Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
+ Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
+ " hosting lib " + libraryInfo.getName() + " version "
+ libraryInfo.getLongVersion() + " used by " + libClientPackages
+ " for user " + currUserId);
@@ -17534,13 +17200,13 @@ public class PackageManagerService extends IPackageManager.Stub
if (info.args != null) {
info.args.doPostDeleteLI(true);
}
- final PackageParser.Package stubPkg =
+ final AndroidPackage stubPkg =
(disabledSystemPs == null) ? null : disabledSystemPs.pkg;
- if (stubPkg != null && stubPkg.isStub) {
+ if (stubPkg != null && stubPkg.isStub()) {
synchronized (mLock) {
// restore the enabled state of the stub; the state is overwritten when
// the stub is uninstalled
- final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+ final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.getPackageName());
if (stubPs != null) {
stubPs.setEnabled(origEnabledState, userId, "android");
}
@@ -17549,7 +17215,7 @@ public class PackageManagerService extends IPackageManager.Stub
|| origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "Enabling system stub after removal; pkg: "
- + stubPkg.packageName);
+ + stubPkg.getPackageName());
}
enableCompressedPackage(stubPkg);
}
@@ -17577,7 +17243,6 @@ public class PackageManagerService extends IPackageManager.Stub
boolean isStaticSharedLib;
// Clean up resources deleted packages.
InstallArgs args = null;
- ArrayMap<String, PackageRemovedInfo> removedChildPackages;
ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
PackageRemovedInfo(PackageSender packageSender) {
@@ -17586,24 +17251,11 @@ public class PackageManagerService extends IPackageManager.Stub
void sendPackageRemovedBroadcasts(boolean killApp) {
sendPackageRemovedBroadcastInternal(killApp);
- final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
- childInfo.sendPackageRemovedBroadcastInternal(killApp);
- }
}
void sendSystemPackageUpdatedBroadcasts() {
if (isRemovedPackageSystemUpdate) {
sendSystemPackageUpdatedBroadcastsInternal();
- final int childCount = (removedChildPackages != null)
- ? removedChildPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
- if (childInfo.isRemovedPackageSystemUpdate) {
- childInfo.sendSystemPackageUpdatedBroadcastsInternal();
- }
- }
}
}
@@ -17715,12 +17367,12 @@ public class PackageManagerService extends IPackageManager.Stub
String packageName = deletedPs.name;
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
// Retrieve object to delete permissions for shared user later on
- final PackageParser.Package deletedPkg = deletedPs.pkg;
+ final AndroidPackage deletedPkg = deletedPs.pkg;
if (outInfo != null) {
outInfo.removedPackage = packageName;
outInfo.installerPackageName = deletedPs.installSource.installerPackageName;
outInfo.isStaticSharedLib = deletedPkg != null
- && deletedPkg.staticSharedLibName != null;
+ && deletedPkg.getStaticSharedLibName() != null;
outInfo.populateUsers(deletedPs == null ? null
: deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
}
@@ -17728,14 +17380,14 @@ public class PackageManagerService extends IPackageManager.Stub
removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0);
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- final PackageParser.Package resolvedPkg;
+ final AndroidPackage resolvedPkg;
if (deletedPkg != null) {
resolvedPkg = deletedPkg;
} else {
// We don't have a parsed package when it lives on an ejected
// adopted storage device, so fake something together
- resolvedPkg = new PackageParser.Package(deletedPs.name);
- resolvedPkg.setVolumeUuid(deletedPs.volumeUuid);
+ resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.name,
+ deletedPs.volumeUuid);
}
destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
@@ -17849,13 +17501,13 @@ public class PackageManagerService extends IPackageManager.Stub
throws SystemDeleteException {
final boolean applyUserRestrictions =
(allUserHandles != null) && outInfo != null && (outInfo.origUsers != null);
- final PackageParser.Package deletedPkg = deletedPs.pkg;
+ final AndroidPackage deletedPkg = deletedPs.pkg;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
// reader
final PackageSetting disabledPs = action.disabledPs;
- if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
+ if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
+ " disabledPs=" + disabledPs);
Slog.d(TAG, "Deleting system pkg from data partition");
@@ -17872,21 +17524,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (outInfo != null) {
// Delete the updated package
outInfo.isRemovedPackageSystemUpdate = true;
- if (outInfo.removedChildPackages != null) {
- final int childCount = (deletedPs.childPackageNames != null)
- ? deletedPs.childPackageNames.size() : 0;
- for (int i = 0; i < childCount; i++) {
- String childPackageName = deletedPs.childPackageNames.get(i);
- if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
- .contains(childPackageName)) {
- PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
- childPackageName);
- if (childInfo != null) {
- childInfo.isRemovedPackageSystemUpdate = true;
- }
- }
- }
- }
}
if (disabledPs.versionCode < deletedPs.versionCode) {
@@ -17898,7 +17535,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
- outInfo, writeSettings, disabledPs.pkg);
+ outInfo, writeSettings);
// writer
synchronized (mLock) {
@@ -17919,16 +17556,16 @@ public class PackageManagerService extends IPackageManager.Stub
outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
writeSettings);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
+ Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
+ e.getMessage());
// TODO(patb): can we avoid this; throw would come from scan...
throw new SystemDeleteException(e);
} finally {
- if (disabledPs.pkg.isStub) {
+ if (disabledPs.pkg.isStub()) {
// We've re-installed the stub; make sure it's disabled here. If package was
// originally enabled, we'll install the compressed version of the application
// and re-enable it afterward.
- final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName);
+ final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName());
if (stubPs != null) {
stubPs.setEnabled(
COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
@@ -17940,7 +17577,7 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* Installs a package that's already on the system partition.
*/
- private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString,
+ private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
@Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
@Nullable PermissionsState origPermissionState, boolean writeSettings)
throws PackageManagerException {
@@ -17961,7 +17598,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final File codePath = new File(codePathString);
- final PackageParser.Package pkg =
+ final AndroidPackage pkg =
scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
try {
@@ -17975,7 +17612,7 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
synchronized (mLock) {
- PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+ PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
// Propagate the permissions state as we do not want to drop on the floor
// runtime permissions. The update permissions method below will take
@@ -17983,7 +17620,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (origPermissionState != null) {
ps.getPermissionsState().copyFrom(origPermissionState);
}
- mPermissionManager.updatePermissions(pkg.packageName, pkg);
+ mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
final boolean applyUserRestrictions
= (allUserHandles != null) && (origUserHandles != null);
@@ -18021,58 +17658,22 @@ public class PackageManagerService extends IPackageManager.Stub
private void deleteInstalledPackageLIF(PackageSetting ps,
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
- PackageRemovedInfo outInfo, boolean writeSettings,
- PackageParser.Package replacingPackage) {
+ PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mLock) {
if (outInfo != null) {
outInfo.uid = ps.appId;
}
-
- if (outInfo != null && outInfo.removedChildPackages != null) {
- final int childCount = (ps.childPackageNames != null)
- ? ps.childPackageNames.size() : 0;
- for (int i = 0; i < childCount; i++) {
- String childPackageName = ps.childPackageNames.get(i);
- PackageSetting childPs = mSettings.mPackages.get(childPackageName);
- PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
- childPackageName);
- if (childInfo != null) {
- childInfo.uid = childPs.appId;
- }
- }
- }
}
// Delete package data from internal structures and also remove data if flag is set
removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings);
- // Delete the child packages data
- final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageSetting childPs;
- synchronized (mLock) {
- childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
- }
- if (childPs != null) {
- PackageRemovedInfo childOutInfo = (outInfo != null
- && outInfo.removedChildPackages != null)
- ? outInfo.removedChildPackages.get(childPs.name) : null;
- final int deleteFlags = (flags & DELETE_KEEP_DATA) != 0
- && (replacingPackage != null
- && !replacingPackage.hasChildPackage(childPs.name))
- ? flags & ~DELETE_KEEP_DATA : flags;
- removePackageDataLIF(childPs, allUserHandles, childOutInfo,
- deleteFlags, writeSettings);
- }
- }
-
// Delete application code and resources only for parent packages
- if (ps.parentPackageName == null) {
- if (deleteCodeAndResources && (outInfo != null)) {
- outInfo.args = createInstallArgsForExisting(
- ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
- }
+ if (deleteCodeAndResources && (outInfo != null)) {
+ outInfo.args = createInstallArgsForExisting(
+ ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(
+ ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
+ if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
}
@@ -18085,10 +17686,10 @@ public class PackageManagerService extends IPackageManager.Stub
// Cannot block uninstall of static shared libs as they are
// considered a part of the using app (emulating static linking).
// Also static libs are installed always on internal storage.
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null && pkg.staticSharedLibName != null) {
+ AndroidPackage pkg = mPackages.get(packageName);
+ if (pkg != null && pkg.getStaticSharedLibName() != null) {
Slog.w(TAG, "Cannot block uninstall of package: " + packageName
- + " providing static shared library: " + pkg.staticSharedLibName);
+ + " providing static shared library: " + pkg.getStaticSharedLibName());
return false;
}
mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall);
@@ -18152,40 +17753,22 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
private static DeletePackageAction mayDeletePackageLocked(
PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
- @Nullable PackageSetting[] children, int flags, UserHandle user) {
+ int flags, UserHandle user) {
if (ps == null) {
return null;
}
if (isSystemApp(ps)) {
- if (ps.parentPackageName != null) {
- Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName);
- return null;
- }
-
final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0;
final boolean deleteAllUsers =
user == null || user.getIdentifier() == UserHandle.USER_ALL;
if ((!deleteSystem || deleteAllUsers) && disabledPs == null) {
- Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.packageName);
+ Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.getPackageName());
return null;
}
// Confirmed if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition reader
}
- final int parentReferenceCount =
- (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
- final int childCount = children != null ? children.length : 0;
- if (childCount != parentReferenceCount) {
- return null;
- }
- if (childCount != 0 && outInfo != null && outInfo.removedChildPackages != null) {
- for (PackageSetting child : children) {
- if (child == null || !ps.childPackageNames.contains(child.name)) {
- return null;
- }
- }
- }
return new DeletePackageAction(ps, disabledPs, outInfo, flags, user);
}
@@ -18195,13 +17778,12 @@ public class PackageManagerService extends IPackageManager.Stub
private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
boolean deleteCodeAndResources, int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings,
- PackageParser.Package replacingPackage) {
+ ParsedPackage replacingPackage) {
final DeletePackageAction action;
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
- PackageSetting[] children = mSettings.getChildSettingsLPr(ps);
- action = mayDeletePackageLocked(outInfo, ps, disabledPs, children, flags, user);
+ action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user);
}
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
if (null == action) {
@@ -18232,30 +17814,13 @@ public class PackageManagerService extends IPackageManager.Stub
private void executeDeletePackageLIF(DeletePackageAction action,
String packageName, boolean deleteCodeAndResources,
int[] allUserHandles, boolean writeSettings,
- PackageParser.Package replacingPackage) throws SystemDeleteException {
+ ParsedPackage replacingPackage) throws SystemDeleteException {
final PackageSetting ps = action.deletingPs;
final PackageRemovedInfo outInfo = action.outInfo;
final UserHandle user = action.user;
final int flags = action.flags;
final boolean systemApp = isSystemApp(ps);
- if (ps.parentPackageName != null
- && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
- if (DEBUG_REMOVE) {
- Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
- + ((user == null) ? UserHandle.USER_ALL : user));
- }
- final int removedUserId = (user != null) ? user.getIdentifier()
- : UserHandle.USER_ALL;
-
- clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags);
- synchronized (mLock) {
- markPackageUninstalledForUserLPw(ps, user);
- scheduleWritePackageRestrictionsLocked(user);
- }
- return;
- }
-
final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS, userId)) {
unsuspendForSuspendingPackage(packageName, userId);
@@ -18305,26 +17870,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- // If we are deleting a composite package for all users, keep track
- // of result for each child.
- if (ps.childPackageNames != null && outInfo != null) {
- synchronized (mLock) {
- final int childCount = ps.childPackageNames.size();
- outInfo.removedChildPackages = new ArrayMap<>(childCount);
- for (int i = 0; i < childCount; i++) {
- String childPackageName = ps.childPackageNames.get(i);
- PackageRemovedInfo childInfo = new PackageRemovedInfo(this);
- childInfo.removedPackage = childPackageName;
- childInfo.installerPackageName = ps.installSource.installerPackageName;
- outInfo.removedChildPackages.put(childPackageName, childInfo);
- PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
- if (childPs != null) {
- childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true);
- }
- }
- }
- }
-
// TODO(b/109941548): break reasons for ret = false out into mayDelete method
if (systemApp) {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
@@ -18334,53 +17879,12 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
- outInfo, writeSettings, replacingPackage);
+ outInfo, writeSettings);
}
// Take a note whether we deleted the package for all users
if (outInfo != null) {
outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
- if (outInfo.removedChildPackages != null) {
- synchronized (mLock) {
- final int childCount = outInfo.removedChildPackages.size();
- for (int i = 0; i < childCount; i++) {
- PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i);
- if (childInfo != null) {
- childInfo.removedForAllUsers = mPackages.get(
- childInfo.removedPackage) == null;
- }
- }
- }
- }
- // If we uninstalled an update to a system app there may be some
- // child packages that appeared as they are declared in the system
- // app but were not declared in the update.
- if (systemApp) {
- synchronized (mLock) {
- PackageSetting updatedPs = mSettings.getPackageLPr(ps.name);
- final int childCount = (updatedPs.childPackageNames != null)
- ? updatedPs.childPackageNames.size() : 0;
- for (int i = 0; i < childCount; i++) {
- String childPackageName = updatedPs.childPackageNames.get(i);
- if (outInfo.removedChildPackages == null
- || outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) {
- PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
- if (childPs == null) {
- continue;
- }
- PackageInstalledInfo installRes = new PackageInstalledInfo();
- installRes.name = childPackageName;
- installRes.newUsers = childPs.queryInstalledUsers(allUserHandles, true);
- installRes.pkg = mPackages.get(childPackageName);
- installRes.uid = childPs.pkg.applicationInfo.uid;
- if (outInfo.appearedChildPackages == null) {
- outInfo.appearedChildPackages = new ArrayMap<>();
- }
- outInfo.appearedChildPackages.put(childPackageName, installRes);
- }
- }
- }
- }
}
}
@@ -18414,7 +17918,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void clearPackageStateForUserLIF(PackageSetting ps, int userId,
PackageRemovedInfo outInfo, int flags) {
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(ps.name);
}
@@ -18456,7 +17960,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (outInfo != null) {
outInfo.removedPackage = ps.name;
outInfo.installerPackageName = ps.installSource.installerPackageName;
- outInfo.isStaticSharedLib = pkg != null && pkg.staticSharedLibName != null;
+ outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
outInfo.removedAppId = ps.appId;
outInfo.removedUsers = userIds;
outInfo.broadcastUsers = userIds;
@@ -18467,7 +17971,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void clearApplicationProfileData(String packageName) {
enforceSystemOrRoot("Only the system can clear all profile data");
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
}
@@ -18545,7 +18049,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Try finding details about the requested package
- PackageParser.Package pkg;
+ AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
@@ -18564,7 +18068,7 @@ public class PackageManagerService extends IPackageManager.Stub
clearAppDataLIF(pkg, userId,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
- final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+ final int appId = UserHandle.getAppId(pkg.getUid());
removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId);
UserManagerInternal umInternal = mInjector.getUserManagerInternal();
@@ -18641,14 +18145,14 @@ public class PackageManagerService extends IPackageManager.Stub
final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.ACCESS_INSTANT_APPS);
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
}
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(() -> {
- final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = pkg == null ? null : getPackageSetting(pkg.getPackageName());
boolean doClearData = true;
if (ps != null) {
final boolean targetIsInstantApp =
@@ -18728,7 +18232,7 @@ public class PackageManagerService extends IPackageManager.Stub
while (it.hasNext()) {
final PackageSetting ps = it.next();
if (ps.pkg != null) {
- int v = ps.pkg.applicationInfo.targetSdkVersion;
+ int v = ps.pkg.getTargetSdkVersion();
if (v < vers) vers = v;
}
}
@@ -18736,7 +18240,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (ps.pkg != null) {
- return ps.pkg.applicationInfo.targetSdkVersion;
+ return ps.pkg.getTargetSdkVersion();
}
}
return Build.VERSION_CODES.CUR_DEVELOPMENT;
@@ -18744,9 +18248,9 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
private int getPackageTargetSdkVersionLockedLPr(String packageName) {
- final PackageParser.Package p = mPackages.get(packageName);
+ final AndroidPackage p = mPackages.get(packageName);
if (p != null) {
- return p.applicationInfo.targetSdkVersion;
+ return p.getTargetSdkVersion();
}
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
@@ -18915,7 +18419,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// writer
synchronized (mLock) {
- PackageParser.Package pkg = mPackages.get(packageName);
+ AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -18989,8 +18493,8 @@ public class PackageManagerService extends IPackageManager.Stub
private void clearIntentFilterVerificationsLPw(int userId) {
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
- PackageParser.Package pkg = mPackages.valueAt(i);
- clearIntentFilterVerificationsLPw(pkg.packageName, userId);
+ AndroidPackage pkg = mPackages.valueAt(i);
+ clearIntentFilterVerificationsLPw(pkg.getPackageName(), userId);
}
}
@@ -19682,13 +19186,14 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getSystemTextClassifierPackageName() {
- return mContext.getString(R.string.config_defaultTextClassifierPackage);
+ return ensureSystemPackageName(mContext.getString(
+ R.string.config_defaultTextClassifierPackage));
}
@Override
public String[] getSystemTextClassifierPackages() {
- return mContext.getResources().getStringArray(
- R.array.config_defaultTextClassifierPackages);
+ return ensureSystemPackageNames(mContext.getResources().getStringArray(
+ R.array.config_defaultTextClassifierPackages));
}
@Override
@@ -19698,7 +19203,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (flattenedComponentName != null) {
ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName);
if (componentName != null && componentName.getPackageName() != null) {
- return componentName.getPackageName();
+ return ensureSystemPackageName(componentName.getPackageName());
}
}
return null;
@@ -19723,9 +19228,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ @Nullable
+ private String getDeviceConfiguratorPackageName() {
+ return ensureSystemPackageName(mContext.getString(
+ R.string.config_deviceConfiguratorPackageName));
+ }
+
@Override
public String getWellbeingPackageName() {
- return mContext.getString(R.string.config_defaultWellbeingPackage);
+ return ensureSystemPackageName(mContext.getString(R.string.config_defaultWellbeingPackage));
}
@Override
@@ -19740,7 +19251,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (appPredictionServiceComponentName == null) {
return null;
}
- return appPredictionServiceComponentName.getPackageName();
+ return ensureSystemPackageName(appPredictionServiceComponentName.getPackageName());
}
@Override
@@ -19757,7 +19268,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (systemCaptionsServiceComponentName == null) {
return null;
}
- return systemCaptionsServiceComponentName.getPackageName();
+ return ensureSystemPackageName(systemCaptionsServiceComponentName.getPackageName());
}
@Override
@@ -19769,7 +19280,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
public String getIncidentReportApproverPackageName() {
- return mContext.getString(R.string.config_incidentReportApproverPackage);
+ return ensureSystemPackageName(mContext.getString(
+ R.string.config_incidentReportApproverPackage));
}
@Override
@@ -19779,7 +19291,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!TextUtils.isEmpty(names)) {
telephonyPackageNames = names.trim().split(",");
}
- return telephonyPackageNames;
+ return ensureSystemPackageNames(telephonyPackageNames);
}
@Override
@@ -19796,7 +19308,32 @@ public class PackageManagerService extends IPackageManager.Stub
if (contentCaptureServiceComponentName == null) {
return null;
}
- return contentCaptureServiceComponentName.getPackageName();
+ return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName());
+ }
+
+ @Nullable
+ private String ensureSystemPackageName(@Nullable String packageName) {
+ if (packageName == null) {
+ return null;
+ }
+ if (getPackageInfo(packageName, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE | MATCH_DISABLED_COMPONENTS,
+ UserHandle.getCallingUserId()) == null) {
+ return null;
+ }
+ return packageName;
+ }
+
+ @Nullable
+ private String[] ensureSystemPackageNames(@Nullable String[] packageNames) {
+ if (packageNames == null) {
+ return null;
+ }
+ final int packageNamesLength = packageNames.length;
+ for (int i = 0; i < packageNamesLength; i++) {
+ packageNames[i] = ensureSystemPackageName(packageNames[i]);
+ }
+ return ArrayUtils.filterNotNull(packageNames, String[]::new);
}
@Override
@@ -19938,8 +19475,8 @@ public class PackageManagerService extends IPackageManager.Stub
// If we're enabling a system stub, there's a little more work to do.
// Prior to enabling the package, we need to decompress the APK(s) to the
// data partition and then replace the version on the system partition.
- final PackageParser.Package deletedPkg = pkgSetting.pkg;
- final boolean isSystemStub = deletedPkg.isStub
+ final AndroidPackage deletedPkg = pkgSetting.pkg;
+ final boolean isSystemStub = deletedPkg.isStub()
&& deletedPkg.isSystem();
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
@@ -19960,10 +19497,10 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
// We're dealing with a component level state change
// First, verify that this is a valid class name.
- PackageParser.Package pkg = pkgSetting.pkg;
+ AndroidPackage pkg = pkgSetting.pkg;
if (pkg == null || !pkg.hasComponentClassName(className)) {
if (pkg != null &&
- pkg.applicationInfo.targetSdkVersion >=
+ pkg.getTargetSdkVersion() >=
Build.VERSION_CODES.JELLY_BEAN) {
throw new IllegalArgumentException("Component class " + className
+ " does not exist in " + packageName);
@@ -20428,14 +19965,14 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null) {
return;
}
- PackageParser.Package pkg = mPackages.get(packageName);
+ AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
return;
}
- sendPackageChangedBroadcast(pkg.packageName,
+ sendPackageChangedBroadcast(pkg.getPackageName(),
true /* dontKillApp */,
- new ArrayList<>(Collections.singletonList(pkg.packageName)),
- pkg.applicationInfo.uid,
+ new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
+ pkg.getUid(),
Intent.ACTION_OVERLAY_CHANGED);
}
}, overlayFilter);
@@ -21024,7 +20561,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
&& packageName == null) {
- mComponentResolver.dumpServicePermissions(pw, dumpState, packageName);
+ mComponentResolver.dumpServicePermissions(pw, dumpState);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
@@ -21167,9 +20704,9 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.println();
ipw.println("Dexopt state:");
ipw.increaseIndent();
- Collection<PackageParser.Package> packages;
+ Collection<AndroidPackage> packages;
if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
+ AndroidPackage targetPackage = mPackages.get(packageName);
if (targetPackage != null) {
packages = Collections.singletonList(targetPackage);
} else {
@@ -21180,11 +20717,11 @@ public class PackageManagerService extends IPackageManager.Stub
packages = mPackages.values();
}
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
+ for (AndroidPackage pkg : packages) {
+ ipw.println("[" + pkg.getPackageName() + "]");
ipw.increaseIndent();
mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
- mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
+ mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
ipw.decreaseIndent();
}
}
@@ -21196,9 +20733,9 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.println();
ipw.println("Compiler stats:");
ipw.increaseIndent();
- Collection<PackageParser.Package> packages;
+ Collection<AndroidPackage> packages;
if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
+ AndroidPackage targetPackage = mPackages.get(packageName);
if (targetPackage != null) {
packages = Collections.singletonList(targetPackage);
} else {
@@ -21209,11 +20746,11 @@ public class PackageManagerService extends IPackageManager.Stub
packages = mPackages.values();
}
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
+ for (AndroidPackage pkg : packages) {
+ ipw.println("[" + pkg.getPackageName() + "]");
ipw.increaseIndent();
- CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
+ CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.getPackageName());
if (stats == null) {
ipw.println("(No recorded stats)");
} else {
@@ -21284,14 +20821,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
- final int size = infos.size();
+ ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) {
+ final int size = packages.size();
final String[] packageNames = new String[size];
final int[] packageUids = new int[size];
for (int i = 0; i < size; i++) {
- final ApplicationInfo info = infos.get(i);
- packageNames[i] = info.packageName;
- packageUids[i] = info.uid;
+ final AndroidPackage pkg = packages.get(i);
+ packageNames[i] = pkg.getAppInfoPackageName();
+ packageUids[i] = pkg.getUid();
}
sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
finishedReceiver);
@@ -21334,7 +20871,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final ArrayList<PackageFreezer> freezers = new ArrayList<>();
- final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
+ final ArrayList<AndroidPackage> loaded = new ArrayList<>();
final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
final VersionInfo ver;
@@ -21347,10 +20884,10 @@ public class PackageManagerService extends IPackageManager.Stub
for (PackageSetting ps : packages) {
freezers.add(freezePackage(ps.name, "loadPrivatePackagesInner"));
synchronized (mInstallLock) {
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
try {
pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null);
- loaded.add(pkg.applicationInfo);
+ loaded.add(pkg);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
@@ -21422,14 +20959,14 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
- final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
+ final ArrayList<AndroidPackage> unloaded = new ArrayList<>();
synchronized (mInstallLock) {
synchronized (mLock) {
final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
for (PackageSetting ps : packages) {
if (ps.pkg == null) continue;
- final ApplicationInfo info = ps.pkg.applicationInfo;
+ final AndroidPackage pkg = ps.pkg;
final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
final PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
@@ -21437,7 +20974,7 @@ public class PackageManagerService extends IPackageManager.Stub
"unloadPrivatePackagesInner")) {
if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
false, null)) {
- unloaded.add(info);
+ unloaded.add(pkg);
} else {
Slog.w(TAG, "Failed to unload " + ps.codePath);
}
@@ -21652,7 +21189,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
// Skip non-core apps if requested
- if (onlyCoreApps && !ps.pkg.coreApp) {
+ if (onlyCoreApps && !ps.pkg.isCoreApp()) {
result.add(packageName);
continue;
}
@@ -21679,10 +21216,10 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>
* <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
*/
- private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
+ private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.packageName);
+ ps = mSettings.mPackages.get(pkg.getPackageName());
mSettings.writeKernelMappingLPr(ps);
}
@@ -21712,19 +21249,15 @@ public class PackageManagerService extends IPackageManager.Stub
* will try recovering system apps by wiping data; third-party app data is
* left intact.
*/
- private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+ private void prepareAppDataLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
prepareAppDataLeafLIF(pkg, userId, flags);
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
- }
}
- private void prepareAppDataAndMigrateLIF(PackageParser.Package pkg, int userId, int flags,
+ private void prepareAppDataAndMigrateLIF(AndroidPackage pkg, int userId, int flags,
boolean maybeMigrateAppData) {
prepareAppDataLIF(pkg, userId, flags);
@@ -21735,43 +21268,37 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+ private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
if (DEBUG_APP_DATA) {
- Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
+ Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
+ Integer.toHexString(flags));
}
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.packageName);
+ ps = mSettings.mPackages.get(pkg.getPackageName());
}
- final String volumeUuid = pkg.volumeUuid;
- final String packageName = pkg.packageName;
+ final String volumeUuid = pkg.getVolumeUuid();
+ final String packageName = pkg.getPackageName();
- ApplicationInfo app = (ps == null)
- ? pkg.applicationInfo
- : PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId);
- if (app == null) {
- app = pkg.applicationInfo;
- }
+ final int appId = UserHandle.getAppId(pkg.getUid());
- final int appId = UserHandle.getAppId(app.uid);
+ Preconditions.checkNotNull(pkg.getSeInfo());
- Preconditions.checkNotNull(app.seInfo);
-
- final String seInfo = app.seInfo + (app.seInfoUser != null ? app.seInfoUser : "");
+ final String seInfo =
+ pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
long ceDataInode = -1;
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
- appId, seInfo, app.targetSdkVersion);
+ appId, seInfo, pkg.getTargetSdkVersion());
} catch (InstallerException e) {
- if (app.isSystemApp()) {
+ if (pkg.isSystemApp()) {
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
+ ", but trying to recover: " + e);
destroyAppDataLeafLIF(pkg, userId, flags);
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
- appId, seInfo, app.targetSdkVersion);
+ appId, seInfo, pkg.getTargetSdkVersion());
logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
} catch (InstallerException e2) {
logCriticalInfo(Log.DEBUG, "Recovery failed!");
@@ -21813,29 +21340,24 @@ public class PackageManagerService extends IPackageManager.Stub
prepareAppDataContentsLeafLIF(pkg, userId, flags);
}
- private void prepareAppDataContentsLIF(PackageParser.Package pkg, int userId, int flags) {
+ private void prepareAppDataContentsLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
prepareAppDataContentsLeafLIF(pkg, userId, flags);
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- prepareAppDataContentsLeafLIF(pkg.childPackages.get(i), userId, flags);
- }
}
- private void prepareAppDataContentsLeafLIF(PackageParser.Package pkg, int userId, int flags) {
- final String volumeUuid = pkg.volumeUuid;
- final String packageName = pkg.packageName;
- final ApplicationInfo app = pkg.applicationInfo;
+ private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, int userId, int flags) {
+ final String volumeUuid = pkg.getVolumeUuid();
+ final String packageName = pkg.getPackageName();
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
// Create a native library symlink only if we have native libraries
// and if the native libraries are 32 bit libraries. We do not provide
// this symlink for 64 bit libraries.
- if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) {
- final String nativeLibPath = app.nativeLibraryDir;
+ if (pkg.getPrimaryCpuAbi() != null && !VMRuntime.is64BitAbi(pkg.getPrimaryCpuAbi())) {
+ final String nativeLibPath = pkg.getNativeLibraryDir();
try {
mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
nativeLibPath, userId);
@@ -21851,17 +21373,17 @@ public class PackageManagerService extends IPackageManager.Stub
* CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
* requested by the app.
*/
- private boolean maybeMigrateAppDataLIF(PackageParser.Package pkg, int userId) {
+ private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) {
if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated()
&& PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
- final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage()
+ final int storageTarget = pkg.isDefaultToDeviceProtectedStorage()
? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
try {
- mInstaller.migrateAppData(pkg.volumeUuid, pkg.packageName, userId,
+ mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId,
storageTarget);
} catch (InstallerException e) {
logCriticalInfo(Log.WARN,
- "Failed to migrate " + pkg.packageName + ": " + e.getMessage());
+ "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage());
}
return true;
} else {
@@ -21912,7 +21434,6 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private class PackageFreezer implements AutoCloseable {
private final String mPackageName;
- private final PackageFreezer[] mChildren;
private final boolean mWeFroze;
@@ -21927,7 +21448,6 @@ public class PackageManagerService extends IPackageManager.Stub
*/
public PackageFreezer() {
mPackageName = null;
- mChildren = null;
mWeFroze = false;
mCloseGuard.open("close");
}
@@ -21941,18 +21461,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (ps != null) {
killApplication(ps.name, ps.appId, userId, killReason);
}
-
- final PackageParser.Package p = mPackages.get(packageName);
- if (p != null && p.childPackages != null) {
- final int N = p.childPackages.size();
- mChildren = new PackageFreezer[N];
- for (int i = 0; i < N; i++) {
- mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName,
- userId, killReason);
- }
- } else {
- mChildren = null;
- }
}
mCloseGuard.open("close");
}
@@ -21975,12 +21483,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (mWeFroze) {
mFrozenPackages.remove(mPackageName);
}
-
- if (mChildren != null) {
- for (PackageFreezer freezer : mChildren) {
- freezer.close();
- }
- }
}
}
}
@@ -22035,14 +21537,14 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
- final PackageParser.Package pkg = mPackages.get(packageName);
+ final AndroidPackage pkg = mPackages.get(packageName);
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (pkg == null
|| ps == null
|| shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
}
- if (pkg.applicationInfo.isSystemApp()) {
+ if (pkg.isSystemApp()) {
throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
"Cannot move system application");
}
@@ -22057,7 +21559,7 @@ public class PackageManagerService extends IPackageManager.Stub
currentVolumeUuid = ps.volumeUuid;
- final File probe = new File(pkg.codePath);
+ final File probe = new File(pkg.getCodePath());
final File probeOat = new File(probe, "oat");
if (!probe.isDirectory() || !probeOat.isDirectory()) {
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
@@ -22068,7 +21570,7 @@ public class PackageManagerService extends IPackageManager.Stub
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Package already moved to " + volumeUuid);
}
- if (pkg.applicationInfo.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
+ if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
"Device admin cannot be moved");
}
@@ -22079,13 +21581,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
isCurrentLocationExternal = isExternal(pkg);
- codeFile = new File(pkg.codePath);
+ codeFile = new File(pkg.getCodePath());
installSource = ps.installSource;
packageAbiOverride = ps.cpuAbiOverrideString;
- appId = UserHandle.getAppId(pkg.applicationInfo.uid);
- seinfo = pkg.applicationInfo.seInfo;
- label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
- targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ appId = UserHandle.getAppId(pkg.getUid());
+ seinfo = pkg.getSeInfo();
+ label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfoWithoutState()));
+ targetSdkVersion = pkg.getTargetSdkVersion();
freezer = freezePackage(packageName, "movePackageInternal");
installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
}
@@ -22246,7 +21748,7 @@ public class PackageManagerService extends IPackageManager.Stub
* @param packageName The package that was moved.
*/
private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
}
@@ -22254,8 +21756,8 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
- final StorageManager storage = mInjector.getStorageManager();
- VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
+ final StorageManager storage = mInjector.getStorageManager();;
+ VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString());
int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
if (!isPreviousLocationExternal && isExternal(pkg)) {
@@ -22369,10 +21871,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (ps.pkg == null) {
continue;
}
- final String packageName = ps.pkg.packageName;
+ final String packageName = ps.pkg.getPackageName();
// Skip over if system app or static shared library
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
- || !TextUtils.isEmpty(ps.pkg.staticSharedLibName)) {
+ || !TextUtils.isEmpty(ps.pkg.getStaticSharedLibName())) {
continue;
}
if (DEBUG_CLEAN_APKS) {
@@ -22499,13 +22001,13 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null || alias == null) {
return null;
}
- synchronized (mLock) {
- final PackageParser.Package pkg = mPackages.get(packageName);
+ synchronized(mLock) {
+ final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (shouldFilterApplicationLocked(
ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
@@ -22524,19 +22026,19 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageParser.Package pkg = mPackages.get(packageName);
+ final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
// filter and pretend the package doesn't exist
Slog.w(TAG, "KeySet requested for filtered package: " + packageName
+ ", uid:" + callingUid);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- if (pkg.applicationInfo.uid != callingUid
+ if (pkg.getUid() != callingUid
&& Process.SYSTEM_UID != callingUid) {
throw new SecurityException("May not access signing KeySet of other apps.");
}
@@ -22554,11 +22056,11 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null || ks == null) {
return false;
}
- synchronized (mLock) {
- final PackageParser.Package pkg = mPackages.get(packageName);
+ synchronized(mLock) {
+ final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null
- || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
- UserHandle.getUserId(callingUid))) {
+ || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
+ callingUid, UserHandle.getUserId(callingUid))) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -22581,10 +22083,10 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
synchronized (mLock) {
- final PackageParser.Package pkg = mPackages.get(packageName);
+ final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null
- || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
- UserHandle.getUserId(callingUid))) {
+ || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
+ callingUid, UserHandle.getUserId(callingUid))) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -22616,29 +22118,29 @@ public class PackageManagerService extends IPackageManager.Stub
* Check and throw if the given before/after packages would be considered a
* downgrade.
*/
- private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
+ private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
throws PackageManagerException {
if (after.getLongVersionCode() < before.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update version code " + after.versionCode + " is older than current "
+ before.getLongVersionCode());
} else if (after.getLongVersionCode() == before.getLongVersionCode()) {
- if (after.baseRevisionCode < before.baseRevisionCode) {
+ if (after.baseRevisionCode < before.getBaseRevisionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update base revision code " + after.baseRevisionCode
- + " is older than current " + before.baseRevisionCode);
+ + " is older than current " + before.getBaseRevisionCode());
}
if (!ArrayUtils.isEmpty(after.splitNames)) {
for (int i = 0; i < after.splitNames.length; i++) {
final String splitName = after.splitNames[i];
- final int j = ArrayUtils.indexOf(before.splitNames, splitName);
+ final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
if (j != -1) {
- if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) {
+ if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update split " + splitName + " revision code "
+ after.splitRevisionCodes[i] + " is older than current "
- + before.splitRevisionCodes[j]);
+ + before.getSplitRevisionCodes()[j]);
}
}
}
@@ -22828,13 +22330,13 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageSetting == null) {
return false;
}
- PackageParser.Package pkg = packageSetting.pkg;
+ AndroidPackage pkg = packageSetting.pkg;
if (pkg == null) {
// May happen if package in on a removable sd card
return false;
}
- return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails)
- || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
+ return pkg.getSigningDetails().hasAncestorOrSelf(mPlatformPackage.getSigningDetails())
+ || mPlatformPackage.getSigningDetails().checkCapability(pkg.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION);
}
@@ -22870,11 +22372,11 @@ public class PackageManagerService extends IPackageManager.Stub
private SigningDetails getSigningDetails(@NonNull String packageName) {
synchronized (mLock) {
- PackageParser.Package p = mPackages.get(packageName);
+ AndroidPackage p = mPackages.get(packageName);
if (p == null) {
return null;
}
- return p.mSigningDetails;
+ return p.getSigningDetails();
}
}
@@ -22905,28 +22407,25 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) {
+ public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
synchronized (mLock) {
- return PackageManagerService.this.shouldFilterApplicationLocked(
- (PackageSetting) pkg.mExtras, callingUid, userId);
+ PackageSetting ps = getPackageSetting(pkg.getPackageName());
+ return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
+ userId);
}
}
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
synchronized (mLock) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- return false;
- }
- return PackageManagerService.this
- .shouldFilterApplicationLocked(
- (PackageSetting) pkg.mExtras, callingUid, userId);
+ PackageSetting ps = getPackageSetting(packageName);
+ return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
+ userId);
}
}
@Override
- public PackageParser.Package getPackage(String packageName) {
+ public AndroidPackage getPackage(String packageName) {
synchronized (mLock) {
packageName = resolveInternalPackageNameLPr(
packageName, PackageManager.VERSION_CODE_HIGHEST);
@@ -22935,10 +22434,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public PackageParser.Package getPackage(int uid) {
+ public AndroidPackage getPackage(int uid) {
synchronized (mLock) {
final String[] packageNames = getPackagesForUid(uid);
- PackageParser.Package pkg = null;
+ AndroidPackage pkg = null;
final int numPackages = packageNames == null ? 0 : packageNames.length;
for (int i = 0; pkg == null && i < numPackages; i++) {
pkg = mPackages.get(packageNames[i]);
@@ -22947,6 +22446,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ @Nullable
+ @Override
+ public PackageSetting getPackageSetting(String packageName) {
+ return PackageManagerService.this.getPackageSetting(packageName);
+ }
+
@Override
public PackageList getPackageList(PackageListObserver observer) {
synchronized (mLock) {
@@ -22971,17 +22476,19 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public PackageParser.Package getDisabledSystemPackage(String packageName) {
+ public Object getDisabledSystemPackage(@NonNull String packageName) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
- return (ps != null) ? ps.pkg : null;
+ return mSettings.getDisabledSystemPkgLPr(packageName);
}
}
@Override
- public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) {
- PackageParser.Package pkg = getDisabledSystemPackage(packageName);
- return pkg == null ? null : pkg.packageName;
+ public @Nullable
+ String getDisabledSystemPackageName(@NonNull String packageName) {
+ PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage(
+ packageName);
+ AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
+ return disabledPkg == null ? null : disabledPkg.getPackageName();
}
/**
@@ -23005,7 +22512,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
- PackageParser.Package pkg = getPackage(pkgName);
+ AndroidPackage pkg = getPackage(pkgName);
if (pkg == null) {
Log.w(TAG, "Could not find package " + pkgName);
continue;
@@ -23094,7 +22601,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPermissionsReviewRequired(String packageName, int userId) {
synchronized (mLock) {
- final PackageParser.Package pkg = mPackages.get(packageName);
+ final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
return false;
}
@@ -23280,9 +22787,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) {
+ public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) {
synchronized (mLock) {
- return mSettings.isEnabledAndMatchLPr(info, flags, userId);
+ AndroidPackage pkg = getPackage(component.getPackageName());
+ return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId);
}
}
@@ -23299,10 +22807,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean setInstalled(PackageParser.Package pkg, @UserIdInt int userId,
+ public boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId,
boolean installed) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+ final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
if (ps.getInstalled(userId) != installed) {
ps.setInstalled(installed, userId);
return true;
@@ -23324,16 +22832,15 @@ public class PackageManagerService extends IPackageManager.Stub
public void grantImplicitAccess(int userId, Intent intent,
int callingUid, int targetAppId) {
synchronized (mLock) {
- final PackageParser.Package callingPackage = getPackage(callingUid);
+ final AndroidPackage callingPackage = getPackage(callingUid);
final int targetUid = UserHandle.getUid(userId, targetAppId);
- final PackageParser.Package targetPackage =
- getPackage(targetUid);
+ final AndroidPackage targetPackage = getPackage(targetUid);
if (callingPackage == null || targetPackage == null) {
return;
}
- final boolean instantApp = isInstantAppInternal(callingPackage.packageName, userId,
- callingUid);
+ final boolean instantApp = isInstantAppInternal(callingPackage.getPackageName(),
+ userId, callingUid);
if (instantApp) {
mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
UserHandle.getAppId(callingUid), targetAppId);
@@ -23370,9 +22877,9 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPackagePersistent(String packageName) {
synchronized (mLock) {
- PackageParser.Package pkg = mPackages.get(packageName);
+ AndroidPackage pkg = mPackages.get(packageName);
return pkg != null
- ? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM
+ ? ((pkg.getFlags() & (ApplicationInfo.FLAG_SYSTEM
| ApplicationInfo.FLAG_PERSISTENT)) ==
(ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT))
: false;
@@ -23380,9 +22887,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean isLegacySystemApp(PackageParser.Package pkg) {
+ public boolean isLegacySystemApp(AndroidPackage pkg) {
synchronized (mLock) {
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = getPackageSetting(pkg.getPackageName());
return mPromoteSystemApps
&& ps.isSystem()
&& mExistingSystemPackages.contains(ps.name);
@@ -23393,9 +22900,10 @@ public class PackageManagerService extends IPackageManager.Stub
public List<PackageInfo> getOverlayPackages(int userId) {
final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
synchronized (mLock) {
- for (PackageParser.Package p : mPackages.values()) {
- if (p.mOverlayTarget != null) {
- PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId);
+ for (AndroidPackage p : mPackages.values()) {
+ if (p.getOverlayTarget() != null) {
+ PackageInfo pkg = generatePackageInfo(getPackageSetting(p.getPackageName()),
+ 0, userId);
if (pkg != null) {
overlayPackages.add(pkg);
}
@@ -23409,9 +22917,9 @@ public class PackageManagerService extends IPackageManager.Stub
public List<String> getTargetPackageNames(int userId) {
List<String> targetPackages = new ArrayList<>();
synchronized (mLock) {
- for (PackageParser.Package p : mPackages.values()) {
- if (p.mOverlayTarget == null) {
- targetPackages.add(p.packageName);
+ for (AndroidPackage p : mPackages.values()) {
+ if (p.getOverlayTarget() == null) {
+ targetPackages.add(p.getPackageName());
}
}
}
@@ -23432,12 +22940,12 @@ public class PackageManagerService extends IPackageManager.Stub
overlayPaths = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
final String packageName = overlayPackageNames.get(i);
- final PackageParser.Package pkg = mPackages.get(packageName);
+ final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
Slog.e(TAG, "failed to find package " + packageName);
return false;
}
- overlayPaths.add(pkg.baseCodePath);
+ overlayPaths.add(pkg.getBaseCodePath());
}
}
@@ -23555,12 +23063,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+ public void forEachPackage(Consumer<AndroidPackage> actionLocked) {
PackageManagerService.this.forEachPackage(actionLocked);
}
@Override
- public void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+ public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
@UserIdInt int userId) {
PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
}
@@ -23609,7 +23117,7 @@ public class PackageManagerService extends IPackageManager.Stub
*/
@Override
public boolean compileLayouts(String packageName) {
- PackageParser.Package pkg;
+ AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
@@ -23716,12 +23224,12 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isCallerInstallerOfRecord(
- @NonNull PackageParser.Package pkg, int callingUid) {
+ @NonNull AndroidPackage pkg, int callingUid) {
synchronized (mLock) {
if (pkg == null) {
return false;
}
- final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+ final PackageSetting packageSetting = getPackageSetting(pkg.getPackageName());
if (packageSetting == null) {
return false;
}
@@ -23750,6 +23258,14 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.writeLPr();
}
}
+
+ @Override
+ public void setIntegrityVerificationResult(int verificationId, int verificationResult) {
+ final Message msg = mHandler.obtainMessage(INTEGRITY_VERIFICATION_COMPLETE);
+ msg.arg1 = verificationId;
+ msg.obj = verificationResult;
+ mHandler.sendMessage(msg);
+ }
}
@GuardedBy("mLock")
@@ -23784,11 +23300,12 @@ public class PackageManagerService extends IPackageManager.Stub
PackageSetting ps = it.next();
if (ps.getInstalled(userId)) {
res[i++] = ps.name;
- } else {
- res = ArrayUtils.removeElement(String.class, res, res[i]);
}
}
- return res;
+ res = ArrayUtils.trimToSize(res, i);
+ if (res != null) {
+ return res;
+ }
} catch (PackageManagerException e) {
// Should not happen
}
@@ -23818,7 +23335,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+ @Nullable
+ public PackageSetting getPackageSetting(String packageName) {
+ synchronized (mPackages) {
+ packageName = resolveInternalPackageNameLPr(
+ packageName, PackageManager.VERSION_CODE_HIGHEST);
+ return mSettings.mPackages.get(packageName);
+ }
+ }
+
+ void forEachPackage(Consumer<AndroidPackage> actionLocked) {
synchronized (mLock) {
int numPackages = mPackages.size();
for (int i = 0; i < numPackages; i++) {
@@ -23827,13 +23353,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+ void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
@UserIdInt int userId) {
synchronized (mLock) {
int numPackages = mPackages.size();
for (int i = 0; i < numPackages; i++) {
- PackageParser.Package pkg = mPackages.valueAt(i);
- PackageSetting setting = mSettings.getPackageLPr(pkg.packageName);
+ AndroidPackage pkg = mPackages.valueAt(i);
+ PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName());
if (setting == null || !setting.getInstalled(userId)) {
continue;
}
@@ -23850,7 +23376,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Return a <b>copy</b> of the collection of packages known to the package manager.
* @return A copy of the values of mPackages.
*/
- Collection<PackageParser.Package> getPackages() {
+ Collection<AndroidPackage> getPackages() {
synchronized (mLock) {
return new ArrayList<>(mPackages.values());
}
@@ -23886,8 +23412,8 @@ public class PackageManagerService extends IPackageManager.Stub
return mCompilerStats.getPackageStats(pkgName);
}
- public CompilerStats.PackageStats getOrCreateCompilerPackageStats(PackageParser.Package pkg) {
- return getOrCreateCompilerPackageStats(pkg.packageName);
+ public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) {
+ return getOrCreateCompilerPackageStats(pkg.getPackageName());
}
public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) {
@@ -23997,7 +23523,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean canHaveOatDir(String packageName) {
synchronized (mLock) {
- PackageParser.Package p = mPackages.get(packageName);
+ AndroidPackage p = mPackages.get(packageName);
if (p == null) {
return false;
}
@@ -24005,11 +23531,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private String getOatDir(PackageParser.Package pkg) {
+ private String getOatDir(AndroidPackage pkg) {
if (!pkg.canHaveOatDir()) {
return null;
}
- File codePath = new File(pkg.codePath);
+ File codePath = new File(pkg.getCodePath());
if (codePath.isDirectory()) {
return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
}
@@ -24020,11 +23546,12 @@ public class PackageManagerService extends IPackageManager.Stub
final String[] instructionSets;
final List<String> codePaths;
final String oatDir;
- final PackageParser.Package pkg;
+ final AndroidPackage pkg;
synchronized (mLock) {
pkg = mPackages.get(packageName);
}
- instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+ instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+ pkg.getSecondaryCpuAbi());
codePaths = pkg.getAllCodePaths();
oatDir = getOatDir(pkg);
@@ -24043,19 +23570,19 @@ public class PackageManagerService extends IPackageManager.Stub
Set<String> unusedPackages = new HashSet<>();
long currentTimeInMillis = System.currentTimeMillis();
synchronized (mLock) {
- for (PackageParser.Package pkg : mPackages.values()) {
- PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+ for (AndroidPackage pkg : mPackages.values()) {
+ PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
if (ps == null) {
continue;
}
PackageDexUsage.PackageUseInfo packageUseInfo =
- getDexManager().getPackageUseInfoOrDefault(pkg.packageName);
+ getDexManager().getPackageUseInfoOrDefault(pkg.getPackageName());
if (PackageManagerServiceUtils
.isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis,
downgradeTimeThresholdMillis, packageUseInfo,
pkg.getLatestPackageUseTimeInMills(),
pkg.getLatestForegroundPackageUseTimeInMills())) {
- unusedPackages.add(pkg.packageName);
+ unusedPackages.add(pkg.getPackageName());
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index ef47410ded8c..ded9a9c58c5e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -35,10 +35,13 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
import android.os.Build;
import android.os.Debug;
import android.os.Environment;
@@ -120,7 +123,7 @@ public class PackageManagerServiceUtils {
// Sort a list of apps by their last usage, most recently used apps first. The order of
// packages without usage data is undefined (but they will be sorted after the packages
// that do have usage data).
- public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
+ public static void sortPackagesByUsageDate(List<AndroidPackage> pkgs,
PackageManagerService packageManagerService) {
if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
return;
@@ -135,12 +138,12 @@ public class PackageManagerServiceUtils {
// package will be removed from {@code packages} and added to {@code result} with its
// dependencies. If usage data is available, the positive packages will be sorted by usage
// data (with {@code sortTemp} as temporary storage).
- private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
- Collection<PackageParser.Package> result,
- Collection<PackageParser.Package> packages,
- @NonNull List<PackageParser.Package> sortTemp,
+ private static void applyPackageFilter(Predicate<AndroidPackage> filter,
+ Collection<AndroidPackage> result,
+ Collection<AndroidPackage> packages,
+ @NonNull List<AndroidPackage> sortTemp,
PackageManagerService packageManagerService) {
- for (PackageParser.Package pkg : packages) {
+ for (AndroidPackage pkg : packages) {
if (filter.test(pkg)) {
sortTemp.add(pkg);
}
@@ -149,10 +152,10 @@ public class PackageManagerServiceUtils {
sortPackagesByUsageDate(sortTemp, packageManagerService);
packages.removeAll(sortTemp);
- for (PackageParser.Package pkg : sortTemp) {
+ for (AndroidPackage pkg : sortTemp) {
result.add(pkg);
- Collection<PackageParser.Package> deps =
+ Collection<AndroidPackage> deps =
packageManagerService.findSharedNonSystemLibraries(pkg);
if (!deps.isEmpty()) {
deps.removeAll(result);
@@ -166,50 +169,51 @@ public class PackageManagerServiceUtils {
// Sort apps by importance for dexopt ordering. Important apps are given
// more priority in case the device runs out of space.
- public static List<PackageParser.Package> getPackagesForDexopt(
- Collection<PackageParser.Package> packages,
+ public static List<AndroidPackage> getPackagesForDexopt(
+ Collection<AndroidPackage> packages,
PackageManagerService packageManagerService) {
return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
}
- public static List<PackageParser.Package> getPackagesForDexopt(
- Collection<PackageParser.Package> packages,
+ public static List<AndroidPackage> getPackagesForDexopt(
+ Collection<AndroidPackage> packages,
PackageManagerService packageManagerService,
boolean debug) {
- ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
- LinkedList<PackageParser.Package> result = new LinkedList<>();
- ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
+ ArrayList<AndroidPackage> remainingPkgs = new ArrayList<>(packages);
+ LinkedList<AndroidPackage> result = new LinkedList<>();
+ ArrayList<AndroidPackage> sortTemp = new ArrayList<>(remainingPkgs.size());
// Give priority to core apps.
- applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
+ applyPackageFilter((pkg) -> pkg.isCoreApp(), result, remainingPkgs, sortTemp,
packageManagerService);
// Give priority to system apps that listen for pre boot complete.
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
- applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
+ applyPackageFilter((pkg) -> pkgNames.contains(pkg.getPackageName()), result, remainingPkgs,
sortTemp, packageManagerService);
// Give priority to apps used by other apps.
DexManager dexManager = packageManagerService.getDexManager();
applyPackageFilter((pkg) ->
- dexManager.getPackageUseInfoOrDefault(pkg.packageName)
+ dexManager.getPackageUseInfoOrDefault(pkg.getPackageName())
.isAnyCodePathUsedByOtherApps(),
result, remainingPkgs, sortTemp, packageManagerService);
// Filter out packages that aren't recently used, add all remaining apps.
// TODO: add a property to control this?
- Predicate<PackageParser.Package> remainingPredicate;
+ Predicate<AndroidPackage> remainingPredicate;
if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
if (debug) {
Log.i(TAG, "Looking at historical package use");
}
// Get the package that was used last.
- PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
+ AndroidPackage lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
pkg2.getLatestForegroundPackageUseTimeInMills()));
if (debug) {
- Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
+ Log.i(TAG, "Taking package " + lastUsed.getPackageName()
+ + " as reference in time use");
}
long estimatedPreviousSystemUseTime =
lastUsed.getLatestForegroundPackageUseTimeInMills();
@@ -285,13 +289,13 @@ public class PackageManagerServiceUtils {
}
}
- public static String packagesToString(Collection<PackageParser.Package> c) {
+ public static String packagesToString(Collection<AndroidPackage> c) {
StringBuilder sb = new StringBuilder();
- for (PackageParser.Package pkg : c) {
+ for (AndroidPackage pkg : c) {
if (sb.length() > 0) {
sb.append(", ");
}
- sb.append(pkg.packageName);
+ sb.append(pkg.getPackageName());
}
return sb.toString();
}
@@ -309,16 +313,16 @@ public class PackageManagerServiceUtils {
return false;
}
- public static long getLastModifiedTime(PackageParser.Package pkg) {
- final File srcFile = new File(pkg.codePath);
+ public static long getLastModifiedTime(AndroidPackage pkg) {
+ final File srcFile = new File(pkg.getCodePath());
if (!srcFile.isDirectory()) {
return srcFile.lastModified();
}
- final File baseFile = new File(pkg.baseCodePath);
+ final File baseFile = new File(pkg.getBaseCodePath());
long maxModifiedTime = baseFile.lastModified();
- if (pkg.splitCodePaths != null) {
- for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
- final File splitFile = new File(pkg.splitCodePaths[i]);
+ if (pkg.getSplitCodePaths() != null) {
+ for (int i = pkg.getSplitCodePaths().length - 1; i >=0; --i) {
+ final File splitFile = new File(pkg.getSplitCodePaths()[i]);
maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
}
}
@@ -539,7 +543,7 @@ public class PackageManagerServiceUtils {
private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
PackageSetting disabledPkgSetting) {
try {
- PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
+ ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
if (pkgSetting.signatures.mSigningDetails.checkCapability(
disabledPkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
@@ -905,8 +909,10 @@ public class PackageManagerServiceUtils {
* Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState}
* could not be found, {@code null} will be returned.
*/
- public static PermissionsState getPermissionsState(PackageParser.Package pkg) {
- final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+ public static PermissionsState getPermissionsState(
+ PackageManagerInternal packageManagerInternal, AndroidPackage pkg) {
+ final PackageSetting packageSetting =
+ (PackageSetting) packageManagerInternal.getPackageSetting(pkg.getPackageName());
if (packageSetting == null) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index b96109683115..fff404f3ede6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -48,7 +48,6 @@ import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
@@ -62,6 +61,7 @@ import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
+import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
@@ -453,7 +453,7 @@ class PackageManagerShellCommand extends ShellCommand {
throw new IllegalArgumentException("Error: Can't open file: " + inPath);
}
try {
- ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0);
+ ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0);
PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
null, null);
sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d38dd9344821..bbc0dc986b0c 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -18,8 +18,9 @@ package com.android.server.pm;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
import android.service.pm.PackageProto;
import android.util.proto.ProtoOutputStream;
@@ -31,9 +32,11 @@ import java.util.List;
/**
* Settings data for a particular package we know about.
*/
-public final class PackageSetting extends PackageSettingBase {
+public final class PackageSetting extends PackageSettingBase implements
+ ParsedPackage.PackageSettingCallback {
int appId;
- PackageParser.Package pkg;
+
+ public AndroidPackage pkg;
/**
* WARNING. The object reference is important. We perform integer equality and NOT
* object equality to check whether shared user settings are the same.
@@ -50,12 +53,12 @@ public final class PackageSetting extends PackageSettingBase {
PackageSetting(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- long pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
- List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries,
+ long pVersionCode, int pkgFlags, int privateFlags,
+ int sharedUserId, String[] usesStaticLibraries,
long[] usesStaticLibrariesVersions) {
super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames,
+ pVersionCode, pkgFlags, privateFlags,
usesStaticLibraries, usesStaticLibrariesVersions);
this.sharedUserId = sharedUserId;
}
@@ -116,10 +119,6 @@ public final class PackageSetting extends PackageSettingBase {
: super.getPermissionsState();
}
- public PackageParser.Package getPackage() {
- return pkg;
- }
-
public int getAppId() {
return appId;
}
@@ -132,6 +131,7 @@ public final class PackageSetting extends PackageSettingBase {
return installPermissionsFixed;
}
+ // TODO(b/135203078): Remove these in favor of reading from the package directly
public boolean isPrivileged() {
return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
@@ -176,10 +176,6 @@ public final class PackageSetting extends PackageSettingBase {
return true;
}
- public boolean hasChildPackages() {
- return childPackageNames != null && !childPackageNames.isEmpty();
- }
-
public void dumpDebug(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
final long packageToken = proto.start(fieldId);
proto.write(PackageProto.NAME, (realName != null ? realName : name));
@@ -190,18 +186,19 @@ public final class PackageSetting extends PackageSettingBase {
proto.write(PackageProto.INSTALLER_NAME, installSource.installerPackageName);
if (pkg != null) {
- proto.write(PackageProto.VERSION_STRING, pkg.mVersionName);
+ proto.write(PackageProto.VERSION_STRING, pkg.getVersionName());
long splitToken = proto.start(PackageProto.SPLITS);
proto.write(PackageProto.SplitProto.NAME, "base");
- proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode);
+ proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.getBaseRevisionCode());
proto.end(splitToken);
- if (pkg.splitNames != null) {
- for (int i = 0; i < pkg.splitNames.length; i++) {
+ if (pkg.getSplitNames() != null) {
+ for (int i = 0; i < pkg.getSplitNames().length; i++) {
splitToken = proto.start(PackageProto.SPLITS);
- proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]);
- proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]);
+ proto.write(PackageProto.SplitProto.NAME, pkg.getSplitNames()[i]);
+ proto.write(PackageProto.SplitProto.REVISION_CODE,
+ pkg.getSplitRevisionCodes()[i]);
proto.end(splitToken);
}
}
@@ -225,4 +222,10 @@ public final class PackageSetting extends PackageSettingBase {
sharedUserId = other.sharedUserId;
sharedUser = other.sharedUser;
}
+
+ // TODO(b/135203078): Move to constructor
+ @Override
+ public void setAndroidPackage(AndroidPackage pkg) {
+ this.pkg = pkg;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 45ab3575c805..671450d71b4d 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -39,7 +39,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.io.File;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -54,9 +53,6 @@ public abstract class PackageSettingBase extends SettingBase {
public final String name;
final String realName;
- String parentPackageName;
- List<String> childPackageNames;
-
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
@@ -138,14 +134,10 @@ public abstract class PackageSettingBase extends SettingBase {
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
long pVersionCode, int pkgFlags, int pkgPrivateFlags,
- String parentPackageName, List<String> childPackageNames,
String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
super(pkgFlags, pkgPrivateFlags);
this.name = name;
this.realName = realName;
- this.parentPackageName = parentPackageName;
- this.childPackageNames = (childPackageNames != null)
- ? new ArrayList<>(childPackageNames) : null;
this.usesStaticLibraries = usesStaticLibraries;
this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
this.codePath = codePath;
@@ -235,8 +227,6 @@ public abstract class PackageSettingBase extends SettingBase {
}
private void doCopy(PackageSettingBase orig) {
- childPackageNames = (orig.childPackageNames != null)
- ? new ArrayList<>(orig.childPackageNames) : null;
codePath = orig.codePath;
codePathString = orig.codePathString;
cpuAbiOverrideString = orig.cpuAbiOverrideString;
@@ -247,7 +237,6 @@ public abstract class PackageSettingBase extends SettingBase {
lastUpdateTime = orig.lastUpdateTime;
legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
// Intentionally skip mOldCodePaths; it's not relevant for copies
- parentPackageName = orig.parentPackageName;
primaryCpuAbiString = orig.primaryCpuAbiString;
resourcePath = orig.resourcePath;
resourcePathString = orig.resourcePathString;
@@ -670,8 +659,6 @@ public abstract class PackageSettingBase extends SettingBase {
protected PackageSettingBase updateFrom(PackageSettingBase other) {
super.copyFrom(other);
- this.parentPackageName = other.parentPackageName;
- this.childPackageNames = other.childPackageNames;
this.codePath = other.codePath;
this.codePathString = other.codePathString;
this.resourcePath = other.resourcePath;
diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java
index ac1f739cd9f8..ce2c9e767d5e 100644
--- a/services/core/java/com/android/server/pm/PackageUsage.java
+++ b/services/core/java/com/android/server/pm/PackageUsage.java
@@ -20,7 +20,7 @@ import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
import android.os.FileUtils;
import android.util.AtomicFile;
import android.util.Log;
@@ -36,7 +36,7 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
-class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> {
+class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> {
private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_";
private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1";
@@ -52,7 +52,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
}
@Override
- protected void writeInternal(Map<String, PackageParser.Package> packages) {
+ protected void writeInternal(Map<String, AndroidPackage> packages) {
AtomicFile file = getFile();
FileOutputStream f = null;
try {
@@ -66,13 +66,13 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
sb.append('\n');
out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
- for (PackageParser.Package pkg : packages.values()) {
+ for (AndroidPackage pkg : packages.values()) {
if (pkg.getLatestPackageUseTimeInMills() == 0L) {
continue;
}
sb.setLength(0);
- sb.append(pkg.packageName);
- for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) {
+ sb.append(pkg.getPackageName());
+ for (long usageTimeInMillis : pkg.getLastPackageUsageTimeInMills()) {
sb.append(' ');
sb.append(usageTimeInMillis);
}
@@ -90,7 +90,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
}
@Override
- protected void readInternal(Map<String, PackageParser.Package> packages) {
+ protected void readInternal(Map<String, AndroidPackage> packages) {
AtomicFile file = getFile();
BufferedInputStream in = null;
try {
@@ -114,7 +114,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
}
}
- private void readVersion0LP(Map<String, PackageParser.Package> packages, InputStream in,
+ private void readVersion0LP(Map<String, AndroidPackage> packages, InputStream in,
StringBuffer sb, String firstLine)
throws IOException {
// Initial version of the file had no version number and stored one
@@ -128,7 +128,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
}
String packageName = tokens[0];
- PackageParser.Package pkg = packages.get(packageName);
+ AndroidPackage pkg = packages.get(packageName);
if (pkg == null) {
continue;
}
@@ -137,12 +137,12 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
for (int reason = 0;
reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
reason++) {
- pkg.mLastPackageUsageTimeInMills[reason] = timestamp;
+ pkg.mutate().setLastPackageUsageTimeInMills(reason, timestamp);
}
}
}
- private void readVersion1LP(Map<String, PackageParser.Package> packages, InputStream in,
+ private void readVersion1LP(Map<String, AndroidPackage> packages, InputStream in,
StringBuffer sb) throws IOException {
// Version 1 of the file started with the corresponding version
// number and then stored a package name and eight timestamps per line.
@@ -154,7 +154,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
}
String packageName = tokens[0];
- PackageParser.Package pkg = packages.get(packageName);
+ AndroidPackage pkg = packages.get(packageName);
if (pkg == null) {
continue;
}
@@ -162,7 +162,8 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
for (int reason = 0;
reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
reason++) {
- pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]);
+ pkg.mutate().setLastPackageUsageTimeInMills(reason,
+ parseAsLong(tokens[reason + 1]));
}
}
}
@@ -196,4 +197,4 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>>
sb.append((char)ch);
}
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 4ff3e1218b53..a5065145cafd 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -16,7 +16,10 @@
package com.android.server.pm;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsedPackage;
import android.os.Process;
import android.os.Trace;
import android.util.DisplayMetrics;
@@ -30,8 +33,6 @@ import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-
/**
* Helper class for parallel parsing of packages using {@link PackageParser}.
* <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}.
@@ -65,14 +66,14 @@ class ParallelPackageParser implements AutoCloseable {
static class ParseResult {
- PackageParser.Package pkg; // Parsed package
+ ParsedPackage parsedPackage; // Parsed package
File scanFile; // File that was parsed
Throwable throwable; // Set if an error occurs during parsing
@Override
public String toString() {
return "ParseResult{" +
- "pkg=" + pkg +
+ "parsedPackage=" + parsedPackage +
", scanFile=" + scanFile +
", throwable=" + throwable +
'}';
@@ -100,7 +101,7 @@ class ParallelPackageParser implements AutoCloseable {
/**
* Submits the file for parsing
* @param scanFile file to scan
- * @param parseFlags parse falgs
+ * @param parseFlags parse flags
*/
public void submit(File scanFile, int parseFlags) {
mService.submit(() -> {
@@ -114,7 +115,7 @@ class ParallelPackageParser implements AutoCloseable {
pp.setCacheDir(mCacheDir);
pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile;
- pr.pkg = parsePackage(pp, scanFile, parseFlags);
+ pr.parsedPackage = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
@@ -133,9 +134,9 @@ class ParallelPackageParser implements AutoCloseable {
}
@VisibleForTesting
- protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+ protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
- return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
+ return packageParser.parseParsedPackage(scanFile, parseFlags, true);
}
@Override
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index d20f20ffec46..466f19c43289 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -21,6 +21,7 @@ import android.compat.annotation.EnabledAfter;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Environment;
import android.util.Slog;
import android.util.Xml;
@@ -336,7 +337,7 @@ public final class SELinuxMMAC {
}
}
- private static int getTargetSdkVersionForSeInfo(PackageParser.Package pkg,
+ private static int getTargetSdkVersionForSeInfo(AndroidPackage pkg,
SharedUserSetting sharedUserSetting, PlatformCompat compatibility) {
// Apps which share a sharedUserId must be placed in the same selinux domain. If this
// package is the first app installed as this shared user, set seInfoTargetSdkVersion to its
@@ -349,11 +350,11 @@ public final class SELinuxMMAC {
if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) {
return sharedUserSetting.seInfoTargetSdkVersion;
}
- if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.applicationInfo)) {
+ if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.toAppInfoWithoutState())) {
return android.os.Build.VERSION_CODES.R;
}
- return pkg.applicationInfo.targetSdkVersion;
+ return pkg.getTargetSdkVersion();
}
/**
@@ -367,7 +368,7 @@ public final class SELinuxMMAC {
* @param compatibility the PlatformCompat service to ask about state of compat changes.
* @return String representing the resulting seinfo.
*/
- public static String getSeInfo(PackageParser.Package pkg, SharedUserSetting sharedUserSetting,
+ public static String getSeInfo(AndroidPackage pkg, SharedUserSetting sharedUserSetting,
PlatformCompat compatibility) {
final int targetSdkVersion = getTargetSdkVersionForSeInfo(pkg, sharedUserSetting,
compatibility);
@@ -391,7 +392,7 @@ public final class SELinuxMMAC {
* MINIMUM_TARGETSDKVERSION.
* @return String representing the resulting seinfo.
*/
- public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged,
+ public static String getSeInfo(AndroidPackage pkg, boolean isPrivileged,
int targetSdkVersion) {
String seInfo = null;
synchronized (sPolicies) {
@@ -420,8 +421,8 @@ public final class SELinuxMMAC {
seInfo += TARGETSDKVERSION_STR + targetSdkVersion;
if (DEBUG_POLICY_INSTALL) {
- Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
- "seinfo=" + seInfo);
+ Slog.i(TAG, "package (" + pkg.getPackageName() + ") labeled with "
+ + "seinfo=" + seInfo);
}
return seInfo;
}
@@ -430,7 +431,7 @@ public final class SELinuxMMAC {
/**
* Holds valid policy representations of individual stanzas from a mac_permissions.xml
* file. Each instance can further be used to assign seinfo values to apks using the
- * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the
+ * {@link Policy#getMatchedSeInfo(AndroidPackage)} method. To create an instance of this use the
* {@link PolicyBuilder} pattern class, where each instance is validated against a set
* of invariants before being built and returned. Each instance can be guaranteed to
* hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml
@@ -557,21 +558,21 @@ final class Policy {
* @return A string representing the seinfo matched during policy lookup.
* A value of null can also be returned if no match occured.
*/
- public String getMatchedSeInfo(PackageParser.Package pkg) {
+ public String getMatchedSeInfo(AndroidPackage pkg) {
// Check for exact signature matches across all certs.
Signature[] certs = mCerts.toArray(new Signature[0]);
- if (pkg.mSigningDetails != SigningDetails.UNKNOWN
- && !Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) {
+ if (pkg.getSigningDetails() != SigningDetails.UNKNOWN
+ && !Signature.areExactMatch(certs, pkg.getSigningDetails().signatures)) {
// certs aren't exact match, but the package may have rotated from the known system cert
- if (certs.length > 1 || !pkg.mSigningDetails.hasCertificate(certs[0])) {
+ if (certs.length > 1 || !pkg.getSigningDetails().hasCertificate(certs[0])) {
return null;
}
}
// Check for inner package name matches given that the
// signature checks already passed.
- String seinfoValue = mPkgMap.get(pkg.packageName);
+ String seinfoValue = mPkgMap.get(pkg.getPackageName());
if (seinfoValue != null) {
return seinfoValue;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1082eaa0374e..6653011b8b22 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -42,7 +42,6 @@ import android.content.pm.ComponentInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
@@ -50,6 +49,10 @@ import android.content.pm.Signature;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -479,8 +482,8 @@ public final class Settings {
final PackageSetting dp = mDisabledSysPackages.get(name);
// always make sure the system package code and resource paths dont change
if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) {
- if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
- p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ if(p.pkg != null) {
+ p.pkg.mutate().setUpdatedSystemApp(true);
}
final PackageSetting disabled;
if (replaced) {
@@ -506,14 +509,14 @@ public final class Settings {
return null;
}
// Reset flag in ApplicationInfo object
- if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
- p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ if(p.pkg != null) {
+ p.pkg.mutate().setUpdatedSystemApp(false);
}
PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
p.secondaryCpuAbiString, p.cpuAbiOverrideString,
p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
- p.parentPackageName, p.childPackageNames, p.usesStaticLibraries,
+ p.usesStaticLibraries,
p.usesStaticLibrariesVersions);
mDisabledSysPackages.remove(name);
return ret;
@@ -530,8 +533,7 @@ public final class Settings {
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int
- pkgFlags, int pkgPrivateFlags, String parentPackageName,
- List<String> childPackageNames, String[] usesStaticLibraries,
+ pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries,
long[] usesStaticLibraryNames) {
PackageSetting p = mPackages.get(name);
if (p != null) {
@@ -544,8 +546,8 @@ public final class Settings {
}
p = new PackageSetting(name, realName, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName,
- childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
+ cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags,
+ 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
p.appId = uid;
if (registerExistingAppIdLPw(uid, p, name)) {
mPackages.put(name, p);
@@ -607,19 +609,15 @@ public final class Settings {
File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
UserHandle installUser, boolean allowInstall, boolean instantApp,
- boolean virtualPreload, String parentPkgName, List<String> childPkgNames,
- UserManagerService userManager,
+ boolean virtualPreload, UserManagerService userManager,
String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
final PackageSetting pkgSetting;
if (originalPkg != null) {
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ pkgName + " is adopting original package " + originalPkg.name);
pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
- pkgSetting.childPackageNames =
- (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null;
pkgSetting.codePath = codePath;
pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
- pkgSetting.parentPackageName = parentPkgName;
pkgSetting.pkgFlags = pkgFlags;
pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
pkgSetting.primaryCpuAbiString = primaryCpuAbi;
@@ -637,7 +635,7 @@ public final class Settings {
pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
- parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries,
+ 0 /*sharedUserId*/, usesStaticLibraries,
usesStaticLibrariesVersions);
pkgSetting.setTimeStamp(codePath.lastModified());
pkgSetting.sharedUser = sharedUser;
@@ -721,7 +719,7 @@ public final class Settings {
@NonNull File codePath, File resourcePath,
@Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi,
@Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags,
- @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager,
+ @NonNull UserManagerService userManager,
@Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions)
throws PackageManagerException {
final String pkgName = pkgSetting.name;
@@ -799,9 +797,6 @@ public final class Settings {
pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM;
pkgSetting.primaryCpuAbiString = primaryCpuAbi;
pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
- if (childPkgNames != null) {
- pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
- }
// Update static shared library dependencies if needed
if (usesStaticLibraries != null && usesStaticLibrariesVersions != null
&& usesStaticLibraries.length == usesStaticLibrariesVersions.length) {
@@ -870,15 +865,15 @@ public final class Settings {
// TODO: Move to scanPackageOnlyLI() after verifying signatures are setup correctly
// by that time.
- void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
+ void insertPackageSettingLPw(PackageSetting p, AndroidPackage pkg) {
// Update signatures if needed.
if (p.signatures.mSigningDetails.signatures == null) {
- p.signatures.mSigningDetails = pkg.mSigningDetails;
+ p.signatures.mSigningDetails = pkg.getSigningDetails();
}
// If this app defines a shared user id initialize
// the shared user signatures as well.
if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) {
- p.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails;
+ p.sharedUser.signatures.mSigningDetails = pkg.getSigningDetails();
}
addPackageSettingLPw(p, p.sharedUser);
}
@@ -955,7 +950,7 @@ public final class Settings {
int affectedUserId = UserHandle.USER_NULL;
// Update permissions
- for (String eachPerm : deletedPs.pkg.requestedPermissions) {
+ for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
BasePermission bp = mPermissions.getPermission(eachPerm);
if (bp == null) {
continue;
@@ -965,8 +960,8 @@ public final class Settings {
boolean used = false;
for (PackageSetting pkg : sus.packages) {
if (pkg.pkg != null
- && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName)
- && pkg.pkg.requestedPermissions.contains(eachPerm)) {
+ && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
+ && pkg.pkg.getRequestedPermissions().contains(eachPerm)) {
used = true;
break;
}
@@ -976,13 +971,13 @@ public final class Settings {
}
PermissionsState permissionsState = sus.getPermissionsState();
- PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.packageName);
+ PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName());
// If the package is shadowing is a disabled system package,
// do not drop permissions that the shadowed package requests.
if (disabledPs != null) {
boolean reqByDisabledSysPkg = false;
- for (String permission : disabledPs.pkg.requestedPermissions) {
+ for (String permission : disabledPs.pkg.getRequestedPermissions()) {
if (permission.equals(eachPerm)) {
reqByDisabledSysPkg = true;
break;
@@ -2215,20 +2210,6 @@ public final class Settings {
serializer.endTag(null, TAG_PERMISSIONS);
}
- void writeChildPackagesLPw(XmlSerializer serializer, List<String> childPackageNames)
- throws IOException {
- if (childPackageNames == null) {
- return;
- }
- final int childCount = childPackageNames.size();
- for (int i = 0; i < childCount; i++) {
- String childPackageName = childPackageNames.get(i);
- serializer.startTag(null, TAG_CHILD_PACKAGE);
- serializer.attribute(null, ATTR_NAME, childPackageName);
- serializer.endTag(null, TAG_CHILD_PACKAGE);
- }
- }
-
void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs)
throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
@@ -2682,17 +2663,15 @@ public final class Settings {
StringBuilder sb = new StringBuilder();
for (final PackageSetting pkg : mPackages.values()) {
- if (pkg.pkg == null || pkg.pkg.applicationInfo == null
- || pkg.pkg.applicationInfo.dataDir == null) {
+ if (pkg.pkg == null || pkg.pkg.getDataDir() == null) {
if (!"android".equals(pkg.name)) {
Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
}
continue;
}
- final ApplicationInfo ai = pkg.pkg.applicationInfo;
- final String dataPath = ai.dataDir;
- final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ final String dataPath = pkg.pkg.getDataDir();
+ final boolean isDebug = (pkg.pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
final int[] gids = pkg.getPermissionsState().computeGids(userIds);
// Avoid any application that has a space in its path.
@@ -2717,13 +2696,13 @@ public final class Settings {
// system/core/libpackagelistparser
//
sb.setLength(0);
- sb.append(ai.packageName);
+ sb.append(pkg.pkg.getPackageName());
sb.append(" ");
- sb.append(ai.uid);
+ sb.append(pkg.pkg.getUid());
sb.append(isDebug ? " 1 " : " 0 ");
sb.append(dataPath);
sb.append(" ");
- sb.append(ai.seInfo);
+ sb.append(pkg.pkg.getSeInfo());
sb.append(" ");
if (gids != null && gids.length > 0) {
sb.append(gids[0]);
@@ -2735,9 +2714,9 @@ public final class Settings {
sb.append("none");
}
sb.append(" ");
- sb.append(ai.isProfileableByShell() ? "1" : "0");
+ sb.append(pkg.pkg.isProfileableByShell() ? "1" : "0");
sb.append(" ");
- sb.append(String.valueOf(ai.longVersionCode));
+ sb.append(pkg.pkg.getLongVersionCode());
sb.append("\n");
writer.append(sb);
}
@@ -2786,12 +2765,6 @@ public final class Settings {
serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
}
- if (pkg.parentPackageName != null) {
- serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
- }
-
- writeChildPackagesLPw(serializer, pkg.childPackageNames);
-
writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
// If this is a shared user, the permissions will be written there.
@@ -2861,15 +2834,10 @@ public final class Settings {
if (pkg.categoryHint != ApplicationInfo.CATEGORY_UNDEFINED) {
serializer.attribute(null, "categoryHint", Integer.toString(pkg.categoryHint));
}
- if (pkg.parentPackageName != null) {
- serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
- }
if (pkg.updateAvailable) {
serializer.attribute(null, "updateAvailable", "true");
}
- writeChildPackagesLPw(serializer, pkg.childPackageNames);
-
writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
@@ -3161,13 +3129,13 @@ public final class Settings {
LocalServices.getService(PackageManagerInternal.class);
for (PackageSetting ps : mPackages.values()) {
if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
- && ps.pkg.preferredActivityFilters != null) {
- ArrayList<PackageParser.ActivityIntentInfo> intents
- = ps.pkg.preferredActivityFilters;
+ && ps.pkg.getPreferredActivityFilters() != null) {
+ List<ComponentParseUtils.ParsedActivityIntentInfo> intents
+ = ps.pkg.getPreferredActivityFilters();
for (int i=0; i<intents.size(); i++) {
- PackageParser.ActivityIntentInfo aii = intents.get(i);
+ ComponentParseUtils.ParsedActivityIntentInfo aii = intents.get(i);
applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName(
- ps.name, aii.activity.className), userId);
+ ps.name, aii.getClassName()), userId);
}
}
}
@@ -3527,7 +3495,7 @@ public final class Settings {
PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
- parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null);
+ 0 /*sharedUserId*/, null, null);
String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
@@ -3576,12 +3544,6 @@ public final class Settings {
if (parser.getName().equals(TAG_PERMISSIONS)) {
readInstallPermissionsLPr(parser, ps.getPermissionsState());
- } else if (parser.getName().equals(TAG_CHILD_PACKAGE)) {
- String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
- if (ps.childPackageNames == null) {
- ps.childPackageNames = new ArrayList<>();
- }
- ps.childPackageNames.add(childPackageName);
} else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
readUsesStaticLibLPw(parser, ps);
} else {
@@ -3628,7 +3590,6 @@ public final class Settings {
PackageSetting packageSetting = null;
String version = null;
long versionCode = 0;
- String parentPackageName;
try {
name = parser.getAttributeValue(null, ATTR_NAME);
realName = parser.getAttributeValue(null, "realName");
@@ -3640,8 +3601,6 @@ public final class Settings {
legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
- parentPackageName = parser.getAttributeValue(null, "parentPackageName");
-
legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi");
secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi");
@@ -3770,7 +3729,7 @@ public final class Settings {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
- pkgPrivateFlags, parentPackageName, null /*childPackageNames*/,
+ pkgPrivateFlags,
null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
@@ -3789,8 +3748,8 @@ public final class Settings {
packageSetting = new PackageSetting(name.intern(), realName, new File(
codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- versionCode, pkgFlags, pkgPrivateFlags, parentPackageName,
- null /*childPackageNames*/, sharedUserId,
+ versionCode, pkgFlags, pkgPrivateFlags,
+ sharedUserId,
null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
packageSetting.setTimeStamp(timeStamp);
packageSetting.firstInstallTime = firstInstallTime;
@@ -3899,12 +3858,6 @@ public final class Settings {
packageSetting.keySetData.addDefinedKeySet(id, alias);
} else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
readDomainVerificationLPw(parser, packageSetting);
- } else if (tagName.equals(TAG_CHILD_PACKAGE)) {
- String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
- if (packageSetting.childPackageNames == null) {
- packageSetting.childPackageNames = new ArrayList<>();
- }
- packageSetting.childPackageNames.add(childPackageName);
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element under <package>: " + parser.getName());
@@ -4057,13 +4010,13 @@ public final class Settings {
Iterator<PackageSetting> packagesIterator = packages.iterator();
for (int i = 0; i < packagesCount; i++) {
PackageSetting ps = packagesIterator.next();
- if (ps.pkg == null || ps.pkg.applicationInfo == null) {
+ if (ps.pkg == null) {
continue;
}
final boolean shouldInstall = ps.isSystem() &&
(skipPackageWhitelist || installablePackages.contains(ps.name)) &&
!ArrayUtils.contains(disallowedPackages, ps.name) &&
- !ps.pkg.applicationInfo.hiddenUntilInstalled;
+ !ps.pkg.isHiddenUntilInstalled();
// Only system apps are initially installed.
ps.setInstalled(shouldInstall, userHandle);
if (!shouldInstall) {
@@ -4074,8 +4027,8 @@ public final class Settings {
volumeUuids[i] = ps.volumeUuid;
names[i] = ps.name;
appIds[i] = ps.appId;
- seinfos[i] = ps.pkg.applicationInfo.seInfo;
- targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion;
+ seinfos[i] = ps.pkg.getSeInfo();
+ targetSdkVersions[i] = ps.pkg.getTargetSdkVersion();
}
}
t.traceBegin("createAppData");
@@ -4185,28 +4138,6 @@ public final class Settings {
return mVerifierDeviceIdentity;
}
- boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName,
- String childPackageName) {
- final int packageCount = mDisabledSysPackages.size();
- for (int i = 0; i < packageCount; i++) {
- PackageSetting disabledPs = mDisabledSysPackages.valueAt(i);
- if (disabledPs.childPackageNames == null || disabledPs.childPackageNames.isEmpty()) {
- continue;
- }
- if (disabledPs.name.equals(parentPackageName)) {
- continue;
- }
- final int childCount = disabledPs.childPackageNames.size();
- for (int j = 0; j < childCount; j++) {
- String currChildPackageName = disabledPs.childPackageNames.get(j);
- if (currChildPackageName.equals(childPackageName)) {
- return true;
- }
- }
- }
- return false;
- }
-
/**
* Returns the disabled {@link PackageSetting} for the provided package name if one exists,
* {@code null} otherwise.
@@ -4229,26 +4160,6 @@ public final class Settings {
return getDisabledSystemPkgLPr(enabledPackageSetting.name);
}
- /**
- * Fetches an array of the child {@link PackageSetting}s for all child package names referenced
- * by the provided parent {@link PackageSetting} or {@code null} if no children are referenced.
- *
- * Note: Any child packages not found will be null in the returned array.
- */
- @Nullable
- public PackageSetting[] getChildSettingsLPr(PackageSetting parentPackageSetting) {
- if (parentPackageSetting == null || !parentPackageSetting.hasChildPackages()) {
- return null;
- }
- final int childCount = parentPackageSetting.childPackageNames.size();
- PackageSetting[] children =
- new PackageSetting[childCount];
- for (int i = 0; i < childCount; i++) {
- children[i] = mPackages.get(parentPackageSetting.childPackageNames.get(i));
- }
- return children;
- }
-
boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
final PackageSetting ps = mPackages.get(componentInfo.packageName);
if (ps == null) return false;
@@ -4257,6 +4168,15 @@ public final class Settings {
return userState.isMatch(componentInfo, flags);
}
+ boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedComponent component, int flags,
+ int userId) {
+ final PackageSetting ps = mPackages.get(component.getPackageName());
+ if (ps == null) return false;
+
+ final PackageUserState userState = ps.readUserState(userId);
+ return userState.isMatch(pkg.isSystem(), pkg.isEnabled(), component, flags);
+ }
+
boolean isOrphaned(String packageName) {
final PackageSetting pkg = mPackages.get(packageName);
if (pkg == null) {
@@ -4467,6 +4387,7 @@ public final class Settings {
void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
Date date, List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
+ AndroidPackage pkg = ps.pkg;
if (checkinTag != null) {
pw.print(checkinTag);
pw.print(",");
@@ -4483,15 +4404,16 @@ public final class Settings {
pw.print(ps.installSource.installerPackageName != null
? ps.installSource.installerPackageName : "?");
pw.println();
- if (ps.pkg != null) {
+ if (pkg != null) {
pw.print(checkinTag); pw.print("-"); pw.print("splt,");
pw.print("base,");
- pw.println(ps.pkg.baseRevisionCode);
- if (ps.pkg.splitNames != null) {
- for (int i = 0; i < ps.pkg.splitNames.length; i++) {
+ pw.println(pkg.getBaseRevisionCode());
+ if (pkg.getSplitNames() != null) {
+ int[] splitRevisionCodes = pkg.getSplitRevisionCodes();
+ for (int i = 0; i < pkg.getSplitNames().length; i++) {
pw.print(checkinTag); pw.print("-"); pw.print("splt,");
- pw.print(ps.pkg.splitNames[i]); pw.print(",");
- pw.println(ps.pkg.splitRevisionCodes[i]);
+ pw.print(pkg.getSplitNames()[i]); pw.print(",");
+ pw.println(splitRevisionCodes[i]);
}
}
}
@@ -4538,7 +4460,7 @@ public final class Settings {
if (ps.sharedUser != null) {
pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser);
}
- pw.print(prefix); pw.print(" pkg="); pw.println(ps.pkg);
+ pw.print(prefix); pw.print(" pkg="); pw.println(pkg);
pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString);
if (permissionNames == null) {
pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
@@ -4548,140 +4470,123 @@ public final class Settings {
pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
}
pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
- if (ps.pkg != null) {
- pw.print(" minSdk="); pw.print(ps.pkg.applicationInfo.minSdkVersion);
- pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
+ if (pkg != null) {
+ pw.print(" minSdk="); pw.print(pkg.getMinSdkVersion());
+ pw.print(" targetSdk="); pw.print(pkg.getTargetSdkVersion());
}
pw.println();
- if (ps.pkg != null) {
- if (ps.pkg.parentPackage != null) {
- PackageParser.Package parentPkg = ps.pkg.parentPackage;
- PackageSetting pps = mPackages.get(parentPkg.packageName);
- if (pps == null || !pps.codePathString.equals(parentPkg.codePath)) {
- pps = mDisabledSysPackages.get(parentPkg.packageName);
- }
- if (pps != null) {
- pw.print(prefix); pw.print(" parentPackage=");
- pw.println(pps.realName != null ? pps.realName : pps.name);
- }
- } else if (ps.pkg.childPackages != null) {
- pw.print(prefix); pw.print(" childPackages=[");
- final int childCount = ps.pkg.childPackages.size();
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = ps.pkg.childPackages.get(i);
- PackageSetting cps = mPackages.get(childPkg.packageName);
- if (cps == null || !cps.codePathString.equals(childPkg.codePath)) {
- cps = mDisabledSysPackages.get(childPkg.packageName);
- }
- if (cps != null) {
- if (i > 0) {
- pw.print(", ");
- }
- pw.print(cps.realName != null ? cps.realName : cps.name);
- }
- }
- pw.println("]");
- }
- pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
- pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, ps.pkg); pw.println();
- final int apkSigningVersion = ps.pkg.mSigningDetails.signatureSchemeVersion;
+ if (pkg != null) {
+ pw.print(prefix); pw.print(" versionName="); pw.println(pkg.getVersionName());
+ pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, pkg); pw.println();
+ final int apkSigningVersion = pkg.getSigningDetails().signatureSchemeVersion;
pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
+ // TODO(b/135203078): Is there anything to print here with AppInfo removed?
pw.print(prefix); pw.print(" applicationInfo=");
- pw.println(ps.pkg.applicationInfo.toString());
- pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
+ pw.println(pkg.toAppInfoWithoutState().toString());
+ pw.print(prefix); pw.print(" flags="); printFlags(pw, pkg.getFlags(),
FLAG_DUMP_SPEC); pw.println();
- if (ps.pkg.applicationInfo.privateFlags != 0) {
+ if (pkg.getPrivateFlags() != 0) {
pw.print(prefix); pw.print(" privateFlags="); printFlags(pw,
- ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
+ pkg.getPrivateFlags(), PRIVATE_FLAG_DUMP_SPEC); pw.println();
}
- pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.mForceQueryable);
- if (ps.pkg.mQueriesPackages != null) {
- pw.append(prefix).append(" queriesPackages=").println(ps.pkg.mQueriesPackages);
+ pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.isForceQueryable());
+ if (ps.pkg.getQueriesPackages() != null) {
+ pw.append(prefix).append(" queriesPackages=").println(ps.pkg.getQueriesPackages());
}
- if (ps.pkg.mQueriesIntents != null) {
- pw.append(prefix).append(" queriesIntents=").println(ps.pkg.mQueriesIntents);
+ if (ps.pkg.getQueriesIntents() != null) {
+ pw.append(prefix).append(" queriesIntents=").println(ps.pkg.getQueriesIntents());
}
- pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
+ pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.getDataDir());
pw.print(prefix); pw.print(" supportsScreens=[");
boolean first = true;
- if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
if (!first)
pw.print(", ");
first = false;
pw.print("small");
}
- if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
if (!first)
pw.print(", ");
first = false;
pw.print("medium");
}
- if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
if (!first)
pw.print(", ");
first = false;
pw.print("large");
}
- if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
if (!first)
pw.print(", ");
first = false;
pw.print("xlarge");
}
- if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
if (!first)
pw.print(", ");
first = false;
pw.print("resizeable");
}
- if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
if (!first)
pw.print(", ");
first = false;
pw.print("anyDensity");
}
pw.println("]");
- if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) {
+ List<String> libraryNames = pkg.getLibraryNames();
+ if (libraryNames != null && libraryNames.size() > 0) {
pw.print(prefix); pw.println(" dynamic libraries:");
- for (int i = 0; i<ps.pkg.libraryNames.size(); i++) {
+ for (int i = 0; i< libraryNames.size(); i++) {
pw.print(prefix); pw.print(" ");
- pw.println(ps.pkg.libraryNames.get(i));
+ pw.println(libraryNames.get(i));
}
}
- if (ps.pkg.staticSharedLibName != null) {
+ if (pkg.getStaticSharedLibName() != null) {
pw.print(prefix); pw.println(" static library:");
pw.print(prefix); pw.print(" ");
- pw.print("name:"); pw.print(ps.pkg.staticSharedLibName);
- pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion);
+ pw.print("name:"); pw.print(pkg.getStaticSharedLibName());
+ pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion());
}
- if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) {
+
+ List<String> usesLibraries = pkg.getUsesLibraries();
+ if (usesLibraries != null && usesLibraries.size() > 0) {
pw.print(prefix); pw.println(" usesLibraries:");
- for (int i=0; i<ps.pkg.usesLibraries.size(); i++) {
- pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraries.get(i));
+ for (int i=0; i< usesLibraries.size(); i++) {
+ pw.print(prefix); pw.print(" "); pw.println(usesLibraries.get(i));
}
}
- if (ps.pkg.usesStaticLibraries != null
- && ps.pkg.usesStaticLibraries.size() > 0) {
+
+ List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
+ long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions();
+ if (usesStaticLibraries != null
+ && usesStaticLibraries.size() > 0) {
pw.print(prefix); pw.println(" usesStaticLibraries:");
- for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) {
+ for (int i=0; i< usesStaticLibraries.size(); i++) {
pw.print(prefix); pw.print(" ");
- pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:");
- pw.println(ps.pkg.usesStaticLibrariesVersions[i]);
+ pw.print(usesStaticLibraries.get(i)); pw.print(" version:");
+ pw.println(usesStaticLibrariesVersions[i]);
}
}
- if (ps.pkg.usesOptionalLibraries != null
- && ps.pkg.usesOptionalLibraries.size() > 0) {
+
+ List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries();
+ if (usesOptionalLibraries != null
+ && usesOptionalLibraries.size() > 0) {
pw.print(prefix); pw.println(" usesOptionalLibraries:");
- for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) {
+ for (int i=0; i< usesOptionalLibraries.size(); i++) {
pw.print(prefix); pw.print(" ");
- pw.println(ps.pkg.usesOptionalLibraries.get(i));
+ pw.println(usesOptionalLibraries.get(i));
}
}
- if (ps.pkg.usesLibraryFiles != null
- && ps.pkg.usesLibraryFiles.length > 0) {
+
+ String[] usesLibraryFiles = pkg.getUsesLibraryFiles();
+ if (usesLibraryFiles != null
+ && usesLibraryFiles.length > 0) {
pw.print(prefix); pw.println(" usesLibraryFiles:");
- for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) {
- pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraryFiles[i]);
+ for (int i=0; i< usesLibraryFiles.length; i++) {
+ pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]);
}
}
}
@@ -4709,40 +4614,40 @@ public final class Settings {
pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
pw.println();
- if (ps.pkg != null && ps.pkg.mOverlayTarget != null) {
- pw.print(prefix); pw.print(" overlayTarget="); pw.println(ps.pkg.mOverlayTarget);
- pw.print(prefix); pw.print(" overlayCategory="); pw.println(ps.pkg.mOverlayCategory);
+ if (pkg != null && pkg.getOverlayTarget() != null) {
+ pw.print(prefix); pw.print(" overlayTarget="); pw.println(pkg.getOverlayTarget());
+ pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory());
}
- if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) {
- final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions;
+ if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) {
+ final List<ParsedPermission> perms = pkg.getPermissions();
pw.print(prefix); pw.println(" declared permissions:");
for (int i=0; i<perms.size(); i++) {
- PackageParser.Permission perm = perms.get(i);
+ ParsedPermission perm = perms.get(i);
if (permissionNames != null
- && !permissionNames.contains(perm.info.name)) {
+ && !permissionNames.contains(perm.getName())) {
continue;
}
- pw.print(prefix); pw.print(" "); pw.print(perm.info.name);
+ pw.print(prefix); pw.print(" "); pw.print(perm.getName());
pw.print(": prot=");
- pw.print(PermissionInfo.protectionToString(perm.info.protectionLevel));
- if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
+ pw.print(PermissionInfo.protectionToString(perm.protectionLevel));
+ if ((perm.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
pw.print(", COSTS_MONEY");
}
- if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) {
+ if ((perm.flags&PermissionInfo.FLAG_REMOVED) != 0) {
pw.print(", HIDDEN");
}
- if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
+ if ((perm.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
pw.print(", INSTALLED");
}
pw.println();
}
}
- if ((permissionNames != null || dumpAll) && ps.pkg != null
- && ps.pkg.requestedPermissions != null
- && ps.pkg.requestedPermissions.size() > 0) {
- final ArrayList<String> perms = ps.pkg.requestedPermissions;
+ if ((permissionNames != null || dumpAll) && pkg != null
+ && pkg.getRequestedPermissions() != null
+ && pkg.getRequestedPermissions().size() > 0) {
+ final List<String> perms = pkg.getRequestedPermissions();
pw.print(prefix); pw.println(" requested permissions:");
for (int i=0; i<perms.size(); i++) {
String perm = perms.get(i);
@@ -5019,22 +4924,24 @@ public final class Settings {
pw.print(mReadMessages.toString());
}
- private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
+ private static void dumpSplitNames(PrintWriter pw, AndroidPackage pkg) {
if (pkg == null) {
pw.print("unknown");
} else {
// [base:10, config.mdpi, config.xhdpi:12]
pw.print("[");
pw.print("base");
- if (pkg.baseRevisionCode != 0) {
- pw.print(":"); pw.print(pkg.baseRevisionCode);
+ if (pkg.getBaseRevisionCode() != 0) {
+ pw.print(":"); pw.print(pkg.getBaseRevisionCode());
}
- if (pkg.splitNames != null) {
- for (int i = 0; i < pkg.splitNames.length; i++) {
+ String[] splitNames = pkg.getSplitNames();
+ int[] splitRevisionCodes = pkg.getSplitRevisionCodes();
+ if (splitNames != null) {
+ for (int i = 0; i < splitNames.length; i++) {
pw.print(", ");
- pw.print(pkg.splitNames[i]);
- if (pkg.splitRevisionCodes[i] != 0) {
- pw.print(":"); pw.print(pkg.splitRevisionCodes[i]);
+ pw.print(splitNames[i]);
+ if (splitRevisionCodes[i] != 0) {
+ pw.print(":"); pw.print(splitRevisionCodes[i]);
}
}
}
@@ -5110,22 +5017,23 @@ public final class Settings {
}
void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps) {
- dumpComponents(pw, prefix, ps, "activities:", ps.pkg.activities);
- dumpComponents(pw, prefix, ps, "services:", ps.pkg.services);
- dumpComponents(pw, prefix, ps, "receivers:", ps.pkg.receivers);
- dumpComponents(pw, prefix, ps, "providers:", ps.pkg.providers);
- dumpComponents(pw, prefix, ps, "instrumentations:", ps.pkg.instrumentation);
+ // TODO(b/135203078): ParsedComponent toString methods for dumping
+ dumpComponents(pw, prefix, "activities:", ps.pkg.getActivities());
+ dumpComponents(pw, prefix, "services:", ps.pkg.getServices());
+ dumpComponents(pw, prefix, "receivers:", ps.pkg.getReceivers());
+ dumpComponents(pw, prefix, "providers:", ps.pkg.getProviders());
+ dumpComponents(pw, prefix, "instrumentations:", ps.pkg.getInstrumentations());
}
- void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps,
- String label, List<? extends PackageParser.Component<?>> list) {
+ void dumpComponents(PrintWriter pw, String prefix, String label,
+ List<? extends ParsedComponent> list) {
final int size = CollectionUtils.size(list);
if (size == 0) {
return;
}
pw.print(prefix);pw.println(label);
for (int i = 0; i < size; i++) {
- final PackageParser.Component<?> component = list.get(i);
+ final ParsedComponent component = list.get(i);
pw.print(prefix);pw.print(" ");
pw.println(component.getComponentName().flattenToShortString());
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 648051817295..0a42ccf1c5ba 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -18,7 +18,7 @@ package com.android.server.pm;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
import android.service.pm.PackageServiceDumpProto;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
@@ -46,7 +46,7 @@ public final class SharedUserSetting extends SettingBase {
// that all apps within the sharedUser run in the same selinux context.
int seInfoTargetSdkVersion;
- final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
+ final ArraySet<PackageSetting> packages = new ArraySet<>();
final PackageSignatures signatures = new PackageSignatures();
Boolean signaturesChanged;
@@ -98,7 +98,7 @@ public final class SharedUserSetting extends SettingBase {
// If this is the first package added to this shared user, temporarily (until next boot) use
// its targetSdkVersion when assigning seInfo for the shared user.
if ((packages.size() == 0) && (packageSetting.pkg != null)) {
- seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
+ seInfoTargetSdkVersion = packageSetting.pkg.getTargetSdkVersion();
}
if (packages.add(packageSetting)) {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
@@ -106,11 +106,11 @@ public final class SharedUserSetting extends SettingBase {
}
}
- public @Nullable List<PackageParser.Package> getPackages() {
+ public @Nullable List<AndroidPackage> getPackages() {
if (packages == null || packages.size() == 0) {
return null;
}
- final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
+ final ArrayList<AndroidPackage> pkgList = new ArrayList<>(packages.size());
for (PackageSetting ps : packages) {
if ((ps == null) || (ps.pkg == null)) {
continue;
@@ -131,20 +131,20 @@ public final class SharedUserSetting extends SettingBase {
* restrictive selinux domain.
*/
public void fixSeInfoLocked() {
- final List<PackageParser.Package> pkgList = getPackages();
+ final List<AndroidPackage> pkgList = getPackages();
if (pkgList == null || pkgList.size() == 0) {
return;
}
- for (PackageParser.Package pkg : pkgList) {
- if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
- seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ for (AndroidPackage pkg : pkgList) {
+ if (pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) {
+ seInfoTargetSdkVersion = pkg.getTargetSdkVersion();
}
}
- for (PackageParser.Package pkg : pkgList) {
+ for (AndroidPackage pkg : pkgList) {
final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
- pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
- seInfoTargetSdkVersion);
+ pkg.mutate().setSeInfo(SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+ seInfoTargetSdkVersion));
}
}
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 0a6a43543860..c36b9938a8cd 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
import android.content.res.Resources;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -191,15 +192,15 @@ class UserSystemPackageInstaller {
return;
}
final boolean install =
- (userWhitelist == null || userWhitelist.contains(pkg.packageName))
- && !pkg.applicationInfo.hiddenUntilInstalled;
+ (userWhitelist == null || userWhitelist.contains(pkg.getPackageName()))
+ && !pkg.isHiddenUntilInstalled();
if (isConsideredUpgrade && !isFirstBoot && !install) {
return; // To be careful, we don’t uninstall apps during OTAs
}
final boolean changed = pmInt.setInstalled(pkg, userId, install);
if (changed) {
Slog.i(TAG, (install ? "Installed " : "Uninstalled ")
- + pkg.packageName + " for user " + userId);
+ + pkg.getPackageName() + " for user " + userId);
}
});
}
@@ -220,7 +221,7 @@ class UserSystemPackageInstaller {
// Check whether all whitelisted packages are indeed on the system.
for (String pkgName : allWhitelistedPackages) {
- PackageParser.Package pkg = pmInt.getPackage(pkgName);
+ AndroidPackage pkg = pmInt.getPackage(pkgName);
if (pkg == null) {
Slog.w(TAG, pkgName + " is whitelisted but not present.");
} else if (!pkg.isSystem()) {
@@ -234,8 +235,8 @@ class UserSystemPackageInstaller {
}
final boolean doWtf = isEnforceMode(mode);
pmInt.forEachPackage(pkg -> {
- if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.manifestPackageName)) {
- final String msg = "System package " + pkg.manifestPackageName
+ if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.getManifestPackageName())) {
+ final String msg = "System package " + pkg.getManifestPackageName()
+ " is not whitelisted using 'install-in-user-type' in SystemConfig "
+ "for any user types!";
if (doWtf) {
@@ -344,7 +345,7 @@ class UserSystemPackageInstaller {
if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes,
whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) {
// Although the whitelist uses manifest names, this function returns packageNames.
- installPackages.add(pkg.packageName);
+ installPackages.add(pkg.getPackageName());
}
});
return installPackages;
@@ -366,12 +367,12 @@ class UserSystemPackageInstaller {
* @param isSystemUser whether the user is USER_SYSTEM (which gets special treatment).
*/
@VisibleForTesting
- static boolean shouldInstallPackage(PackageParser.Package sysPkg,
+ static boolean shouldInstallPackage(AndroidPackage sysPkg,
@NonNull ArrayMap<String, Long> userTypeWhitelist,
@NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode,
boolean isSystemUser) {
- final String pkgName = sysPkg.manifestPackageName;
+ final String pkgName = sysPkg.getManifestPackageName();
boolean install = (isImplicitWhitelistMode && !userTypeWhitelist.containsKey(pkgName))
|| userWhitelist.contains(pkgName);
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index cc5aec2e113e..486cfeff0739 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -25,13 +25,13 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.ArtManager.ProfileType;
import android.content.pm.dex.ArtManagerInternal;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.dex.PackageOptimizationInfo;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -390,9 +390,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
* - create the current primary profile to save time at app startup time.
* - copy the profiles from the associated dex metadata file to the reference profile.
*/
- public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user,
+ public void prepareAppProfiles(
+ AndroidPackage pkg, @UserIdInt int user,
boolean updateReferenceProfileContent) {
- final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+ final int appId = UserHandle.getAppId(pkg.getUid());
if (user < 0) {
Slog.wtf(TAG, "Invalid user id: " + user);
return;
@@ -415,23 +416,24 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
}
synchronized (mInstaller) {
- boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
+ boolean result = mInstaller.prepareAppProfile(pkg.getPackageName(), user, appId,
profileName, codePath, dexMetadataPath);
if (!result) {
Slog.e(TAG, "Failed to prepare profile for " +
- pkg.packageName + ":" + codePath);
+ pkg.getPackageName() + ":" + codePath);
}
}
}
} catch (InstallerException e) {
- Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e);
+ Slog.e(TAG, "Failed to prepare profile for " + pkg.getPackageName(), e);
}
}
/**
* Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
*/
- public void prepareAppProfiles(PackageParser.Package pkg, int[] user,
+ public void prepareAppProfiles(
+ AndroidPackage pkg, int[] user,
boolean updateReferenceProfileContent) {
for (int i = 0; i < user.length; i++) {
prepareAppProfiles(pkg, user[i], updateReferenceProfileContent);
@@ -441,12 +443,12 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
/**
* Clear the profiles for the given package.
*/
- public void clearAppProfiles(PackageParser.Package pkg) {
+ public void clearAppProfiles(AndroidPackage pkg) {
try {
ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
String profileName = packageProfileNames.valueAt(i);
- mInstaller.clearAppProfiles(pkg.packageName, profileName);
+ mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
}
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
@@ -456,15 +458,15 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
/**
* Dumps the profiles for the given package.
*/
- public void dumpProfiles(PackageParser.Package pkg) {
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ public void dumpProfiles(AndroidPackage pkg) {
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
try {
ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
String codePath = packageProfileNames.keyAt(i);
String profileName = packageProfileNames.valueAt(i);
synchronized (mInstallLock) {
- mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
+ mInstaller.dumpProfiles(sharedGid, pkg.getPackageName(), profileName, codePath);
}
}
} catch (InstallerException e) {
@@ -475,14 +477,13 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
/**
* Compile layout resources in a given package.
*/
- public boolean compileLayouts(PackageParser.Package pkg) {
+ public boolean compileLayouts(AndroidPackage pkg) {
try {
- final String packageName = pkg.packageName;
- final String apkPath = pkg.baseCodePath;
- final ApplicationInfo appInfo = pkg.applicationInfo;
- final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
- if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed()
- || appInfo.isDefaultToDeviceProtectedStorage()) {
+ final String packageName = pkg.getPackageName();
+ final String apkPath = pkg.getBaseCodePath();
+ final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
+ if (pkg.isPrivileged() || pkg.isEmbeddedDexUsed()
+ || pkg.isDefaultToDeviceProtectedStorage()) {
// Privileged apps prefer to load trusted code so they don't use compiled views.
// If the app is not privileged but prefers code integrity, also avoid compiling
// views.
@@ -496,7 +497,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
try {
synchronized (mInstallLock) {
return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
- appInfo.uid);
+ pkg.getUid());
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -512,15 +513,19 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
* Build the profiles names for all the package code paths (excluding resource only paths).
* Return the map [code path -> profile name].
*/
- private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) {
+ private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
ArrayMap<String, String> result = new ArrayMap<>();
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
- result.put(pkg.baseCodePath, ArtManager.getProfileName(null));
+ if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null));
}
- if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
- for (int i = 0; i < pkg.splitCodePaths.length; i++) {
- if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
- result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i]));
+
+ String[] splitCodePaths = pkg.getSplitCodePaths();
+ int[] splitFlags = pkg.getSplitFlags();
+ String[] splitNames = pkg.getSplitNames();
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ for (int i = 0; i < splitCodePaths.length; i++) {
+ if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ result.put(splitCodePaths[i], ArtManager.getProfileName(splitNames[i]));
}
}
}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 41dcaa59047b..29183bb78f07 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -588,7 +588,7 @@ public class DexManager {
// We found the package. Now record the usage for all declared ISAs.
boolean update = false;
- for (String isa : getAppDexInstructionSets(info)) {
+ for (String isa : getAppDexInstructionSets(info.primaryCpuAbi, info.secondaryCpuAbi)) {
boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName,
dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false,
searchResult.mOwningPackageName,
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 5a473c1819c1..6e6b137d23a2 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -18,10 +18,12 @@ package com.android.server.pm.dex;
import android.content.pm.ApplicationInfo;
import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.AndroidPackage;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.util.ArrayUtils;
import java.io.File;
import java.util.List;
@@ -66,7 +68,7 @@ public final class DexoptUtils {
* {@link android.app.LoadedApk#makePaths(
* android.app.ActivityThread, boolean, ApplicationInfo, List, List)}.
*/
- public static String[] getClassLoaderContexts(ApplicationInfo info,
+ public static String[] getClassLoaderContexts(AndroidPackage pkg,
List<SharedLibraryInfo> sharedLibraries, boolean[] pathsWithCode) {
// The base class loader context contains only the shared library.
String sharedLibrariesContext = "";
@@ -75,8 +77,8 @@ public final class DexoptUtils {
}
String baseApkContextClassLoader = encodeClassLoader(
- "", info.classLoaderName, sharedLibrariesContext);
- if (info.getSplitCodePaths() == null) {
+ "", pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
+ if (pkg.getSplitCodePaths() == null) {
// The application has no splits.
return new String[] {baseApkContextClassLoader};
}
@@ -84,11 +86,11 @@ public final class DexoptUtils {
// The application has splits. Compute their class loader contexts.
// First, cache the relative paths of the splits and do some sanity checks
- String[] splitRelativeCodePaths = getSplitRelativeCodePaths(info);
+ String[] splitRelativeCodePaths = getSplitRelativeCodePaths(pkg);
// The splits have an implicit dependency on the base apk.
// This means that we have to add the base apk file in addition to the shared libraries.
- String baseApkName = new File(info.getBaseCodePath()).getName();
+ String baseApkName = new File(pkg.getBaseCodePath()).getName();
String baseClassPath = baseApkName;
// The result is stored in classLoaderContexts.
@@ -97,7 +99,11 @@ public final class DexoptUtils {
String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length];
classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null;
- if (!info.requestsIsolatedSplitLoading() || info.splitDependencies == null) {
+ SparseArray<int[]> splitDependencies = pkg.getSplitDependencies();
+
+ if (!pkg.requestsIsolatedSplitLoading()
+ || splitDependencies == null
+ || splitDependencies.size() == 0) {
// If the app didn't request for the splits to be loaded in isolation or if it does not
// declare inter-split dependencies, then all the splits will be loaded in the base
// apk class loader (in the order of their definition).
@@ -105,7 +111,7 @@ public final class DexoptUtils {
for (int i = 1; i < classLoaderContexts.length; i++) {
if (pathsWithCode[i]) {
classLoaderContexts[i] = encodeClassLoader(
- classpath, info.classLoaderName, sharedLibrariesContext);
+ classpath, pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
} else {
classLoaderContexts[i] = null;
}
@@ -132,11 +138,10 @@ public final class DexoptUtils {
String[] splitClassLoaderEncodingCache = new String[splitRelativeCodePaths.length];
for (int i = 0; i < splitRelativeCodePaths.length; i++) {
splitClassLoaderEncodingCache[i] = encodeClassLoader(splitRelativeCodePaths[i],
- info.splitClassLoaderNames[i]);
+ pkg.getSplitClassLoaderNames()[i]);
}
String splitDependencyOnBase = encodeClassLoader(
- baseClassPath, info.classLoaderName);
- SparseArray<int[]> splitDependencies = info.splitDependencies;
+ baseClassPath, pkg.getClassLoaderName());
// Note that not all splits have dependencies (e.g. configuration splits)
// The splits without dependencies will have classLoaderContexts[config_split_index]
@@ -154,7 +159,8 @@ public final class DexoptUtils {
// We also need to add the class loader of the current split which should
// come first in the context.
for (int i = 1; i < classLoaderContexts.length; i++) {
- String splitClassLoader = encodeClassLoader("", info.splitClassLoaderNames[i - 1]);
+ String splitClassLoader = encodeClassLoader("",
+ pkg.getSplitClassLoaderNames()[i - 1]);
if (pathsWithCode[i]) {
// If classLoaderContexts[i] is null it means that the split does not have
// any dependency. In this case its context equals its declared class loader.
@@ -394,11 +400,11 @@ public final class DexoptUtils {
* Returns the relative paths of the splits declared by the application {@code info}.
* Assumes that the application declares a non-null array of splits.
*/
- private static String[] getSplitRelativeCodePaths(ApplicationInfo info) {
- String baseCodePath = new File(info.getBaseCodePath()).getParent();
- String[] splitCodePaths = info.getSplitCodePaths();
- String[] splitRelativeCodePaths = new String[splitCodePaths.length];
- for (int i = 0; i < splitCodePaths.length; i++) {
+ private static String[] getSplitRelativeCodePaths(AndroidPackage pkg) {
+ String baseCodePath = new File(pkg.getBaseCodePath()).getParent();
+ String[] splitCodePaths = pkg.getSplitCodePaths();
+ String[] splitRelativeCodePaths = new String[ArrayUtils.size(splitCodePaths)];
+ for (int i = 0; i < splitRelativeCodePaths.length; i++) {
File pathFile = new File(splitCodePaths[i]);
splitRelativeCodePaths[i] = pathFile.getName();
// Sanity check that the base paths of the splits are all the same.
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index 8d8e17e92b3d..b7443f36e494 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -16,10 +16,10 @@
package com.android.server.pm.dex;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Binder;
import android.util.Log;
+
import com.android.internal.annotations.GuardedBy;
import com.android.server.pm.Installer;
@@ -33,19 +33,18 @@ public class ViewCompiler {
mInstaller = installer;
}
- public boolean compileLayouts(PackageParser.Package pkg) {
+ public boolean compileLayouts(AndroidPackage pkg) {
try {
- final String packageName = pkg.packageName;
- final String apkPath = pkg.baseCodePath;
- final ApplicationInfo appInfo = pkg.applicationInfo;
- final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
+ final String packageName = pkg.getPackageName();
+ final String apkPath = pkg.getBaseCodePath();
+ final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
") to " + outDexFile);
long callingId = Binder.clearCallingIdentity();
try {
synchronized (mInstallLock) {
return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
- appInfo.uid);
+ pkg.getUid());
}
} finally {
Binder.restoreCallingIdentity(callingId);
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index c39dcfefb2e8..05545cdbe50a 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -29,10 +29,12 @@ import static com.android.server.pm.Settings.TAG_ITEM;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Permission;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.PackageInfoUtils;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
@@ -89,7 +91,7 @@ public final class BasePermission {
int protectionLevel;
- PackageParser.Permission perm;
+ ParsedPermission perm;
PermissionInfo pendingPermissionInfo;
@@ -144,7 +146,7 @@ public final class BasePermission {
this.gids = gids;
this.perUser = perUser;
}
- public void setPermission(@Nullable Permission perm) {
+ public void setPermission(@Nullable ParsedPermission perm) {
this.perm = perm;
}
public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) {
@@ -165,13 +167,17 @@ public final class BasePermission {
public int calculateFootprint(BasePermission perm) {
if (uid == perm.uid) {
- return perm.name.length() + perm.perm.info.calculateFootprint();
+ return perm.name.length() + perm.perm.calculateFootprint();
}
return 0;
}
- public boolean isPermission(Permission perm) {
- return this.perm == perm;
+ public boolean isPermission(@NonNull ParsedPermission perm) {
+ if (this.perm == null) {
+ return false;
+ }
+ return Objects.equals(this.perm.getPackageName(), perm.getPackageName())
+ && Objects.equals(this.perm.className, perm.className);
}
public boolean isDynamic() {
@@ -189,29 +195,24 @@ public final class BasePermission {
}
public boolean isRemoved() {
- return perm != null && perm.info != null
- && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0;
+ return perm != null && (perm.flags & PermissionInfo.FLAG_REMOVED) != 0;
}
public boolean isSoftRestricted() {
- return perm != null && perm.info != null
- && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
+ return perm != null && (perm.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
}
public boolean isHardRestricted() {
- return perm != null && perm.info != null
- && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
+ return perm != null && (perm.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
}
public boolean isHardOrSoftRestricted() {
- return perm != null && perm.info != null
- && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
+ return perm != null && (perm.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
| PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
}
public boolean isImmutablyRestricted() {
- return perm != null && perm.info != null
- && (perm.info.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
+ return perm != null && (perm.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
}
public boolean isSignature() {
@@ -300,13 +301,12 @@ public final class BasePermission {
(this.protectionLevel != protectionLevel
|| perm == null
|| uid != tree.uid
- || !perm.owner.equals(tree.perm.owner)
- || !comparePermissionInfos(perm.info, info));
+ || !Objects.equals(perm.getPackageName(), tree.perm.getPackageName())
+ || !comparePermissionInfos(perm, info));
this.protectionLevel = protectionLevel;
info = new PermissionInfo(info);
info.protectionLevel = protectionLevel;
- perm = new PackageParser.Permission(tree.perm.owner, info);
- perm.info.packageName = tree.perm.info.packageName;
+ perm = new ParsedPermission(tree.perm);
uid = tree.uid;
return changed;
}
@@ -319,71 +319,89 @@ public final class BasePermission {
final BasePermission tree = findPermissionTree(permissionTrees, name);
if (tree != null && tree.perm != null) {
sourcePackageSetting = tree.sourcePackageSetting;
- perm = new PackageParser.Permission(tree.perm.owner,
- new PermissionInfo(pendingPermissionInfo));
- perm.info.packageName = tree.perm.info.packageName;
- perm.info.name = name;
+ perm = new ParsedPermission(tree.perm);
+ perm.protectionLevel = pendingPermissionInfo.protectionLevel;
+ perm.flags = pendingPermissionInfo.flags;
+ perm.setGroup(pendingPermissionInfo.group);
+ perm.backgroundPermission = pendingPermissionInfo.backgroundPermission;
+ perm.descriptionRes = pendingPermissionInfo.descriptionRes;
+ perm.requestRes = pendingPermissionInfo.requestRes;
+ perm.setPackageName(tree.perm.getPackageName());
+ perm.setName(name);
uid = tree.uid;
}
}
}
- static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p,
- @NonNull PackageParser.Package pkg, Collection<BasePermission> permissionTrees,
+ static BasePermission createOrUpdate(PackageManagerInternal packageManagerInternal,
+ @Nullable BasePermission bp, @NonNull ParsedPermission p,
+ @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees,
boolean chatty) {
- final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras;
+ final PackageSettingBase pkgSetting =
+ (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName());
// Allow system apps to redefine non-system permissions
- if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) {
- final boolean currentOwnerIsSystem = (bp.perm != null
- && bp.perm.owner.isSystem());
- if (p.owner.isSystem()) {
+ if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) {
+ final boolean currentOwnerIsSystem;
+ if (bp.perm == null) {
+ currentOwnerIsSystem = false;
+ } else {
+ AndroidPackage currentPackage = packageManagerInternal.getPackage(
+ bp.perm.getPackageName());
+ if (currentPackage == null) {
+ currentOwnerIsSystem = false;
+ } else {
+ currentOwnerIsSystem = currentPackage.isSystem();
+ }
+ }
+
+ if (pkg.isSystem()) {
if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
// It's a built-in permission and no owner, take ownership now
+ p.flags |= PermissionInfo.FLAG_INSTALLED;
bp.sourcePackageSetting = pkgSetting;
bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackageName = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+ bp.uid = pkg.getUid();
+ bp.sourcePackageName = p.getPackageName();
} else if (!currentOwnerIsSystem) {
- String msg = "New decl " + p.owner + " of permission "
- + p.info.name + " is system; overriding " + bp.sourcePackageName;
+ String msg = "New decl " + pkg + " of permission "
+ + p.getName() + " is system; overriding " + bp.sourcePackageName;
PackageManagerService.reportSettingsProblem(Log.WARN, msg);
bp = null;
}
}
}
if (bp == null) {
- bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL);
+ bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL);
}
StringBuilder r = null;
if (bp.perm == null) {
if (bp.sourcePackageName == null
- || bp.sourcePackageName.equals(p.info.packageName)) {
- final BasePermission tree = findPermissionTree(permissionTrees, p.info.name);
+ || bp.sourcePackageName.equals(p.getPackageName())) {
+ final BasePermission tree = findPermissionTree(permissionTrees, p.getName());
if (tree == null
- || tree.sourcePackageName.equals(p.info.packageName)) {
+ || tree.sourcePackageName.equals(p.getPackageName())) {
+ p.flags |= PermissionInfo.FLAG_INSTALLED;
bp.sourcePackageSetting = pkgSetting;
bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackageName = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+ bp.uid = pkg.getUid();
+ bp.sourcePackageName = p.getPackageName();
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
- r.append(p.info.name);
+ r.append(p.getName());
}
} else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: base tree "
+ Slog.w(TAG, "Permission " + p.getName() + " from package "
+ + p.getPackageName() + " ignored: base tree "
+ tree.name + " is from package "
+ tree.sourcePackageName);
}
} else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: original from "
+ Slog.w(TAG, "Permission " + p.getName() + " from package "
+ + p.getPackageName() + " ignored: original from "
+ bp.sourcePackageName);
}
} else if (chatty) {
@@ -393,10 +411,11 @@ public final class BasePermission {
r.append(' ');
}
r.append("DUP:");
- r.append(p.info.name);
+ r.append(p.getName());
}
- if (bp.perm == p) {
- bp.protectionLevel = p.info.protectionLevel;
+ if (bp.perm != null && Objects.equals(bp.perm.getPackageName(), p.getPackageName())
+ && Objects.equals(bp.perm.className, p.className)) {
+ bp.protectionLevel = p.protectionLevel;
}
if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
Log.d(TAG, " Permissions: " + r);
@@ -420,17 +439,17 @@ public final class BasePermission {
throw new SecurityException("No permission tree found for " + permName);
}
- public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) {
- final PackageSetting pkgSetting = (PackageSetting) pkg.mExtras;
+ public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
+ PackageSetting pkgSetting) {
final PermissionsState permsState = pkgSetting.getPermissionsState();
- int index = pkg.requestedPermissions.indexOf(name);
+ int index = pkg.getRequestedPermissions().indexOf(name);
if (!permsState.hasRequestedPermission(name) && index == -1) {
- throw new SecurityException("Package " + pkg.packageName
+ throw new SecurityException("Package " + pkg.getPackageName()
+ " has not requested permission " + name);
}
if (!isRuntime() && !isDevelopment()) {
- throw new SecurityException("Permission " + name
- + " requested by " + pkg.packageName + " is not a changeable permission type");
+ throw new SecurityException("Permission " + name + " requested by "
+ + pkg.getPackageName() + " is not a changeable permission type");
}
}
@@ -448,12 +467,12 @@ public final class BasePermission {
public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
if (groupName == null) {
- if (perm == null || perm.info.group == null) {
+ if (perm == null || perm.getGroup() == null) {
return generatePermissionInfo(protectionLevel, flags);
}
} else {
- if (perm != null && groupName.equals(perm.info.group)) {
- return PackageParser.generatePermissionInfo(perm, flags);
+ if (perm != null && groupName.equals(perm.getGroup())) {
+ return PackageInfoUtils.generatePermissionInfo(perm, flags);
}
}
return null;
@@ -463,8 +482,8 @@ public final class BasePermission {
PermissionInfo permissionInfo;
if (perm != null) {
final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
- permissionInfo = PackageParser.generatePermissionInfo(perm, flags);
- if (protectionLevelChanged && permissionInfo == perm.info) {
+ permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags);
+ if (protectionLevelChanged) {
// if we return different protection level, don't use the cached info
permissionInfo = new PermissionInfo(permissionInfo);
permissionInfo.protectionLevel = adjustedProtectionLevel;
@@ -544,14 +563,18 @@ public final class BasePermission {
serializer.attribute(null, "protection", Integer.toString(protectionLevel));
}
if (type == BasePermission.TYPE_DYNAMIC) {
- final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
- if (pi != null) {
+ if (perm != null || pendingPermissionInfo != null) {
serializer.attribute(null, "type", "dynamic");
- if (pi.icon != 0) {
- serializer.attribute(null, "icon", Integer.toString(pi.icon));
+ int icon = perm != null ? perm.icon : pendingPermissionInfo.icon;
+ CharSequence nonLocalizedLabel = perm != null
+ ? perm.nonLocalizedLabel
+ : pendingPermissionInfo.nonLocalizedLabel;
+
+ if (icon != 0) {
+ serializer.attribute(null, "icon", Integer.toString(icon));
}
- if (pi.nonLocalizedLabel != null) {
- serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+ if (nonLocalizedLabel != null) {
+ serializer.attribute(null, "label", nonLocalizedLabel.toString());
}
}
}
@@ -571,14 +594,14 @@ public final class BasePermission {
return s1.equals(s2);
}
- private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
+ private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) {
if (pi1.icon != pi2.icon) return false;
if (pi1.logo != pi2.logo) return false;
if (pi1.protectionLevel != pi2.protectionLevel) return false;
- if (!compareStrings(pi1.name, pi2.name)) return false;
+ if (!compareStrings(pi1.getName(), pi2.name)) return false;
if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
// We'll take care of setting this one.
- if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+ if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false;
// These are not currently stored in settings.
//if (!compareStrings(pi1.group, pi2.group)) return false;
//if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
@@ -614,9 +637,9 @@ public final class BasePermission {
pw.println(PermissionInfo.protectionToString(protectionLevel));
if (perm != null) {
pw.print(" perm="); pw.println(perm);
- if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
- || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
- pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.info.flags));
+ if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
+ || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+ pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.flags));
}
}
if (sourcePackageSetting != null) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 2ffba45be4a3..5adb64876ad4 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -63,10 +63,13 @@ import android.content.pm.PackageManager.PermissionInfoFlags;
import android.content.pm.PackageManager.PermissionWhitelistFlags;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.PackageInfoUtils;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.metrics.LogMaker;
import android.os.Binder;
@@ -419,7 +422,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- @Nullable BasePermission getPermission(String permName) {
+ @Nullable
+ BasePermission getPermission(String permName) {
synchronized (mLock) {
return mSettings.getPermissionLocked(permName);
}
@@ -453,10 +457,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
synchronized (mLock) {
final int n = mSettings.mPermissionGroups.size();
- final ArrayList<PermissionGroupInfo> out =
- new ArrayList<PermissionGroupInfo>(n);
- for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
- out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
+ final ArrayList<PermissionGroupInfo> out = new ArrayList<>(n);
+ for (ParsedPermissionGroup pg : mSettings.mPermissionGroups.values()) {
+ out.add(PackageInfoUtils.generatePermissionGroupInfo(pg, flags));
}
return new ParceledListSlice<>(out);
}
@@ -472,7 +475,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return null;
}
synchronized (mLock) {
- return PackageParser.generatePermissionGroupInfo(
+ return PackageInfoUtils.generatePermissionGroupInfo(
mSettings.mPermissionGroups.get(groupName), flags);
}
}
@@ -596,8 +599,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
false, // requirePermissionWhenSameUser
"getPermissionFlags");
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
- if (pkg == null || pkg.mExtras == null) {
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+ if (pkg == null) {
+ return 0;
+ }
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
+ if (ps == null) {
return 0;
}
synchronized (mLock) {
@@ -608,7 +616,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return 0;
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
PermissionsState permissionsState = ps.getPermissionsState();
return permissionsState.getPermissionFlags(permName, userId);
}
@@ -695,8 +702,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
}
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
- if (pkg == null || pkg.mExtras == null) {
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ packageName);
+ if (pkg == null || ps == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -712,7 +721,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
final PermissionsState permissionsState = ps.getPermissionsState();
final boolean hadState =
permissionsState.getRuntimePermissionState(permName, userId) != null;
@@ -725,11 +733,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Install and runtime permissions are stored in different places,
// so figure out what permission changed and persist the change.
if (permissionsState.getInstallPermissionState(permName) != null) {
- callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid);
+ callback.onInstallPermissionUpdatedNotifyListener(pkg.getUid());
} else if (permissionsState.getRuntimePermissionState(permName, userId) != null
|| hadState) {
- callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
- pkg.applicationInfo.uid);
+ callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false,
+ pkg.getUid());
}
}
}
@@ -761,18 +769,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
? flagValues : flagValues & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
final boolean[] changed = new boolean[1];
- mPackageManagerInt.forEachPackage(new Consumer<PackageParser.Package>() {
- @Override
- public void accept(Package pkg) {
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
- }
- final PermissionsState permissionsState = ps.getPermissionsState();
- changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
- userId, effectiveFlagMask, effectiveFlagValues);
- mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+ mPackageManagerInt.forEachPackage(pkg -> {
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
+ if (ps == null) {
+ return;
}
+ final PermissionsState permissionsState = ps.getPermissionsState();
+ changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
+ userId, effectiveFlagMask, effectiveFlagValues);
+ mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
});
if (changed[0]) {
@@ -802,17 +808,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private int checkPermissionImpl(String permName, String pkgName, int userId) {
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(pkgName);
if (pkg == null) {
return PackageManager.PERMISSION_DENIED;
}
return checkPermissionInternal(pkg, true, permName, userId);
}
- private int checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
+ private int checkPermissionInternal(@NonNull AndroidPackage pkg, boolean isPackageExplicit,
@NonNull String permissionName, @UserIdInt int userId) {
final int callingUid = getCallingUid();
- if (isPackageExplicit || pkg.mSharedUserId == null) {
+ if (isPackageExplicit || pkg.getSharedUserId() == null) {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return PackageManager.PERMISSION_DENIED;
}
@@ -822,8 +828,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final int uid = UserHandle.getUid(userId, pkg.getUid());
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
if (ps == null) {
return PackageManager.PERMISSION_DENIED;
}
@@ -878,7 +885,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private int checkUidPermissionImpl(String permName, int uid) {
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(uid);
return checkUidPermissionInternal(pkg, uid, permName);
}
@@ -889,7 +896,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @see SystemConfig#getSystemPermissions()
*/
- private int checkUidPermissionInternal(@Nullable Package pkg, int uid,
+ private int checkUidPermissionInternal(@Nullable AndroidPackage pkg, int uid,
@NonNull String permissionName) {
if (pkg != null) {
final int userId = UserHandle.getUserId(uid);
@@ -953,7 +960,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
"getWhitelistedRestrictedPermissions for user " + userId);
}
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
if (pkg == null) {
return null;
}
@@ -986,7 +993,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long identity = Binder.clearCallingIdentity();
try {
final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(pkg);
+ PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
if (permissionsState == null) {
return null;
}
@@ -1004,9 +1011,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
ArrayList<String> whitelistedPermissions = null;
- final int permissionCount = pkg.requestedPermissions.size();
+ final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
for (int i = 0; i < permissionCount; i++) {
- final String permissionName = pkg.requestedPermissions.get(i);
+ final String permissionName = pkg.getRequestedPermissions().get(i);
final int currentFlags =
permissionsState.getPermissionFlags(permissionName, userId);
if ((currentFlags & queryFlags) != 0) {
@@ -1103,7 +1110,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
"setWhitelistedRestrictedPermissions for user " + userId);
}
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
if (pkg == null) {
return false;
}
@@ -1132,7 +1139,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
final List<String> whitelistedPermissions =
- getWhitelistedRestrictedPermissions(pkg.packageName, flags, userId);
+ getWhitelistedRestrictedPermissions(pkg.getPackageName(), flags, userId);
if (permissions == null || permissions.isEmpty()) {
if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
return true;
@@ -1206,8 +1213,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
false, // requirePermissionWhenSameUser
"grantRuntimePermission");
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
- if (pkg == null || pkg.mExtras == null) {
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ packageName);
+ if (pkg == null || ps == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -1222,21 +1231,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
// to keep the review required permission flag per user while an
// install permission's state is shared across all users.
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
&& bp.isRuntime()) {
return;
}
- final int uid = UserHandle.getUid(userId,
- UserHandle.getAppId(pkg.applicationInfo.uid));
+ final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
final PermissionsState permissionsState = ps.getPermissionsState();
final int flags = permissionsState.getPermissionFlags(permName, userId);
@@ -1259,7 +1266,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
- pkg.applicationInfo, UserHandle.of(userId), permName).mayGrantPermission()) {
+ pkg.toAppInfoWithoutState(), UserHandle.of(userId), permName)
+ .mayGrantPermission()) {
Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
+ packageName);
return;
@@ -1282,7 +1290,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
+ permName + " for package " + packageName);
}
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
return;
}
@@ -1295,7 +1303,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
if (callback != null) {
- callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId);
+ callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
}
}
break;
@@ -1368,8 +1376,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
false, // requirePermissionWhenSameUser
"revokeRuntimePermission");
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
- if (pkg == null || pkg.mExtras == null) {
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ packageName);
+ if (pkg == null || ps == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -1381,18 +1391,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
// to keep the review required permission flag per user while an
// install permission's state is shared across all users.
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
&& bp.isRuntime()) {
return;
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
final PermissionsState permissionsState = ps.getPermissionsState();
final int flags = permissionsState.getPermissionFlags(permName, userId);
@@ -1435,7 +1444,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (callback != null) {
callback.onPermissionRevoked(UserHandle.getUid(userId,
- UserHandle.getAppId(pkg.applicationInfo.uid)), userId);
+ UserHandle.getAppId(pkg.getUid())), userId);
}
if (bp.isRuntime()) {
@@ -1460,7 +1469,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
StorageManager.UUID_PRIVATE_INTERNAL, false, mDefaultPermissionCallback);
for (final int userId : UserManagerService.getInstance().getUserIds()) {
mPackageManagerInt.forEachPackage(
- (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
+ (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId));
}
}
@@ -1471,9 +1480,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param userId The device user for which to do a reset.
*/
@GuardedBy("mLock")
- private void resetRuntimePermissionsInternal(final PackageParser.Package pkg,
+ private void resetRuntimePermissionsInternal(final AndroidPackage pkg,
final int userId) {
- final String packageName = pkg.packageName;
+ final String packageName = pkg.getPackageName();
// These are flags that can change base on user actions.
final int userSettableMask = FLAG_PERMISSION_USER_SET
@@ -1485,7 +1494,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
| FLAG_PERMISSION_POLICY_FIXED;
// Delay and combine non-async permission callbacks
- final int permissionCount = pkg.requestedPermissions.size();
+ final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
final boolean[] permissionRemoved = new boolean[1];
final ArraySet<Long> revokedPermissions = new ArraySet<>();
final IntArray syncUpdatedUsers = new IntArray(permissionCount);
@@ -1552,7 +1561,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
};
for (int i = 0; i < permissionCount; i++) {
- final String permName = pkg.requestedPermissions.get(i);
+ final String permName = pkg.getRequestedPermissions().get(i);
final BasePermission bp;
synchronized (mLock) {
bp = mSettings.getPermissionLocked(permName);
@@ -1567,7 +1576,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// If shared user we just reset the state to which only this app contributed.
final String sharedUserId =
- mPackageManagerInt.getSharedUserIdForPackage(pkg.packageName);
+ mPackageManagerInt.getSharedUserIdForPackage(pkg.getPackageName());
final String[] pkgNames =
mPackageManagerInt.getPackagesForSharedUserId(sharedUserId, userId);
if (pkgNames != null && pkgNames.length > 0) {
@@ -1575,10 +1584,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int packageCount = pkgNames.length;
for (int j = 0; j < packageCount; j++) {
final String sharedPkgName = pkgNames[j];
- final PackageParser.Package sharedPkg =
+ final AndroidPackage sharedPkg =
mPackageManagerInt.getPackage(sharedPkgName);
- if (sharedPkg != null && !sharedPkg.packageName.equals(packageName)
- && sharedPkg.requestedPermissions.contains(permName)) {
+ if (sharedPkg != null && !sharedPkg.getPackageName().equals(packageName)
+ && sharedPkg.getRequestedPermissions().contains(permName)) {
used = true;
break;
}
@@ -1999,15 +2008,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return protectionLevel;
}
// Normalize package name to handle renamed packages and static libs
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
if (pkg == null) {
return protectionLevel;
}
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
return protectionLevelMasked;
}
// Apps that target O see flags for all protection levels.
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
if (ps == null) {
return protectionLevel;
}
@@ -2028,35 +2038,35 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param permissionCallback Callback for permission changed
*/
private void revokeRuntimePermissionsIfGroupChanged(
- @NonNull PackageParser.Package newPackage,
- @NonNull PackageParser.Package oldPackage,
+ @NonNull AndroidPackage newPackage,
+ @NonNull AndroidPackage oldPackage,
@NonNull ArrayList<String> allPackageNames,
@NonNull PermissionCallback permissionCallback) {
- final int numOldPackagePermissions = oldPackage.permissions.size();
+ final int numOldPackagePermissions = ArrayUtils.size(oldPackage.getPermissions());
final ArrayMap<String, String> oldPermissionNameToGroupName
= new ArrayMap<>(numOldPackagePermissions);
for (int i = 0; i < numOldPackagePermissions; i++) {
- final PackageParser.Permission permission = oldPackage.permissions.get(i);
+ final ParsedPermission permission = oldPackage.getPermissions().get(i);
- if (permission.group != null) {
- oldPermissionNameToGroupName.put(permission.info.name,
- permission.group.info.name);
+ if (permission.parsedPermissionGroup != null) {
+ oldPermissionNameToGroupName.put(permission.getName(),
+ permission.parsedPermissionGroup.getName());
}
}
final int callingUid = Binder.getCallingUid();
- final int numNewPackagePermissions = newPackage.permissions.size();
+ final int numNewPackagePermissions = ArrayUtils.size(newPackage.getPermissions());
for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
newPermissionNum++) {
- final PackageParser.Permission newPermission =
- newPackage.permissions.get(newPermissionNum);
- final int newProtection = newPermission.info.getProtection();
+ final ParsedPermission newPermission =
+ newPackage.getPermissions().get(newPermissionNum);
+ final int newProtection = newPermission.getProtection();
if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
- final String permissionName = newPermission.info.name;
- final String newPermissionGroupName =
- newPermission.group == null ? null : newPermission.group.info.name;
+ final String permissionName = newPermission.getName();
+ final String newPermissionGroupName = newPermission.parsedPermissionGroup == null
+ ? null : newPermission.parsedPermissionGroup.getName();
final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
permissionName);
@@ -2074,7 +2084,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
userId);
if (permissionState == PackageManager.PERMISSION_GRANTED) {
EventLog.writeEvent(0x534e4554, "72710897",
- newPackage.applicationInfo.uid,
+ newPackage.getUid(),
"Revoking permission " + permissionName +
" from package " + packageName +
" as the group changed from " + oldPermissionGroupName +
@@ -2095,54 +2105,56 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private void addAllPermissions(PackageParser.Package pkg, boolean chatty) {
- final int N = pkg.permissions.size();
+ private void addAllPermissions(AndroidPackage pkg, boolean chatty) {
+ final int N = ArrayUtils.size(pkg.getPermissions());
for (int i=0; i<N; i++) {
- PackageParser.Permission p = pkg.permissions.get(i);
+ ParsedPermission p = pkg.getPermissions().get(i);
// Assume by default that we did not install this permission into the system.
- p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
+ p.flags &= ~PermissionInfo.FLAG_INSTALLED;
synchronized (PermissionManagerService.this.mLock) {
// Now that permission groups have a special meaning, we ignore permission
// groups for legacy apps to prevent unexpected behavior. In particular,
// permissions for one app being granted to someone just because they happen
// to be in a group defined by another app (before this had no implications).
- if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
- p.group = mSettings.mPermissionGroups.get(p.info.group);
+ if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) {
+ p.parsedPermissionGroup = mSettings.mPermissionGroups.get(p.getGroup());
// Warn for a permission in an unknown group.
if (DEBUG_PERMISSIONS
- && p.info.group != null && p.group == null) {
- Slog.i(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " in an unknown group " + p.info.group);
+ && p.getGroup() != null && p.parsedPermissionGroup == null) {
+ Slog.i(TAG, "Permission " + p.getName() + " from package "
+ + p.getPackageName() + " in an unknown group " + p.getGroup());
}
}
if (p.tree) {
final BasePermission bp = BasePermission.createOrUpdate(
- mSettings.getPermissionTreeLocked(p.info.name), p, pkg,
+ mPackageManagerInt,
+ mSettings.getPermissionTreeLocked(p.getName()), p, pkg,
mSettings.getAllPermissionTreesLocked(), chatty);
- mSettings.putPermissionTreeLocked(p.info.name, bp);
+ mSettings.putPermissionTreeLocked(p.getName(), bp);
} else {
final BasePermission bp = BasePermission.createOrUpdate(
- mSettings.getPermissionLocked(p.info.name),
+ mPackageManagerInt,
+ mSettings.getPermissionLocked(p.getName()),
p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);
- mSettings.putPermissionLocked(p.info.name, bp);
+ mSettings.putPermissionLocked(p.getName(), bp);
}
}
}
}
- private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) {
- final int N = pkg.permissionGroups.size();
+ private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
+ final int N = ArrayUtils.size(pkg.getPermissionGroups());
StringBuilder r = null;
for (int i=0; i<N; i++) {
- final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
- final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name);
- final String curPackageName = (cur == null) ? null : cur.info.packageName;
- final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
+ final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i);
+ final ParsedPermissionGroup cur = mSettings.mPermissionGroups.get(pg.getName());
+ final String curPackageName = (cur == null) ? null : cur.getPackageName();
+ final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName);
if (cur == null || isPackageUpdate) {
- mSettings.mPermissionGroups.put(pg.info.name, pg);
+ mSettings.mPermissionGroups.put(pg.getName(), pg);
if (chatty && DEBUG_PACKAGE_SCANNING) {
if (r == null) {
r = new StringBuilder(256);
@@ -2152,12 +2164,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (isPackageUpdate) {
r.append("UPD:");
}
- r.append(pg.info.name);
+ r.append(pg.getName());
}
} else {
- Slog.w(TAG, "Permission group " + pg.info.name + " from package "
- + pg.info.packageName + " ignored: original from "
- + cur.info.packageName);
+ Slog.w(TAG, "Permission group " + pg.getName() + " from package "
+ + pg.getPackageName() + " ignored: original from "
+ + cur.getPackageName());
if (chatty && DEBUG_PACKAGE_SCANNING) {
if (r == null) {
r = new StringBuilder(256);
@@ -2165,7 +2177,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
r.append(' ');
}
r.append("DUP:");
- r.append(pg.info.name);
+ r.append(pg.getName());
}
}
}
@@ -2175,15 +2187,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
- private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
+ private void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
synchronized (mLock) {
- int N = pkg.permissions.size();
+ int N = ArrayUtils.size(pkg.getPermissions());
StringBuilder r = null;
for (int i=0; i<N; i++) {
- PackageParser.Permission p = pkg.permissions.get(i);
- BasePermission bp = (BasePermission) mSettings.mPermissions.get(p.info.name);
+ ParsedPermission p = pkg.getPermissions().get(i);
+ BasePermission bp = mSettings.mPermissions.get(p.getName());
if (bp == null) {
- bp = mSettings.mPermissionTrees.get(p.info.name);
+ bp = mSettings.mPermissionTrees.get(p.getName());
}
if (bp != null && bp.isPermission(p)) {
bp.setPermission(null);
@@ -2193,14 +2205,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
} else {
r.append(' ');
}
- r.append(p.info.name);
+ r.append(p.getName());
}
}
if (p.isAppOp()) {
ArraySet<String> appOpPkgs =
- mSettings.mAppOpPermissionPackages.get(p.info.name);
+ mSettings.mAppOpPermissionPackages.get(p.getName());
if (appOpPkgs != null) {
- appOpPkgs.remove(pkg.packageName);
+ appOpPkgs.remove(pkg.getPackageName());
}
}
}
@@ -2208,14 +2220,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
}
- N = pkg.requestedPermissions.size();
+ N = pkg.getRequestedPermissions().size();
r = null;
for (int i=0; i<N; i++) {
- String perm = pkg.requestedPermissions.get(i);
+ String perm = pkg.getRequestedPermissions().get(i);
if (mSettings.isPermissionAppOp(perm)) {
ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm);
if (appOpPkgs != null) {
- appOpPkgs.remove(pkg.packageName);
+ appOpPkgs.remove(pkg.getPackageName());
if (appOpPkgs.isEmpty()) {
mSettings.mAppOpPermissionPackages.remove(perm);
}
@@ -2244,7 +2256,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param packageOfInterest If this is the name of {@code pkg} add extra logging
* @param callback Result call back
*/
- private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
+ private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace,
@Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
// IMPORTANT: There are two types of permissions: install and runtime.
// Install time permissions are granted when the app is installed to
@@ -2257,7 +2269,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// being upgraded to target a newer SDK, in which case dangerous permissions
// are transformed from install time to runtime ones.
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
if (ps == null) {
return;
}
@@ -2298,23 +2311,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
synchronized (mLock) {
ArraySet<String> newImplicitPermissions = new ArraySet<>();
- final int N = pkg.requestedPermissions.size();
+ final int N = pkg.getRequestedPermissions().size();
for (int i = 0; i < N; i++) {
- final String permName = pkg.requestedPermissions.get(i);
+ final String permName = pkg.getRequestedPermissions().get(i);
final BasePermission bp = mSettings.getPermissionLocked(permName);
final boolean appSupportsRuntimePermissions =
- pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
+ pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
String upgradedActivityRecognitionPermission = null;
if (DEBUG_INSTALL) {
- Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp);
+ Log.i(TAG, "Package " + pkg.getPackageName()
+ + " checking " + permName + ": " + bp);
}
if (bp == null || bp.getSourcePackageSetting() == null) {
- if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
+ if (packageOfInterest == null || packageOfInterest.equals(
+ pkg.getPackageName())) {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Unknown permission " + permName
- + " in package " + pkg.packageName);
+ + " in package " + pkg.getPackageName());
}
}
continue;
@@ -2323,14 +2338,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Cache newImplicitPermissions before modifing permissionsState as for the shared
// uids the original and new state are the same object
if (!origPermissions.hasRequestedPermission(permName)
- && (pkg.implicitPermissions.contains(permName)
+ && (pkg.getImplicitPermissions().contains(permName)
|| (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
- if (pkg.implicitPermissions.contains(permName)) {
+ if (pkg.getImplicitPermissions().contains(permName)) {
// If permName is an implicit permission, try to auto-grant
newImplicitPermissions.add(permName);
if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for " + pkg.packageName);
+ Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
}
} else {
// Special case for Activity Recognition permission. Even if AR permission
@@ -2353,7 +2368,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, permName + " is newly added for "
- + pkg.packageName);
+ + pkg.getPackageName());
}
break;
}
@@ -2362,10 +2377,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// Limit ephemeral apps to ephemeral allowed permissions.
- if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
+ if (pkg.isInstantApp() && !bp.isInstant()) {
if (DEBUG_PERMISSIONS) {
Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
- + " for package " + pkg.packageName);
+ + " for package " + pkg.getPackageName());
}
continue;
}
@@ -2373,7 +2388,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
if (DEBUG_PERMISSIONS) {
Log.i(TAG, "Denying runtime-only permission " + bp.getName()
- + " for package " + pkg.packageName);
+ + " for package " + pkg.getPackageName());
}
continue;
}
@@ -2384,7 +2399,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Keep track of app op permissions.
if (bp.isAppOp()) {
- mSettings.addAppOpPackage(perm, pkg.packageName);
+ mSettings.addAppOpPackage(perm, pkg.getPackageName());
}
if (bp.isNormal()) {
@@ -2410,7 +2425,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Considering granting permission " + perm + " to package "
- + pkg.packageName);
+ + pkg.getPackageName());
}
if (grant != GRANT_DENIED) {
@@ -2696,10 +2711,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
default: {
if (packageOfInterest == null
- || packageOfInterest.equals(pkg.packageName)) {
+ || packageOfInterest.equals(pkg.getPackageName())) {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Not granting permission " + perm
- + " to package " + pkg.packageName
+ + " to package " + pkg.getPackageName()
+ " because it was previously installed without");
}
}
@@ -2714,9 +2729,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
changedInstallPermission = true;
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Un-granting permission " + perm
- + " from package " + pkg.packageName
+ + " from package " + pkg.getPackageName()
+ " (protectionLevel=" + bp.getProtectionLevel()
- + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ + " flags=0x" + Integer.toHexString(pkg.getFlags())
+ ")");
}
} else if (bp.isAppOp()) {
@@ -2724,11 +2739,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// not to be granted, there is a UI for the user to decide.
if (DEBUG_PERMISSIONS
&& (packageOfInterest == null
- || packageOfInterest.equals(pkg.packageName))) {
+ || packageOfInterest.equals(pkg.getPackageName()))) {
Slog.i(TAG, "Not granting permission " + perm
- + " to package " + pkg.packageName
+ + " to package " + pkg.getPackageName()
+ " (protectionLevel=" + bp.getProtectionLevel()
- + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ + " flags=0x" + Integer.toHexString(pkg.getFlags())
+ ")");
}
}
@@ -2758,7 +2773,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
for (int userId : updatedUserIds) {
- notifyRuntimePermissionStateChanged(pkg.packageName, userId);
+ notifyRuntimePermissionStateChanged(pkg.getPackageName(), userId);
}
}
@@ -2774,10 +2789,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @return The updated value of the {@code updatedUserIds} parameter
*/
private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
- @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
@NonNull int[] updatedUserIds) {
- String pkgName = pkg.packageName;
- boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+ String pkgName = pkg.getPackageName();
+ boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
>= Build.VERSION_CODES.M;
int[] users = UserManagerService.getInstance().getUserIds();
@@ -2786,7 +2801,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
int userId = users[i];
for (String permission : ps.getPermissions(userId)) {
- if (!pkg.implicitPermissions.contains(permission)) {
+ if (!pkg.getImplicitPermissions().contains(permission)) {
if (!ps.hasInstallPermission(permission)) {
int flags = ps.getRuntimePermissionState(permission, userId).getFlags();
@@ -2836,9 +2851,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*/
private void inheritPermissionStateToNewImplicitPermissionLocked(
@NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
- @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
@UserIdInt int userId) {
- String pkgName = pkg.packageName;
+ String pkgName = pkg.getPackageName();
boolean isGranted = false;
int flags = 0;
@@ -2885,10 +2900,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @return The ids of the users that are changed
*/
private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(
- @NonNull PackageParser.Package pkg, boolean replace, @NonNull int[] updatedUserIds) {
- if (replace && pkg.applicationInfo.hasRequestedLegacyExternalStorage() && (
- pkg.requestedPermissions.contains(READ_EXTERNAL_STORAGE)
- || pkg.requestedPermissions.contains(WRITE_EXTERNAL_STORAGE))) {
+ @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) {
+ if (replace && pkg.hasRequestedLegacyExternalStorage() && (
+ pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE)
+ || pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) {
return UserManagerService.getInstance().getUserIds();
}
@@ -2907,10 +2922,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*/
private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
@NonNull PermissionsState origPs,
- @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
@NonNull ArraySet<String> newImplicitPermissions,
@NonNull int[] updatedUserIds) {
- String pkgName = pkg.packageName;
+ String pkgName = pkg.getPackageName();
ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
final List<SplitPermissionInfoParcelable> permissionList = getSplitPermissions();
@@ -2990,17 +3005,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
SystemConfig.getInstance().getSplitPermissions());
}
- private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
+ private boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
boolean allowed = false;
final int NP = PackageParser.NEW_PERMISSIONS.length;
for (int ip=0; ip<NP; ip++) {
final PackageParser.NewPermissionInfo npi
= PackageParser.NEW_PERMISSIONS[ip];
if (npi.name.equals(perm)
- && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
+ && pkg.getTargetSdkVersion() < npi.sdkVersion) {
allowed = true;
Log.i(TAG, "Auto-granting " + perm + " to old pkg "
- + pkg.packageName);
+ + pkg.getPackageName());
break;
}
}
@@ -3014,29 +3029,26 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* <p>This handles parent/child apps.
*/
- private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) {
- ArraySet<String> wlPermissions = null;
+ private boolean hasPrivappWhitelistEntry(String perm, AndroidPackage pkg) {
+ ArraySet<String> wlPermissions;
if (pkg.isVendor()) {
wlPermissions =
- SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName);
+ SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.getPackageName());
} else if (pkg.isProduct()) {
wlPermissions =
- SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName);
+ SystemConfig.getInstance().getProductPrivAppPermissions(pkg.getPackageName());
} else if (pkg.isSystemExt()) {
wlPermissions =
SystemConfig.getInstance().getSystemExtPrivAppPermissions(
- pkg.packageName);
+ pkg.getPackageName());
} else {
- wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
+ wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.getPackageName());
}
- // Let's check if this package is whitelisted...
- boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
- // If it's not, we'll also tail-recurse to the parent.
- return whitelisted ||
- pkg.parentPackage != null && hasPrivappWhitelistEntry(perm, pkg.parentPackage);
+
+ return wlPermissions != null && wlPermissions.contains(perm);
}
- private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
+ private boolean grantSignaturePermission(String perm, AndroidPackage pkg,
BasePermission bp, PermissionsState origPermissions) {
boolean oemPermission = bp.isOEM();
boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
@@ -3044,7 +3056,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean privappPermissionsDisable =
RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
- boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
+ boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName());
if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
&& !platformPackage && platformPermission) {
if (!hasPrivappWhitelistEntry(perm, pkg)) {
@@ -3054,22 +3066,22 @@ public class PermissionManagerService extends IPermissionManager.Stub {
ArraySet<String> deniedPermissions = null;
if (pkg.isVendor()) {
deniedPermissions = SystemConfig.getInstance()
- .getVendorPrivAppDenyPermissions(pkg.packageName);
+ .getVendorPrivAppDenyPermissions(pkg.getPackageName());
} else if (pkg.isProduct()) {
deniedPermissions = SystemConfig.getInstance()
- .getProductPrivAppDenyPermissions(pkg.packageName);
+ .getProductPrivAppDenyPermissions(pkg.getPackageName());
} else if (pkg.isSystemExt()) {
deniedPermissions = SystemConfig.getInstance()
- .getSystemExtPrivAppDenyPermissions(pkg.packageName);
+ .getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
} else {
deniedPermissions = SystemConfig.getInstance()
- .getPrivAppDenyPermissions(pkg.packageName);
+ .getPrivAppDenyPermissions(pkg.getPackageName());
}
final boolean permissionViolation =
deniedPermissions == null || !deniedPermissions.contains(perm);
if (permissionViolation) {
Slog.w(TAG, "Privileged permission " + perm + " for package "
- + pkg.packageName + " (" + pkg.codePath
+ + pkg.getPackageName() + " (" + pkg.getCodePath()
+ ") not in privapp-permissions whitelist");
if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
@@ -3077,7 +3089,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
mPrivappPermissionsViolations = new ArraySet<>();
}
mPrivappPermissionsViolations.add(
- pkg.packageName + " (" + pkg.codePath + "): " + perm);
+ pkg.getPackageName() + " (" + pkg.getCodePath() + "): " + perm);
}
} else {
return false;
@@ -3091,7 +3103,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// expect single system package
String systemPackageName = ArrayUtils.firstOrNull(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM));
- final PackageParser.Package systemPackage =
+ final AndroidPackage systemPackage =
mPackageManagerInt.getPackage(systemPackageName);
// check if the package is allow to use this signature permission. A package is allowed to
@@ -3102,24 +3114,23 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// package, and the defining package still trusts the old certificate for permissions
// - or it shares the above relationships with the system package
boolean allowed =
- pkg.mSigningDetails.hasAncestorOrSelf(
+ pkg.getSigningDetails().hasAncestorOrSelf(
bp.getSourcePackageSetting().getSigningDetails())
|| bp.getSourcePackageSetting().getSigningDetails().checkCapability(
- pkg.mSigningDetails,
+ pkg.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION)
- || pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails)
- || systemPackage.mSigningDetails.checkCapability(
- pkg.mSigningDetails,
+ || pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails())
+ || systemPackage.getSigningDetails().checkCapability(
+ pkg.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION);
if (!allowed && (privilegedPermission || oemPermission)) {
if (pkg.isSystem()) {
// For updated system applications, a privileged/oem permission
// is granted only if it had been defined by the original application.
if (pkg.isUpdatedSystemApp()) {
- final PackageParser.Package disabledPkg =
- mPackageManagerInt.getDisabledSystemPackage(pkg.packageName);
- final PackageSetting disabledPs =
- (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null;
+ final PackageSetting disabledPs = (PackageSetting) mPackageManagerInt
+ .getDisabledSystemPackage(pkg.getPackageName());
+ final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
if (disabledPs != null
&& disabledPs.getPermissionsState().hasInstallPermission(perm)) {
// If the original was granted this permission, we take
@@ -3144,40 +3155,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
&& canGrantOemPermission(disabledPs, perm)))) {
allowed = true;
}
- // Also if a privileged parent package on the system image or any of
- // its children requested a privileged/oem permission, the updated child
- // packages can also get the permission.
- if (pkg.parentPackage != null) {
- final PackageParser.Package disabledParentPkg = mPackageManagerInt
- .getDisabledSystemPackage(pkg.parentPackage.packageName);
- final PackageSetting disabledParentPs = (disabledParentPkg != null)
- ? (PackageSetting) disabledParentPkg.mExtras : null;
- if (disabledParentPkg != null
- && ((privilegedPermission && disabledParentPs.isPrivileged())
- || (oemPermission && disabledParentPs.isOem()))) {
- if (isPackageRequestingPermission(disabledParentPkg, perm)
- && canGrantOemPermission(disabledParentPs, perm)) {
- allowed = true;
- } else if (disabledParentPkg.childPackages != null) {
- for (PackageParser.Package disabledChildPkg
- : disabledParentPkg.childPackages) {
- final PackageSetting disabledChildPs =
- (disabledChildPkg != null)
- ? (PackageSetting) disabledChildPkg.mExtras
- : null;
- if (isPackageRequestingPermission(disabledChildPkg, perm)
- && canGrantOemPermission(
- disabledChildPs, perm)) {
- allowed = true;
- break;
- }
- }
- }
- }
- }
}
} else {
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
allowed = (privilegedPermission && pkg.isPrivileged())
|| (oemPermission && pkg.isOem()
&& canGrantOemPermission(ps, perm));
@@ -3188,7 +3169,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (allowed && privilegedPermission &&
!vendorPrivilegedPermission && pkg.isVendor()) {
Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk "
- + pkg.packageName + " because it isn't a 'vendorPrivileged' permission.");
+ + pkg.getPackageName()
+ + " because it isn't a 'vendorPrivileged' permission.");
allowed = false;
}
}
@@ -3196,7 +3178,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed) {
if (!allowed
&& bp.isPre23()
- && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
// If this was a previously normal/dangerous permission that got moved
// to a system permission as part of the runtime permission redesign, then
// we still want to blindly grant it to old apps.
@@ -3208,9 +3190,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed && bp.isInstaller()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM),
- pkg.packageName) || ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER,
- UserHandle.USER_SYSTEM), pkg.packageName)) {
+ pkg.getPackageName()) || ArrayUtils.contains(
+ mPackageManagerInt.getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER,
+ UserHandle.USER_SYSTEM), pkg.getPackageName())) {
// If this permission is to be granted to the system installer and
// this app is an installer, then it gets the permission.
allowed = true;
@@ -3218,7 +3201,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed && bp.isVerifier()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM),
- pkg.packageName)) {
+ pkg.getPackageName())) {
// If this permission is to be granted to the system verifier and
// this app is a verifier, then it gets the permission.
allowed = true;
@@ -3236,7 +3219,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed && bp.isSetup()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM),
- pkg.packageName)) {
+ pkg.getPackageName())) {
// If this permission is to be granted to the system setup wizard and
// this app is a setup wizard, then it gets the permission.
allowed = true;
@@ -3244,28 +3227,28 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed && bp.isSystemTextClassifier()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
- UserHandle.USER_SYSTEM), pkg.packageName)) {
+ UserHandle.USER_SYSTEM), pkg.getPackageName())) {
// Special permissions for the system default text classifier.
allowed = true;
}
if (!allowed && bp.isConfigurator()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_CONFIGURATOR,
- UserHandle.USER_SYSTEM), pkg.packageName)) {
+ UserHandle.USER_SYSTEM), pkg.getPackageName())) {
// Special permissions for the device configurator.
allowed = true;
}
if (!allowed && bp.isWellbeing()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM),
- pkg.packageName)) {
+ pkg.getPackageName())) {
// Special permission granted only to the OEM specified wellbeing app
allowed = true;
}
if (!allowed && bp.isDocumenter()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM),
- pkg.packageName)) {
+ pkg.getPackageName())) {
// If this permission is to be granted to the documenter and
// this app is the documenter, then it gets the permission.
allowed = true;
@@ -3273,7 +3256,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed && bp.isIncidentReportApprover()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER,
- UserHandle.USER_SYSTEM), pkg.packageName)) {
+ UserHandle.USER_SYSTEM), pkg.getPackageName())) {
// If this permission is to be granted to the incident report approver and
// this app is the incident report approver, then it gets the permission.
allowed = true;
@@ -3281,14 +3264,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!allowed && bp.isAppPredictor()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM),
- pkg.packageName)) {
+ pkg.getPackageName())) {
// Special permissions for the system app predictor.
allowed = true;
}
if (!allowed && bp.isTelephony()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
PackageManagerInternal.PACKAGE_TELEPHONY, UserHandle.USER_SYSTEM),
- pkg.packageName)) {
+ pkg.getPackageName())) {
// Special permissions for the system telephony apps.
allowed = true;
}
@@ -3310,26 +3293,27 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return Boolean.TRUE == granted;
}
- private boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg,
+ private boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
@UserIdInt int userId) {
// Permission review applies only to apps not supporting the new permission model.
- if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
+ if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) {
return false;
}
// Legacy apps have the permission and get user consent on launch.
- if (pkg.mExtras == null) {
+ final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
+ if (ps == null) {
return false;
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
final PermissionsState permissionsState = ps.getPermissionsState();
return permissionsState.isPermissionReviewRequired(userId);
}
- private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) {
- final int permCount = pkg.requestedPermissions.size();
+ private boolean isPackageRequestingPermission(AndroidPackage pkg, String permission) {
+ final int permCount = pkg.getRequestedPermissions().size();
for (int j = 0; j < permCount; j++) {
- String requestedPermission = pkg.requestedPermissions.get(j);
+ String requestedPermission = pkg.getRequestedPermissions().get(j);
if (permission.equals(requestedPermission)) {
return true;
}
@@ -3337,41 +3321,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return false;
}
- @GuardedBy("mLock")
- private void grantRuntimePermissionsGrantedToDisabledPackageLocked(
- PackageParser.Package pkg, int callingUid, PermissionCallback callback) {
- if (pkg.parentPackage == null) {
- return;
- }
- if (pkg.requestedPermissions == null) {
- return;
- }
- final PackageParser.Package disabledPkg =
- mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName);
- if (disabledPkg == null || disabledPkg.mExtras == null) {
- return;
- }
- final PackageSetting disabledPs = (PackageSetting) disabledPkg.mExtras;
- if (!disabledPs.isPrivileged() || disabledPs.hasChildPackages()) {
- return;
- }
- final int permCount = pkg.requestedPermissions.size();
- for (int i = 0; i < permCount; i++) {
- String permission = pkg.requestedPermissions.get(i);
- BasePermission bp = mSettings.getPermissionLocked(permission);
- if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
- continue;
- }
- for (int userId : mUserManagerInt.getUserIds()) {
- if (disabledPs.getPermissionsState().hasRuntimePermission(permission, userId)) {
- grantRuntimePermissionInternal(
- permission, pkg.packageName, false, callingUid, userId, callback);
- }
- }
- }
- }
-
- private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+ private void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
for (int userId : userIds) {
grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions, callingUid,
@@ -3379,9 +3329,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
+ private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
- PackageSetting ps = (PackageSetting) pkg.mExtras;
+ PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+ pkg.getPackageName());
if (ps == null) {
return;
}
@@ -3394,12 +3345,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int compatFlags = PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
| PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
- final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+ final boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
>= Build.VERSION_CODES.M;
- final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.packageName, userId);
+ final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.getPackageName(), userId);
- for (String permission : pkg.requestedPermissions) {
+ for (String permission : pkg.getRequestedPermissions()) {
final BasePermission bp;
synchronized (mLock) {
bp = mSettings.getPermissionLocked(permission);
@@ -3413,14 +3364,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (supportsRuntimePermissions) {
// Installer cannot change immutable permissions.
if ((flags & immutableFlags) == 0) {
- grantRuntimePermissionInternal(permission, pkg.packageName, false,
+ grantRuntimePermissionInternal(permission, pkg.getPackageName(), false,
callingUid, userId, callback);
}
} else {
// In permission review mode we clear the review flag and the revoked compat
// flag when we are asked to install the app with all permissions granted.
if ((flags & compatFlags) != 0) {
- updatePermissionFlagsInternal(permission, pkg.packageName, compatFlags,
+ updatePermissionFlagsInternal(permission, pkg.getPackageName(), compatFlags,
0, callingUid, userId, false, callback);
}
}
@@ -3428,11 +3379,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg,
+ private void setWhitelistedRestrictedPermissionsForUser(@NonNull AndroidPackage pkg,
@UserIdInt int userId, @Nullable List<String> permissions, int callingUid,
@PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(pkg);
+ PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
if (permissionsState == null) {
return;
}
@@ -3440,9 +3391,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
ArraySet<String> oldGrantedRestrictedPermissions = null;
boolean updatePermissions = false;
- final int permissionCount = pkg.requestedPermissions.size();
+ final int permissionCount = pkg.getRequestedPermissions().size();
for (int i = 0; i < permissionCount; i++) {
- final String permissionName = pkg.requestedPermissions.get(i);
+ final String permissionName = pkg.getRequestedPermissions().get(i);
final BasePermission bp = mSettings.getPermissionLocked(permissionName);
@@ -3518,19 +3469,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// If we are whitelisting an app that does not support runtime permissions
// we need to make sure it goes through the permission review UI at launch.
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
&& !wasWhitelisted && isWhitelisted) {
mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
}
- updatePermissionFlagsInternal(permissionName, pkg.packageName, mask, newFlags,
+ updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags,
callingUid, userId, false, null /*callback*/);
}
if (updatePermissions) {
// Update permission of this app to take into account the new whitelist state.
- restorePermissionState(pkg, false, pkg.packageName, callback);
+ restorePermissionState(pkg, false, pkg.getPackageName(), callback);
// If this resulted in losing a permission we need to kill the app.
if (oldGrantedRestrictedPermissions != null) {
@@ -3539,9 +3490,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final String permission = oldGrantedRestrictedPermissions.valueAt(i);
// Sometimes we create a new permission state instance during update.
final PermissionsState newPermissionsState =
- PackageManagerServiceUtils.getPermissionsState(pkg);
+ PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
if (!newPermissionsState.hasPermission(permission, userId)) {
- callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
+ callback.onPermissionRevoked(pkg.getUid(), userId);
break;
}
}
@@ -3554,17 +3505,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
SharedUserSetting suSetting, int[] allUserIds) {
// Collect all used permissions in the UID
final ArraySet<String> usedPermissions = new ArraySet<>();
- final List<PackageParser.Package> pkgList = suSetting.getPackages();
+ final List<AndroidPackage> pkgList = suSetting.getPackages();
if (pkgList == null || pkgList.size() == 0) {
return EmptyArray.INT;
}
- for (PackageParser.Package pkg : pkgList) {
- if (pkg.requestedPermissions == null) {
+ for (AndroidPackage pkg : pkgList) {
+ if (pkg.getRequestedPermissions() == null) {
continue;
}
- final int requestedPermCount = pkg.requestedPermissions.size();
+ final int requestedPermCount = pkg.getRequestedPermissions().size();
for (int j = 0; j < requestedPermCount; j++) {
- String permission = pkg.requestedPermissions.get(j);
+ String permission = pkg.getRequestedPermissions().get(j);
BasePermission bp = mSettings.getPermissionLocked(permission);
if (bp != null) {
usedPermissions.add(permission);
@@ -3626,18 +3577,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param allPackages All currently known packages
* @param callback Callback to call after permission changes
*/
- private void updatePermissions(@NonNull String packageName, @Nullable PackageParser.Package pkg,
+ private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg,
@NonNull PermissionCallback callback) {
final int flags =
(pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0);
updatePermissions(
packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback);
- if (pkg != null && pkg.childPackages != null) {
- for (PackageParser.Package childPkg : pkg.childPackages) {
- updatePermissions(childPkg.packageName, childPkg,
- getVolumeUuidForPackage(childPkg), flags, callback);
- }
- }
}
/**
@@ -3673,10 +3618,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Only system declares background permissions, hence mapping does never change.
mBackgroundPermissions = new ArrayMap<>();
for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
- if (bp.perm != null && bp.perm.info != null
- && bp.perm.info.backgroundPermission != null) {
+ if (bp.perm != null && bp.perm.backgroundPermission != null) {
String fgPerm = bp.name;
- String bgPerm = bp.perm.info.backgroundPermission;
+ String bgPerm = bp.perm.backgroundPermission;
List<String> fgPerms = mBackgroundPermissions.get(bgPerm);
if (fgPerms == null) {
@@ -3737,7 +3681,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param callback Callback to call after permission changes
*/
private void updatePermissions(final @Nullable String changingPkgName,
- final @Nullable PackageParser.Package changingPkg,
+ final @Nullable AndroidPackage changingPkg,
final @Nullable String replaceVolumeUuid,
@UpdatePermissionFlags int flags,
final @Nullable PermissionCallback callback) {
@@ -3770,7 +3714,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Now update the permissions for all packages.
if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
final boolean replaceAll = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0);
- mPackageManagerInt.forEachPackage((Package pkg) -> {
+ mPackageManagerInt.forEachPackage((AndroidPackage pkg) -> {
if (pkg == changingPkg) {
return;
}
@@ -3809,7 +3753,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @return {@code true} if a permission source package might have changed
*/
private boolean updatePermissionSourcePackage(@Nullable String packageName,
- @Nullable PackageParser.Package pkg,
+ @Nullable AndroidPackage pkg,
final @Nullable PermissionCallback callback) {
boolean changed = false;
@@ -3832,8 +3776,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
final int userId = userIds[userIdNum];
- mPackageManagerInt.forEachPackage((Package p) -> {
- final String pName = p.packageName;
+ mPackageManagerInt.forEachPackage((AndroidPackage p) -> {
+ final String pName = p.getPackageName();
final ApplicationInfo appInfo =
mPackageManagerInt.getApplicationInfo(pName, 0,
Process.SYSTEM_UID, UserHandle.USER_SYSTEM);
@@ -3878,11 +3822,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (needsUpdate != null) {
for (final BasePermission bp : needsUpdate) {
- final PackageParser.Package sourcePkg =
+ final AndroidPackage sourcePkg =
mPackageManagerInt.getPackage(bp.getSourcePackageName());
+ final PackageSetting sourcePs =
+ (PackageSetting) mPackageManagerInt.getPackageSetting(
+ bp.getSourcePackageName());
synchronized (mLock) {
- if (sourcePkg != null && sourcePkg.mExtras != null) {
- final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras;
+ if (sourcePkg != null && sourcePs != null) {
if (bp.getSourcePackageSetting() == null) {
bp.setSourcePackageSetting(sourcePs);
}
@@ -3915,7 +3861,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @return {@code true} if a permission tree ownership might have changed
*/
private boolean updatePermissionTreeSourcePackage(@Nullable String packageName,
- @Nullable PackageParser.Package pkg) {
+ @Nullable AndroidPackage pkg) {
boolean changed = false;
Set<BasePermission> needsUpdate = null;
@@ -3941,11 +3887,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (needsUpdate != null) {
for (final BasePermission bp : needsUpdate) {
- final PackageParser.Package sourcePkg =
+ final AndroidPackage sourcePkg =
mPackageManagerInt.getPackage(bp.getSourcePackageName());
+ final PackageSetting sourcePs =
+ (PackageSetting) mPackageManagerInt.getPackageSetting(
+ bp.getSourcePackageName());
synchronized (mLock) {
- if (sourcePkg != null && sourcePkg.mExtras != null) {
- final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras;
+ if (sourcePkg != null && sourcePs != null) {
if (bp.getSourcePackageSetting() == null) {
bp.setSourcePackageSetting(sourcePs);
}
@@ -4068,24 +4016,28 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private static String getVolumeUuidForPackage(PackageParser.Package pkg) {
+ private static String getVolumeUuidForPackage(AndroidPackage pkg) {
if (pkg == null) {
return StorageManager.UUID_PRIVATE_INTERNAL;
}
if (pkg.isExternal()) {
- if (TextUtils.isEmpty(pkg.volumeUuid)) {
+ if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
return StorageManager.UUID_PRIMARY_PHYSICAL;
} else {
- return pkg.volumeUuid;
+ return pkg.getVolumeUuid();
}
} else {
return StorageManager.UUID_PRIVATE_INTERNAL;
}
}
- private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) {
- for (int i=pkgInfo.permissions.size()-1; i>=0; i--) {
- if (pkgInfo.permissions.get(i).info.name.equals(permName)) {
+ private static boolean hasPermission(AndroidPackage pkg, String permName) {
+ if (pkg.getPermissions() == null) {
+ return false;
+ }
+
+ for (int i = pkg.getPermissions().size() - 1; i >= 0; i--) {
+ if (pkg.getPermissions().get(i).getName().equals(permName)) {
return true;
}
}
@@ -4124,37 +4076,39 @@ public class PermissionManagerService extends IPermissionManager.Stub {
PermissionManagerService.this.systemReady();
}
@Override
- public boolean isPermissionsReviewRequired(@NonNull Package pkg, @UserIdInt int userId) {
+ public boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
+ @UserIdInt int userId) {
return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId);
}
+
@Override
public void revokeRuntimePermissionsIfGroupChanged(
- @NonNull PackageParser.Package newPackage,
- @NonNull PackageParser.Package oldPackage,
+ @NonNull AndroidPackage newPackage,
+ @NonNull AndroidPackage oldPackage,
@NonNull ArrayList<String> allPackageNames) {
PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
oldPackage, allPackageNames, mDefaultPermissionCallback);
}
@Override
- public void addAllPermissions(Package pkg, boolean chatty) {
+ public void addAllPermissions(AndroidPackage pkg, boolean chatty) {
PermissionManagerService.this.addAllPermissions(pkg, chatty);
}
@Override
- public void addAllPermissionGroups(Package pkg, boolean chatty) {
+ public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
PermissionManagerService.this.addAllPermissionGroups(pkg, chatty);
}
@Override
- public void removeAllPermissions(Package pkg, boolean chatty) {
+ public void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
@Override
- public void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+ public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
String[] grantedPermissions, int callingUid) {
PermissionManagerService.this.grantRequestedRuntimePermissions(
pkg, userIds, grantedPermissions, callingUid, mDefaultPermissionCallback);
}
@Override
- public void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
+ public void setWhitelistedRestrictedPermissions(@NonNull AndroidPackage pkg,
@NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
@PackageManager.PermissionWhitelistFlags int flags) {
for (int userId : userIds) {
@@ -4169,13 +4123,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
packageName, permissions, flags, userId);
}
@Override
- public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg,
- int callingUid) {
- PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked(
- pkg, callingUid, mDefaultPermissionCallback);
- }
- @Override
- public void updatePermissions(@NonNull String packageName, @Nullable Package pkg) {
+ public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
PermissionManagerService.this
.updatePermissions(packageName, pkg, mDefaultPermissionCallback);
}
@@ -4185,13 +4133,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
.updateAllPermissions(volumeUuid, sdkUpdated, mDefaultPermissionCallback);
}
@Override
- public void resetRuntimePermissions(Package pkg, int userId) {
+ public void resetRuntimePermissions(AndroidPackage pkg, int userId) {
PermissionManagerService.this.resetRuntimePermissionsInternal(pkg, userId);
}
@Override
public void resetAllRuntimePermissions(final int userId) {
mPackageManagerInt.forEachPackage(
- (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
+ (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId));
}
@Override
public String[] getAppOpPermissionPackages(String permName, int callingUid) {
@@ -4237,9 +4185,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int i = 0; i < numTotalPermissions; i++) {
BasePermission bp = mSettings.mPermissions.valueAt(i);
- if (bp.perm != null && bp.perm.info != null
- && bp.perm.info.getProtection() == protection) {
- matchingPermissions.add(bp.perm.info);
+ if (bp.perm != null && bp.perm.getProtection() == protection) {
+ matchingPermissions.add(
+ PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
}
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index fb5c6fddedc6..0f22619fafa6 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -21,8 +21,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
import android.permission.PermissionManagerInternal;
import java.util.ArrayList;
@@ -175,16 +175,14 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void systemReady();
- public abstract boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg,
+ public abstract boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
@UserIdInt int userId);
- public abstract void grantRuntimePermissionsGrantedToDisabledPackage(
- @NonNull PackageParser.Package pkg, int callingUid);
public abstract void grantRequestedRuntimePermissions(
- @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+ @NonNull AndroidPackage pkg, @NonNull int[] userIds,
@NonNull String[] grantedPermissions, int callingUid);
public abstract void setWhitelistedRestrictedPermissions(
- @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+ @NonNull AndroidPackage pkg, @NonNull int[] userIds,
@NonNull List<String> permissions, int callingUid,
@PackageManager.PermissionWhitelistFlags int whitelistFlags);
/** Sets the whitelisted, restricted permissions for the given package. */
@@ -206,7 +204,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
* @param callback Callback to call after permission changes
*/
public abstract void updatePermissions(@NonNull String packageName,
- @Nullable PackageParser.Package pkg);
+ @Nullable AndroidPackage pkg);
/**
* Update all permissions for all apps.
@@ -226,7 +224,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
* Resets any user permission state changes (eg. permissions and flags) of all
* packages installed for the given user.
*
- * @see #resetRuntimePermissions(android.content.pm.PackageParser.Package, int)
+ * @see #resetRuntimePermissions(AndroidPackage, int)
*/
public abstract void resetAllRuntimePermissions(@UserIdInt int userId);
@@ -234,7 +232,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
* Resets any user permission state changes (eg. permissions and flags) of the
* specified package for the given user.
*/
- public abstract void resetRuntimePermissions(@NonNull PackageParser.Package pkg,
+ public abstract void resetRuntimePermissions(@NonNull AndroidPackage pkg,
@UserIdInt int userId);
/**
@@ -247,8 +245,8 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
* @param allPackageNames All packages
*/
public abstract void revokeRuntimePermissionsIfGroupChanged(
- @NonNull PackageParser.Package newPackage,
- @NonNull PackageParser.Package oldPackage,
+ @NonNull AndroidPackage newPackage,
+ @NonNull AndroidPackage oldPackage,
@NonNull ArrayList<String> allPackageNames);
/**
@@ -257,9 +255,9 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
* NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to
* the permission settings.
*/
- public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
- public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
- public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
+ public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
+ public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty);
+ public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
/** Retrieve the packages that have requested the given app op permission */
public abstract @Nullable String[] getAppOpPermissionPackages(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index 3d8cf2ddc2cc..254b720c57a0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -18,7 +18,7 @@ package com.android.server.pm.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -65,8 +65,8 @@ public class PermissionSettings {
* name to permission group object.
*/
@GuardedBy("mLock")
- final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
- new ArrayMap<String, PackageParser.PermissionGroup>();
+ final ArrayMap<String, ComponentParseUtils.ParsedPermissionGroup> mPermissionGroups =
+ new ArrayMap<>();
/**
* Set of packages that request a particular app op. The mapping is from permission
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 9b9f93f7b5c4..b1feb148e5b3 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -37,8 +37,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
-import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
@@ -357,10 +357,10 @@ public final class PermissionPolicyService extends SystemService {
pkg.sharedUserId, userId);
if (sharedPkgNames != null) {
for (String sharedPkgName : sharedPkgNames) {
- final PackageParser.Package sharedPkg = packageManagerInternal
+ final AndroidPackage sharedPkg = packageManagerInternal
.getPackage(sharedPkgName);
if (sharedPkg != null) {
- synchroniser.addPackage(sharedPkg.packageName);
+ synchroniser.addPackage(sharedPkg.getPackageName());
}
}
}
@@ -377,7 +377,8 @@ public final class PermissionPolicyService extends SystemService {
PackageManagerInternal.class);
final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
getUserContext(getContext(), UserHandle.of(userId)));
- packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName));
+ packageManagerInternal.forEachPackage(
+ (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
synchronizer.syncPackages();
}
@@ -676,10 +677,19 @@ public final class PermissionPolicyService extends SystemService {
private void setUidMode(int opCode, int uid, int mode,
@NonNull String packageName) {
- final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
- .opToPublicName(opCode), uid, packageName);
- if (currentMode != mode) {
+ final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
+ opCode), uid, packageName);
+ if (oldMode != mode) {
mAppOpsManager.setUidMode(opCode, uid, mode);
+ final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
+ opCode), uid, packageName);
+ if (newMode != mode) {
+ // Work around incorrectly-set package mode. It never makes sense for app ops
+ // related to runtime permissions, but can get in the way and we have to reset
+ // it.
+ mAppOpsManager.setMode(opCode, uid, packageName, AppOpsManager.opToDefaultMode(
+ opCode));
+ }
}
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 95a5f52e5efb..f608642f3b81 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -18,6 +18,7 @@ package com.android.server.policy;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -272,14 +273,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public WindowManager.LayoutParams getAttrs();
/**
- * Return whether this window needs the menu key shown. Must be called
- * with window lock held, because it may need to traverse down through
- * window list to determine the result.
- * @param bottom The bottom-most window to consider when determining this.
- */
- public boolean getNeedsMenuLw(WindowState bottom);
-
- /**
* Retrieve the current system UI visibility flags associated with
* this window.
*/
@@ -876,13 +869,15 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
return 30;
+ case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
+ return 31;
case TYPE_SECURE_SYSTEM_OVERLAY:
- return 31;
- case TYPE_BOOT_PROGRESS:
return 32;
+ case TYPE_BOOT_PROGRESS:
+ return 33;
case TYPE_POINTER:
// the (mouse) pointer layer
- return 33;
+ return 34;
default:
Slog.e("WindowManager", "Unknown window type: " + type);
return APPLICATION_LAYER;
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index ff9129956a3b..a62bb74730f8 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -773,9 +773,9 @@ public class BatterySaverStateMachine {
// Handle triggering the notification to show/hide when appropriate
if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) {
- runOnBgThread(this::triggerDynamicModeNotification);
+ triggerDynamicModeNotification();
} else if (!enable) {
- runOnBgThread(this::hideDynamicModeNotification);
+ hideDynamicModeNotification();
}
if (DEBUG) {
@@ -787,33 +787,42 @@ public class BatterySaverStateMachine {
@VisibleForTesting
void triggerDynamicModeNotification() {
- NotificationManager manager = mContext.getSystemService(NotificationManager.class);
- ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID,
- R.string.dynamic_mode_notification_channel_name);
-
- manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID,
- buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
- mContext.getResources().getString(R.string.dynamic_mode_notification_title),
- R.string.dynamic_mode_notification_summary,
- Intent.ACTION_POWER_USAGE_SUMMARY),
- UserHandle.ALL);
+ // The current lock is the PowerManager lock, which sits very low in the service lock
+ // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
+ runOnBgThread(() -> {
+ NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+ ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+ R.string.dynamic_mode_notification_channel_name);
+
+ manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID,
+ buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+ mContext.getResources().getString(
+ R.string.dynamic_mode_notification_title),
+ R.string.dynamic_mode_notification_summary,
+ Intent.ACTION_POWER_USAGE_SUMMARY),
+ UserHandle.ALL);
+ });
}
@VisibleForTesting
void triggerStickyDisabledNotification() {
- NotificationManager manager = mContext.getSystemService(NotificationManager.class);
- ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID,
- R.string.battery_saver_notification_channel_name);
-
- final String percentage = NumberFormat.getPercentInstance()
- .format((double) mBatteryLevel / 100.0);
- manager.notifyAsUser(TAG, STICKY_AUTO_DISABLED_NOTIFICATION_ID,
- buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID,
- mContext.getResources().getString(
- R.string.battery_saver_charged_notification_title, percentage),
- R.string.battery_saver_off_notification_summary,
- Settings.ACTION_BATTERY_SAVER_SETTINGS),
- UserHandle.ALL);
+ // The current lock is the PowerManager lock, which sits very low in the service lock
+ // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
+ runOnBgThread(() -> {
+ NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+ ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID,
+ R.string.battery_saver_notification_channel_name);
+
+ final String percentage = NumberFormat.getPercentInstance()
+ .format((double) mBatteryLevel / 100.0);
+ manager.notifyAsUser(TAG, STICKY_AUTO_DISABLED_NOTIFICATION_ID,
+ buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID,
+ mContext.getResources().getString(
+ R.string.battery_saver_charged_notification_title, percentage),
+ R.string.battery_saver_off_notification_summary,
+ Settings.ACTION_BATTERY_SAVER_SETTINGS),
+ UserHandle.ALL);
+ });
}
private void ensureNotificationChannelExists(NotificationManager manager,
@@ -854,8 +863,12 @@ public class BatterySaverStateMachine {
}
private void hideNotification(int notificationId) {
- NotificationManager manager = mContext.getSystemService(NotificationManager.class);
- manager.cancel(notificationId);
+ // The current lock is the PowerManager lock, which sits very low in the service lock
+ // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
+ runOnBgThread(() -> {
+ NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+ manager.cancelAsUser(TAG, notificationId, UserHandle.ALL);
+ });
}
private void setStickyActive(boolean active) {
diff --git a/services/core/java/com/android/server/role/FinancialSmsManager.java b/services/core/java/com/android/server/role/FinancialSmsManager.java
deleted file mode 100644
index 2ec39931789a..000000000000
--- a/services/core/java/com/android/server/role/FinancialSmsManager.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.role;
-
-import android.Manifest;
-import android.annotation.MainThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteCallback;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.sms.FinancialSmsService;
-import android.service.sms.IFinancialSmsService;
-import android.util.Slog;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/**
- * This class binds to {@code FinancialSmsService}.
- */
-final class FinancialSmsManager {
-
- private static final String TAG = "FinancialSmsManager";
-
- private final Context mContext;
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private ServiceConnection mServiceConnection;
-
- @GuardedBy("mLock")
- private IFinancialSmsService mRemoteService;
-
- @GuardedBy("mLock")
- private ArrayList<Command> mQueuedCommands;
-
- FinancialSmsManager(Context context) {
- mContext = context;
- }
-
- @Nullable
- ServiceInfo getServiceInfo() {
- final String packageName =
- mContext.getPackageManager().getServicesSystemSharedLibraryPackageName();
- if (packageName == null) {
- Slog.w(TAG, "no external services package!");
- return null;
- }
-
- final Intent intent = new Intent(FinancialSmsService.ACTION_FINANCIAL_SERVICE_INTENT);
- intent.setPackage(packageName);
- final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
- PackageManager.GET_SERVICES);
- if (resolveInfo == null || resolveInfo.serviceInfo == null) {
- Slog.w(TAG, "No valid components found.");
- return null;
- }
- return resolveInfo.serviceInfo;
- }
-
- @Nullable
- private ComponentName getServiceComponentName() {
- final ServiceInfo serviceInfo = getServiceInfo();
- if (serviceInfo == null) return null;
-
- final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
- if (!Manifest.permission.BIND_FINANCIAL_SMS_SERVICE.equals(serviceInfo.permission)) {
- Slog.w(TAG, name.flattenToShortString() + " does not require permission "
- + Manifest.permission.BIND_FINANCIAL_SMS_SERVICE);
- return null;
- }
-
- return name;
- }
-
- void reset() {
- synchronized (mLock) {
- if (mServiceConnection != null) {
- mContext.unbindService(mServiceConnection);
- mServiceConnection = null;
- } else {
- Slog.d(TAG, "reset(): service is not bound. Do nothing.");
- }
- }
- }
-
- /**
- * Run a command, starting the service connection if necessary.
- */
- private void connectAndRun(@NonNull Command command) {
- synchronized (mLock) {
- if (mRemoteService != null) {
- try {
- command.run(mRemoteService);
- } catch (RemoteException e) {
- Slog.w(TAG, "exception calling service: " + e);
- }
- return;
- } else {
- if (mQueuedCommands == null) {
- mQueuedCommands = new ArrayList<>(1);
- }
- mQueuedCommands.add(command);
- // If we're already connected, don't create a new connection, just leave - the
- // command will be run when the service connects
- if (mServiceConnection != null) return;
- }
-
- // Create the connection
- mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- mRemoteService = IFinancialSmsService.Stub.asInterface(service);
- if (mQueuedCommands != null) {
- final int size = mQueuedCommands.size();
- for (int i = 0; i < size; i++) {
- final Command queuedCommand = mQueuedCommands.get(i);
- try {
- queuedCommand.run(mRemoteService);
- } catch (RemoteException e) {
- Slog.w(TAG, "exception calling " + name + ": " + e);
- }
- }
- mQueuedCommands = null;
- }
- }
- }
-
- @Override
- @MainThread
- public void onServiceDisconnected(ComponentName name) {
- synchronized (mLock) {
- mRemoteService = null;
- }
- }
-
- @Override
- public void onBindingDied(ComponentName name) {
- synchronized (mLock) {
- mRemoteService = null;
- }
- }
-
- @Override
- public void onNullBinding(ComponentName name) {
- synchronized (mLock) {
- mRemoteService = null;
- }
- }
- };
-
- final ComponentName component = getServiceComponentName();
- if (component != null) {
- final Intent intent = new Intent();
- intent.setComponent(component);
- final long token = Binder.clearCallingIdentity();
- try {
- mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE,
- UserHandle.getUserHandleForUid(UserHandle.getCallingUserId()));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- }
- }
-
- void getSmsMessages(RemoteCallback callback, @Nullable Bundle params) {
- connectAndRun((service) -> service.getSmsMessages(callback, params));
- }
-
- void dump(String prefix, PrintWriter pw) {
- final ComponentName impl = getServiceComponentName();
- pw.print(prefix); pw.print("User ID: "); pw.println(UserHandle.getCallingUserId());
- pw.print(prefix); pw.print("Queued commands: ");
- if (mQueuedCommands == null) {
- pw.println("N/A");
- } else {
- pw.println(mQueuedCommands.size());
- }
- pw.print(prefix); pw.print("Implementation: ");
- if (impl == null) {
- pw.println("N/A");
- return;
- }
- pw.println(impl.flattenToShortString());
- }
-
- private interface Command {
- void run(IFinancialSmsService service) throws RemoteException;
- }
-}
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index aac0f906feaa..c4522e03b700 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -50,7 +50,6 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManagerInternal;
-import android.service.sms.FinancialSmsService;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -308,12 +307,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
ByteArrayOutputStream out = new ByteArrayOutputStream();
pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> {
- out.write(pkg.packageName.getBytes());
+ out.write(pkg.getPackageName().getBytes());
out.write(BitUtils.toBytes(pkg.getLongVersionCode()));
- out.write(pm.getApplicationEnabledState(pkg.packageName, userId));
+ out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId));
ArraySet<String> enabledComponents =
- pm.getEnabledComponents(pkg.packageName, userId);
+ pm.getEnabledComponents(pkg.getPackageName(), userId);
int numComponents = CollectionUtils.size(enabledComponents);
out.write(numComponents);
for (int i = 0; i < numComponents; i++) {
@@ -321,12 +320,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
ArraySet<String> disabledComponents =
- pm.getDisabledComponents(pkg.packageName, userId);
+ pm.getDisabledComponents(pkg.getPackageName(), userId);
numComponents = CollectionUtils.size(disabledComponents);
for (int i = 0; i < numComponents; i++) {
out.write(disabledComponents.valueAt(i).getBytes());
}
- for (Signature signature : pkg.mSigningDetails.signatures) {
+ for (Signature signature : pkg.getSigningDetails().signatures) {
out.write(signature.toByteArray());
}
}), userId);
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index a62616623cb5..bb095841bbaa 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -61,7 +61,6 @@ import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.TimeUnit;
/**
* {@link PackageHealthObserver} for {@link RollbackManagerService}.
@@ -74,10 +73,6 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
private static final String TAG = "RollbackPackageHealthObserver";
private static final String NAME = "rollback-observer";
private static final int INVALID_ROLLBACK_ID = -1;
- // TODO: make the following values configurable via DeviceConfig
- private static final long NATIVE_CRASH_POLLING_INTERVAL_MILLIS =
- TimeUnit.SECONDS.toMillis(30);
- private static final long NUMBER_OF_NATIVE_CRASH_POLLS = 10;
private final Context mContext;
private final Handler mHandler;
@@ -85,13 +80,9 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
// Staged rollback ids that have been committed but their session is not yet ready
@GuardedBy("mPendingStagedRollbackIds")
private final Set<Integer> mPendingStagedRollbackIds = new ArraySet<>();
- // this field is initialized in the c'tor and then only accessed from mHandler thread, so
- // no need to guard with a lock
- private long mNumberOfNativeCrashPollsRemaining;
RollbackPackageHealthObserver(Context context) {
mContext = context;
- mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
handlerThread.start();
mHandler = handlerThread.getThreadHandler();
@@ -102,9 +93,15 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
@Override
- public int onHealthCheckFailed(VersionedPackage failedPackage) {
- if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), failedPackage)
- == null) {
+ public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
+ @FailureReasons int failureReason) {
+ // For native crashes, we will roll back any available rollbacks
+ if (failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH
+ && !mContext.getSystemService(RollbackManager.class)
+ .getAvailableRollbacks().isEmpty()) {
+ return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
+ }
+ if (getAvailableRollback(failedPackage) == null) {
// Don't handle the notification, no rollbacks available for the package
return PackageHealthObserverImpact.USER_IMPACT_NONE;
} else {
@@ -114,52 +111,21 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
@Override
- public boolean execute(VersionedPackage failedPackage, @FailureReasons int rollbackReason) {
- RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
- VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
- RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage);
- int reasonToLog = mapFailureReasonToMetric(rollbackReason);
+ public boolean execute(@Nullable VersionedPackage failedPackage,
+ @FailureReasons int rollbackReason) {
+ if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
+ rollbackAll();
+ return true;
+ }
+ RollbackInfo rollback = getAvailableRollback(failedPackage);
if (rollback == null) {
Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
+ failedPackage.getPackageName() + "] with versionCode: ["
+ failedPackage.getVersionCode() + "]");
return false;
}
-
- logEvent(moduleMetadataPackage,
- StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
- reasonToLog, failedPackage.getPackageName());
- LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
- int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
- RollbackManager.STATUS_FAILURE);
- if (status == RollbackManager.STATUS_SUCCESS) {
- if (rollback.isStaged()) {
- int rollbackId = rollback.getRollbackId();
- synchronized (mPendingStagedRollbackIds) {
- mPendingStagedRollbackIds.add(rollbackId);
- }
- BroadcastReceiver listener =
- listenForStagedSessionReady(rollbackManager, rollbackId,
- moduleMetadataPackage);
- handleStagedSessionChange(rollbackManager, rollbackId, listener,
- moduleMetadataPackage);
- } else {
- logEvent(moduleMetadataPackage,
- StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
- reasonToLog, failedPackage.getPackageName());
- }
- } else {
- logEvent(moduleMetadataPackage,
- StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
- reasonToLog, failedPackage.getPackageName());
- }
- });
-
- mHandler.post(() ->
- rollbackManager.commitRollback(rollback.getRollbackId(),
- Collections.singletonList(failedPackage),
- rollbackReceiver.getIntentSender()));
+ rollbackPackage(rollback, failedPackage, rollbackReason);
// Assume rollback executed successfully
return true;
}
@@ -188,10 +154,10 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
String moduleMetadataPackageName = getModuleMetadataPackageName();
- VersionedPackage newModuleMetadataPackage = getModuleMetadataPackage();
- if (getAvailableRollback(rollbackManager, newModuleMetadataPackage) != null) {
- scheduleCheckAndMitigateNativeCrashes();
+ if (!rollbackManager.getAvailableRollbacks().isEmpty()) {
+ // TODO(gavincorkery): Call into Package Watchdog from outside the observer
+ PackageWatchdog.getInstance(mContext).scheduleCheckAndMitigateNativeCrashes();
}
int rollbackId = popLastStagedRollbackId();
@@ -242,8 +208,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
}
- private RollbackInfo getAvailableRollback(RollbackManager rollbackManager,
- VersionedPackage failedPackage) {
+ private RollbackInfo getAvailableRollback(VersionedPackage failedPackage) {
+ RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
boolean hasFailedPackage = packageRollback.getPackageName().equals(
@@ -285,7 +251,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
- int rollbackId, VersionedPackage moduleMetadataPackage) {
+ int rollbackId, @Nullable VersionedPackage moduleMetadataPackage) {
BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -300,7 +266,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
- BroadcastReceiver listener, VersionedPackage moduleMetadataPackage) {
+ BroadcastReceiver listener, @Nullable VersionedPackage moduleMetadataPackage) {
PackageInstaller packageInstaller =
mContext.getPackageManager().getPackageInstaller();
List<RollbackInfo> recentRollbacks =
@@ -382,36 +348,102 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
}
+
/**
- * This method should be only called on mHandler thread, since it modifies
- * {@link #mNumberOfNativeCrashPollsRemaining} and we want to keep this class lock free.
+ * Returns true if the package name is the name of a module.
*/
- private void checkAndMitigateNativeCrashes() {
- mNumberOfNativeCrashPollsRemaining--;
- // Check if native watchdog reported a crash
- if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
- execute(getModuleMetadataPackage(), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
- // we stop polling after an attempt to execute rollback, regardless of whether the
- // attempt succeeds or not
- } else {
- if (mNumberOfNativeCrashPollsRemaining > 0) {
- mHandler.postDelayed(() -> checkAndMitigateNativeCrashes(),
- NATIVE_CRASH_POLLING_INTERVAL_MILLIS);
- }
+ private boolean isModule(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ return pm.getModuleInfo(packageName, 0) != null;
+ } catch (PackageManager.NameNotFoundException ignore) {
+ return false;
+ }
+ }
+
+ private VersionedPackage getVersionedPackage(String packageName) {
+ try {
+ return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo(
+ packageName, 0 /* flags */).getLongVersionCode());
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
}
}
/**
- * Since this method can eventually trigger a RollbackManager rollback, it should be called
- * only once boot has completed {@code onBootCompleted} and not earlier, because the install
- * session must be entirely completed before we try to rollback.
+ * Rolls back the session that owns {@code failedPackage}
+ *
+ * @param rollback {@code rollbackInfo} of the {@code failedPackage}
+ * @param failedPackage the package that needs to be rolled back
*/
- private void scheduleCheckAndMitigateNativeCrashes() {
- Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check "
- + "and mitigate native crashes");
- mHandler.post(()->checkAndMitigateNativeCrashes());
+ private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
+ @FailureReasons int rollbackReason) {
+ final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+ int reasonToLog = mapFailureReasonToMetric(rollbackReason);
+ final String failedPackageToLog;
+ if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
+ failedPackageToLog = SystemProperties.get(
+ "sys.init.updatable_crashing_process_name", "");
+ } else {
+ failedPackageToLog = failedPackage.getPackageName();
+ }
+ final VersionedPackage logPackage = isModule(failedPackage.getPackageName())
+ ? getModuleMetadataPackage()
+ : null;
+
+ logEvent(logPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
+ reasonToLog, failedPackageToLog);
+ final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
+ int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+ RollbackManager.STATUS_FAILURE);
+ if (status == RollbackManager.STATUS_SUCCESS) {
+ if (rollback.isStaged()) {
+ int rollbackId = rollback.getRollbackId();
+ synchronized (mPendingStagedRollbackIds) {
+ mPendingStagedRollbackIds.add(rollbackId);
+ }
+ BroadcastReceiver listener =
+ listenForStagedSessionReady(rollbackManager, rollbackId,
+ logPackage);
+ handleStagedSessionChange(rollbackManager, rollbackId, listener,
+ logPackage);
+ } else {
+ logEvent(logPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+ reasonToLog, failedPackageToLog);
+ }
+ } else {
+ logEvent(logPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
+ reasonToLog, failedPackageToLog);
+ }
+ });
+
+ mHandler.post(() ->
+ rollbackManager.commitRollback(rollback.getRollbackId(),
+ Collections.singletonList(failedPackage),
+ rollbackReceiver.getIntentSender()));
}
+ private void rollbackAll() {
+ Slog.i(TAG, "Rolling back all available rollbacks");
+ RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+ List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();
+
+ for (RollbackInfo rollback : rollbacks) {
+ String samplePackageName = rollback.getPackages().get(0).getPackageName();
+ VersionedPackage sampleVersionedPackage = getVersionedPackage(samplePackageName);
+ if (sampleVersionedPackage == null) {
+ Slog.e(TAG, "Failed to rollback " + samplePackageName);
+ continue;
+ }
+ rollbackPackage(rollback, sampleVersionedPackage,
+ PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
+ }
+ }
+
+
private int mapFailureReasonToMetric(@FailureReasons int failureReason) {
switch (failureReason) {
case PackageWatchdog.FAILURE_REASON_NATIVE_CRASH:
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index d76836f90e6b..46dd366f1909 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -43,7 +43,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
-import java.io.IOException;
/**
* Controls storage sessions for users initiated by the {@link StorageManagerService}.
@@ -101,18 +100,10 @@ public final class StorageSessionController {
connection = new StorageUserConnection(mContext, userId, this);
mConnections.put(userId, connection);
}
- Slog.i(TAG, "Creating session with id: " + sessionId);
- connection.createSession(sessionId, new ParcelFileDescriptor(deviceFd),
+ Slog.i(TAG, "Creating and starting session with id: " + sessionId);
+ connection.startSession(sessionId, new ParcelFileDescriptor(deviceFd),
vol.getPath().getPath(), vol.getInternalPath().getPath());
}
-
- // At boot, a volume can be mounted before user is unlocked, in that case, we create it
- // above and save it so that we can restart all sessions when the user is unlocked
- if (mExternalStorageServiceComponent != null) {
- connection.startSession(sessionId);
- } else {
- Slog.i(TAG, "Controller not initialised, session not started " + sessionId);
- }
}
/**
@@ -179,23 +170,32 @@ public final class StorageSessionController {
* a session will be ignored.
*/
public void onUnlockUser(int userId) throws ExternalStorageServiceException {
- if (!shouldHandle(null)) {
- return;
- }
-
Slog.i(TAG, "On user unlock " + userId);
- if (userId == 0) {
+ if (shouldHandle(null) && userId == 0) {
initExternalStorageServiceComponent();
}
+ }
+ /**
+ * Called when a user is in the process is being stopped.
+ *
+ * Does nothing if {@link #shouldHandle} is {@code false}
+ *
+ * This call removes all sessions for the user that is being stopped;
+ * this will make sure that we don't rebind to the service needlessly.
+ */
+ public void onUserStopping(int userId) throws ExternalStorageServiceException {
+ if (!shouldHandle(null)) {
+ return;
+ }
StorageUserConnection connection = null;
synchronized (mLock) {
connection = mConnections.get(userId);
}
if (connection != null) {
- Slog.i(TAG, "Restarting all sessions for user: " + userId);
- connection.startAllSessions();
+ Slog.i(TAG, "Removing all sessions for user: " + userId);
+ connection.removeAllSessions();
} else {
Slog.w(TAG, "No connection found for user: " + userId);
}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 7c4773033518..5c44eee4c789 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -34,6 +34,7 @@ import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
import android.os.RemoteCallback;
import android.os.UserHandle;
+import android.os.storage.StorageManagerInternal;
import android.service.storage.ExternalStorageService;
import android.service.storage.IExternalStorageService;
import android.text.TextUtils;
@@ -41,6 +42,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
import java.io.IOException;
import java.util.HashMap;
@@ -73,42 +75,25 @@ public final class StorageUserConnection {
}
/**
- * Creates and stores a storage {@link Session}.
+ * Creates and starts a storage {@link Session}.
*
* They must also be cleaned up with {@link #removeSession}.
*
* @throws IllegalArgumentException if a {@code Session} with {@code sessionId} already exists
*/
- public void createSession(String sessionId, ParcelFileDescriptor pfd, String upperPath,
- String lowerPath) {
+ public void startSession(String sessionId, ParcelFileDescriptor pfd, String upperPath,
+ String lowerPath) throws ExternalStorageServiceException {
Preconditions.checkNotNull(sessionId);
Preconditions.checkNotNull(pfd);
Preconditions.checkNotNull(upperPath);
Preconditions.checkNotNull(lowerPath);
- synchronized (mLock) {
- Preconditions.checkArgument(!mSessions.containsKey(sessionId));
- mSessions.put(sessionId, new Session(sessionId, pfd, upperPath, lowerPath));
- }
- }
-
- /**
- * Starts an already created storage {@link Session} for {@code sessionId}.
- *
- * It is safe to call this multiple times, however if the session is already started,
- * subsequent calls will be ignored.
- *
- * @throws ExternalStorageServiceException if the session failed to start
- **/
- public void startSession(String sessionId) throws ExternalStorageServiceException {
- Session session;
- synchronized (mLock) {
- session = mSessions.get(sessionId);
- }
-
prepareRemote();
synchronized (mLock) {
- mActiveConnection.startSessionLocked(session);
+ Preconditions.checkArgument(!mSessions.containsKey(sessionId));
+ Session session = new Session(sessionId, upperPath, lowerPath);
+ mSessions.put(sessionId, session);
+ mActiveConnection.startSessionLocked(session, pfd);
}
}
@@ -121,16 +106,10 @@ public final class StorageUserConnection {
**/
public Session removeSession(String sessionId) {
synchronized (mLock) {
- Session session = mSessions.remove(sessionId);
- if (session != null) {
- session.close();
- return session;
- }
- return null;
+ return mSessions.remove(sessionId);
}
}
-
/**
* Removes a session and waits for exit
*
@@ -150,25 +129,29 @@ public final class StorageUserConnection {
}
}
- /** Starts all available sessions for a user without blocking. Any failures will be ignored. */
- public void startAllSessions() {
- try {
- prepareRemote();
- } catch (ExternalStorageServiceException e) {
- Slog.e(TAG, "Failed to start all sessions for user: " + mUserId, e);
- return;
+ /** Restarts all available sessions for a user without blocking.
+ *
+ * Any failures will be ignored.
+ **/
+ public void resetUserSessions() {
+ synchronized (mLock) {
+ if (mSessions.isEmpty()) {
+ // Nothing to reset if we have no sessions to restart; we typically
+ // hit this path if the user was consciously shut down.
+ return;
+ }
}
+ StorageManagerInternal sm = LocalServices.getService(StorageManagerInternal.class);
+ sm.resetUser(mUserId);
+ }
+ /**
+ * Removes all sessions, without waiting.
+ */
+ public void removeAllSessions() {
synchronized (mLock) {
- Slog.i(TAG, "Starting " + mSessions.size() + " sessions for user: " + mUserId + "...");
- for (Session session : mSessions.values()) {
- try {
- mActiveConnection.startSessionLocked(session);
- } catch (IllegalStateException | ExternalStorageServiceException e) {
- // TODO: Don't crash process? We could get into process crash loop
- Slog.e(TAG, "Failed to start " + session, e);
- }
- }
+ Slog.i(TAG, "Removing " + mSessions.size() + " sessions for user: " + mUserId + "...");
+ mSessions.clear();
}
}
@@ -269,26 +252,37 @@ public final class StorageUserConnection {
return true;
}
- public void startSessionLocked(Session session) throws ExternalStorageServiceException {
+ public void startSessionLocked(Session session, ParcelFileDescriptor fd)
+ throws ExternalStorageServiceException {
if (!isActiveLocked(session)) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // ignore
+ }
return;
}
CountDownLatch latch = new CountDownLatch(1);
- try (ParcelFileDescriptor dupedPfd = session.pfd.dup()) {
+ try {
mRemote.startSession(session.sessionId,
FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE,
- dupedPfd, session.upperPath, session.lowerPath, new RemoteCallback(result ->
+ fd, session.upperPath, session.lowerPath, new RemoteCallback(result ->
setResultLocked(latch, result)));
waitForLatch(latch, "start_session " + session);
maybeThrowExceptionLocked();
} catch (Exception e) {
throw new ExternalStorageServiceException("Failed to start session: " + session, e);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // Ignore
+ }
}
}
public void endSessionLocked(Session session) throws ExternalStorageServiceException {
- session.close();
if (!isActiveLocked(session)) {
// Nothing to end, not started yet
return;
@@ -390,7 +384,7 @@ public final class StorageUserConnection {
// will be called for any required mounts.
// Notify StorageManagerService so it can restart all necessary sessions
close();
- new Thread(StorageUserConnection.this::startAllSessions).start();
+ resetUserSessions();
}
};
}
@@ -411,29 +405,18 @@ public final class StorageUserConnection {
}
}
- private static final class Session implements AutoCloseable {
+ private static final class Session {
public final String sessionId;
- public final ParcelFileDescriptor pfd;
public final String lowerPath;
public final String upperPath;
- Session(String sessionId, ParcelFileDescriptor pfd, String upperPath, String lowerPath) {
+ Session(String sessionId, String upperPath, String lowerPath) {
this.sessionId = sessionId;
- this.pfd = pfd;
this.upperPath = upperPath;
this.lowerPath = lowerPath;
}
@Override
- public void close() {
- try {
- pfd.close();
- } catch (IOException e) {
- Slog.i(TAG, "Failed to close session: " + this);
- }
- }
-
- @Override
public String toString() {
return "[SessionId: " + sessionId + ". UpperPath: " + upperPath + ". LowerPath: "
+ lowerPath + "]";
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 7d905bae4491..6a986b9da515 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -24,15 +24,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.service.textclassifier.ITextClassifierCallback;
import android.service.textclassifier.ITextClassifierService;
import android.service.textclassifier.TextClassifierService;
@@ -41,7 +38,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.textclassifier.ConfigParser;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
@@ -143,7 +139,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi
private TextClassificationManagerService(Context context) {
mContext = Preconditions.checkNotNull(context);
mLock = new Object();
- mSettingsListener = new TextClassifierSettingsListener(mContext, this);
+ mSettingsListener = new TextClassifierSettingsListener(mContext);
}
private void startListenSettings() {
@@ -171,10 +167,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Slog.d(LOG_TAG, "Unable to bind TextClassifierService at suggestSelection.");
callback.onFailure();
} else if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "suggestSelection.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "suggestSelection")) {
return;
}
userState.mService.onSuggestSelection(sessionId, request, callback);
@@ -203,10 +197,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Slog.d(LOG_TAG, "Unable to bind TextClassifierService at classifyText.");
callback.onFailure();
} else if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "classifyText.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(), "classifyText")) {
return;
}
userState.mService.onClassifyText(sessionId, request, callback);
@@ -235,10 +226,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Slog.d(LOG_TAG, "Unable to bind TextClassifierService at generateLinks.");
callback.onFailure();
} else if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "generateLinks.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "generateLinks")) {
return;
}
userState.mService.onGenerateLinks(sessionId, request, callback);
@@ -262,10 +251,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
synchronized (mLock) {
UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "selectionEvent.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "selectionEvent")) {
return;
}
userState.mService.onSelectionEvent(sessionId, event);
@@ -293,10 +280,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
synchronized (mLock) {
UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "textClassifierEvent.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "textClassifierEvent")) {
return;
}
userState.mService.onTextClassifierEvent(sessionId, event);
@@ -325,10 +310,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Slog.d(LOG_TAG, "Unable to bind TextClassifierService at detectLanguage.");
callback.onFailure();
} else if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "detectLanguage.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "detectLanguage")) {
return;
}
userState.mService.onDetectLanguage(sessionId, request, callback);
@@ -358,10 +341,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
"Unable to bind TextClassifierService at suggestConversationActions.");
callback.onFailure();
} else if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "suggestConversationActions.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "suggestConversationActions")) {
return;
}
userState.mService.onSuggestConversationActions(sessionId, request, callback);
@@ -387,10 +368,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
synchronized (mLock) {
UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "createTextClassificationSession.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "createTextClassificationSession")) {
return;
}
userState.mService.onCreateTextClassificationSession(
@@ -422,10 +401,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
- if (!userState.isRequestAcceptedLocked(Binder.getCallingUid())) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + "destroyTextClassificationSession.");
+ if (!userState.checkRequestAcceptedLocked(Binder.getCallingUid(),
+ "destroyTextClassificationSession")) {
return;
}
userState.mService.onDestroyTextClassificationSession(sessionId);
@@ -488,6 +465,29 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
}
+ private void unbindServiceIfNecessary() {
+ final ComponentName serviceComponentName =
+ TextClassifierService.getServiceComponentName(mContext);
+ if (serviceComponentName == null) {
+ // It should not occur if we had defined default service names in config.xml
+ Slog.w(LOG_TAG, "No default configured system TextClassifierService.");
+ return;
+ }
+ synchronized (mLock) {
+ final int size = mUserStates.size();
+ for (int i = 0; i < size; i++) {
+ UserState userState = mUserStates.valueAt(i);
+ // Only unbind for a new service
+ if (userState.isCurrentlyBoundToComponentLocked(serviceComponentName)) {
+ return;
+ }
+ if (userState.isBoundLocked()) {
+ userState.unbindLocked();
+ }
+ }
+ }
+ }
+
private static final class PendingRequest implements IBinder.DeathRecipient {
private final int mUid;
@@ -582,48 +582,6 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
}
- private TextClassificationConstants getTextClassifierSettings(Context context) {
- synchronized (mLock) {
- if (mSettings == null) {
- mSettings = new TextClassificationConstants(
- () -> Settings.Global.getString(
- context.getContentResolver(),
- Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
- }
- return mSettings;
- }
- }
-
- private void invalidateSettings() {
- synchronized (mLock) {
- mSettings = null;
- }
- }
-
- private void unbindServiceIfNeeded() {
- final ComponentName serviceComponentName =
- TextClassifierService.getServiceComponentName(mContext,
- getTextClassifierSettings(mContext));
- if (serviceComponentName == null) {
- // It should not occur if we had defined default service name in config
- Slog.w(LOG_TAG, "No default configured system TextClassifierService.");
- return;
- }
- synchronized (mLock) {
- final int size = mUserStates.size();
- for (int i = 0; i < size; i++) {
- UserState userState = mUserStates.valueAt(i);
- // Only unbind for a new service
- if (userState.isServiceCurrentBoundLocked(serviceComponentName)) {
- return;
- }
- if (userState.isBoundLocked()) {
- userState.unbindLocked();
- }
- }
- }
- }
-
private final class UserState {
@UserIdInt final int mUserId;
@GuardedBy("mLock")
@@ -635,9 +593,9 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@GuardedBy("mLock")
boolean mBinding;
@GuardedBy("mLock")
- ComponentName mBoundServiceComponent = null;
+ ComponentName mBoundComponentName = null;
@GuardedBy("mLock")
- boolean mIsBoundToDefaultService;
+ boolean mBoundToDefaultTrustService;
@GuardedBy("mLock")
int mBoundServiceUid;
@@ -660,10 +618,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi
PendingRequest request;
while ((request = mPendingRequests.poll()) != null) {
if (isBoundLocked()) {
- if (!isRequestAcceptedLocked(request.mUid)) {
- Slog.d(LOG_TAG,
- "Only allow to see own content for non-default service at "
- + request.mName);
+ if (!checkRequestAcceptedLocked(request.mUid, request.mName)) {
return;
}
request.mRequest.run();
@@ -687,15 +642,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
@GuardedBy("mLock")
- private boolean isServiceCurrentBoundLocked(@NonNull ComponentName componentName) {
- return (mBoundServiceComponent != null
- && mBoundServiceComponent.getPackageName().equals(
+ private boolean isCurrentlyBoundToComponentLocked(@NonNull ComponentName componentName) {
+ return (mBoundComponentName != null
+ && mBoundComponentName.getPackageName().equals(
componentName.getPackageName()));
}
@GuardedBy("mLock")
private void unbindLocked() {
- Slog.d(LOG_TAG, "unbinding to " + mBoundServiceComponent + " for " + mUserId);
+ Slog.v(LOG_TAG, "unbinding from " + mBoundComponentName + " for " + mUserId);
mContext.unbindService(mConnection);
mConnection.cleanupService();
mConnection = null;
@@ -716,8 +671,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi
final long identity = Binder.clearCallingIdentity();
try {
final ComponentName componentName =
- TextClassifierService.getServiceComponentName(mContext,
- getTextClassifierSettings(mContext));
+ TextClassifierService.getServiceComponentName(mContext);
if (componentName == null) {
// Might happen if the storage is encrypted and the user is not unlocked
return false;
@@ -742,8 +696,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
pw.printPair("context", mContext);
pw.printPair("userId", mUserId);
synchronized (mLock) {
- pw.printPair("BoundServiceComponent", mBoundServiceComponent);
- pw.printPair("isBoundToDefaultService", mIsBoundToDefaultService);
+ pw.printPair("boundComponentName", mBoundComponentName);
+ pw.printPair("boundToDefaultTrustService", mBoundToDefaultTrustService);
pw.printPair("boundServiceUid", mBoundServiceUid);
pw.printPair("binding", mBinding);
pw.printPair("numberRequests", mPendingRequests.size());
@@ -751,14 +705,17 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
@GuardedBy("mLock")
- private boolean isRequestAcceptedLocked(int requestUid) {
- if (mIsBoundToDefaultService) {
+ private boolean checkRequestAcceptedLocked(int requestUid, @NonNull String methodName) {
+ if (mBoundToDefaultTrustService || (requestUid == mBoundServiceUid)) {
return true;
}
- return (requestUid == mBoundServiceUid);
+ Slog.w(LOG_TAG, String.format(
+ "[%s] Non-default TextClassifierServices may only see text from the same uid.",
+ methodName));
+ return false;
}
- private boolean isDefaultService(@NonNull ComponentName currentService) {
+ private boolean isDefaultTrustService(@NonNull ComponentName currentService) {
final String[] defaultServiceNames =
mContext.getPackageManager().getSystemTextClassifierPackages();
final String servicePackageName = currentService.getPackageName();
@@ -789,16 +746,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
@GuardedBy("mLock")
- private void updateServiceInfoLocked(@Nullable ComponentName componentName, int userId) {
- mBoundServiceComponent = componentName;
- mIsBoundToDefaultService = (mBoundServiceComponent != null && isDefaultService(
- mBoundServiceComponent));
- mBoundServiceUid = getServiceUid(mBoundServiceComponent, userId);
+ private void updateServiceInfoLocked(int userId, @Nullable ComponentName componentName) {
+ mBoundComponentName = componentName;
+ mBoundToDefaultTrustService = (mBoundComponentName != null && isDefaultTrustService(
+ mBoundComponentName));
+ mBoundServiceUid = getServiceUid(mBoundComponentName, userId);
}
private final class TextClassifierServiceConnection implements ServiceConnection {
- @UserIdInt final int mUserId;
+ @UserIdInt private final int mUserId;
TextClassifierServiceConnection(int userId) {
mUserId = userId;
@@ -840,60 +797,42 @@ public final class TextClassificationManagerService extends ITextClassifierServi
synchronized (mLock) {
mService = service;
mBinding = false;
- updateServiceInfoLocked(name, mUserId);
+ updateServiceInfoLocked(mUserId, name);
handlePendingRequestsLocked();
}
}
}
}
- private final class TextClassifierSettingsListener extends ContentObserver
- implements DeviceConfig.OnPropertiesChangedListener {
+ private final class TextClassifierSettingsListener implements
+ DeviceConfig.OnPropertiesChangedListener {
@NonNull private final Context mContext;
+ @NonNull private final TextClassificationConstants mSettings;
@Nullable private String mServicePackageName;
- TextClassifierSettingsListener(Context context, TextClassificationManagerService service) {
- super(null);
+ TextClassifierSettingsListener(Context context) {
mContext = context;
- mServicePackageName =
- getTextClassifierSettings(mContext).getTextClassifierServiceName();
+ mSettings = TextClassificationManager.getSettings(mContext);
+ mServicePackageName = mSettings.getTextClassifierServicePackageOverride();
}
public void registerObserver() {
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_CONSTANTS),
- false /* notifyForDescendants */,
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ mContext.getMainExecutor(),
this);
- if (ConfigParser.ENABLE_DEVICE_CONFIG) {
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- mContext.getMainExecutor(),
- this);
- }
}
- private void updateChange() {
- final String overrideServiceName = getTextClassifierSettings(
- mContext).getTextClassifierServiceName();
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ final String overrideServiceName = mSettings.getTextClassifierServicePackageOverride();
+
if (TextUtils.equals(overrideServiceName, mServicePackageName)) {
return;
}
mServicePackageName = overrideServiceName;
- unbindServiceIfNeeded();
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- super.onChange(selfChange, uri);
- invalidateSettings();
- updateChange();
- }
-
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- invalidateSettings();
- updateChange();
+ unbindServiceIfNecessary();
}
}
}
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index 340fe3dbaa97..5a31bbc859c8 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -23,21 +23,26 @@ import android.app.AlarmManager;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
+import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Slog;
import android.util.TimestampedValue;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.IndentingPrintWriter;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.LinkedList;
+import java.util.Map;
/**
- * An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
- * {@link AlarmManager}.
+ * An implementation of TimeDetectorStrategy that passes phone and manual suggestions to
+ * {@link AlarmManager}. When there are multiple phone sources, the one with the lowest ID is used
+ * unless the data becomes too stale.
*
* <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
@@ -46,6 +51,17 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
private static final boolean DBG = false;
private static final String LOG_TAG = "SimpleTimeDetectorStrategy";
+ /** A score value used to indicate "no score", either due to validation failure or age. */
+ private static final int PHONE_INVALID_SCORE = -1;
+ /** The number of buckets phone suggestions can be put in by age. */
+ private static final int PHONE_BUCKET_COUNT = 24;
+ /** Each bucket is this size. All buckets are equally sized. */
+ @VisibleForTesting
+ static final int PHONE_BUCKET_SIZE_MILLIS = 60 * 60 * 1000;
+ /** Phone suggestions older than this value are considered too old. */
+ @VisibleForTesting
+ static final long PHONE_MAX_AGE_MILLIS = PHONE_BUCKET_COUNT * PHONE_BUCKET_SIZE_MILLIS;
+
@IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
@Retention(RetentionPolicy.SOURCE)
public @interface Origin {}
@@ -61,25 +77,36 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
/**
* CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
* actual system clock time before a warning is logged. Used to help identify situations where
- * there is something other than this class setting the system clock automatically.
+ * there is something other than this class setting the system clock.
*/
private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
+ /** The number of previous phone suggestions to keep for each ID (for use during debugging). */
+ private static final int KEEP_SUGGESTION_HISTORY_SIZE = 30;
+
// A log for changes made to the system clock and why.
- @NonNull private final LocalLog mTimeChangesLog = new LocalLog(30);
+ @NonNull
+ private final LocalLog mTimeChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
// @NonNull after initialize()
private Callback mCallback;
- // Last phone suggestion.
- @Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
-
- // Information about the last time signal received: Used when toggling auto-time.
- @Nullable private TimestampedValue<Long> mLastAutoSystemClockTime;
- private boolean mLastAutoSystemClockTimeSendNetworkBroadcast;
+ // Used to store the last time the system clock state was set automatically. It is used to
+ // detect (and log) issues with the realtime clock or whether the clock is being set without
+ // going through this strategy code.
+ @GuardedBy("this")
+ @Nullable
+ private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
- // System clock state.
- @Nullable private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
+ /**
+ * A mapping from phoneId to a linked list of time suggestions (the "first" being the latest).
+ * We typically expect one or two entries in this Map: devices will have a small number
+ * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with
+ * the ID will not exceed {@link #KEEP_SUGGESTION_HISTORY_SIZE} in size.
+ */
+ @GuardedBy("this")
+ private ArrayMap<Integer, LinkedList<PhoneTimeSuggestion>> mSuggestionByPhoneId =
+ new ArrayMap<>();
@Override
public void initialize(@NonNull Callback callback) {
@@ -87,66 +114,297 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
@Override
- public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
- // NITZ logic
+ public synchronized void suggestManualTime(ManualTimeSuggestion suggestion) {
+ final TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
+
+ // We can validate the suggestion against the reference time clock.
+ long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+ if (elapsedRealtimeMillis < newUtcTime.getReferenceTimeMillis()) {
+ // elapsedRealtime clock went backwards?
+ Slog.w(LOG_TAG, "New reference time is in the future? Ignoring."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + ", timeSuggestion=" + suggestion);
+ return;
+ }
+
+ String cause = "Manual time suggestion received: suggestion=" + suggestion;
+ setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, cause);
+ }
- // Empty suggestions are just ignored as we don't currently keep track of suggestion origin.
+ @Override
+ public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
+ // Empty time suggestion means that telephony network connectivity has been lost.
+ // The passage of time is relentless, and we don't expect our users to use a time machine,
+ // so we can continue relying on previous suggestions when we lose connectivity. This is
+ // unlike time zone, where a user may lose connectivity when boarding a flight and where we
+ // do want to "forget" old signals. Suggestions that are too old are discarded later in the
+ // detection algorithm.
if (timeSuggestion.getUtcTime() == null) {
return;
}
- boolean timeSuggestionIsValid =
- validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion);
- if (!timeSuggestionIsValid) {
+ // Perform validation / input filtering and record the validated suggestion against the
+ // phoneId.
+ if (!validateAndStorePhoneSuggestion(timeSuggestion)) {
return;
}
- // Always store the last NITZ value received, regardless of whether we go on to use it to
- // update the system clock. This is so that we can validate future phone suggestions.
- mLastPhoneSuggestion = timeSuggestion;
- // System clock update logic.
- final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
- setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion);
+ // Now perform auto time detection. The new suggestion may be used to modify the system
+ // clock.
+ String reason = "New phone time suggested. timeSuggestion=" + timeSuggestion;
+ doAutoTimeDetection(reason);
+ }
+
+ @Override
+ public synchronized void handleAutoTimeDetectionChanged() {
+ boolean enabled = mCallback.isAutoTimeDetectionEnabled();
+ // When automatic time detection is enabled we update the system clock instantly if we can.
+ // Conversely, when automatic time detection is disabled we leave the clock as it is.
+ if (enabled) {
+ String reason = "Auto time zone detection setting enabled.";
+ doAutoTimeDetection(reason);
+ } else {
+ // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
+ // it should be in future.
+ mLastAutoSystemClockTimeSet = null;
+ }
}
@Override
- public synchronized void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
- final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
- setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion);
+ public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println("TimeDetectorStrategy:");
+ ipw.increaseIndent(); // level 1
+
+ ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
+
+ ipw.println("Time change log:");
+ ipw.increaseIndent(); // level 2
+ mTimeChangesLog.dump(ipw);
+ ipw.decreaseIndent(); // level 2
+
+ ipw.println("Phone suggestion history:");
+ ipw.increaseIndent(); // level 2
+ for (Map.Entry<Integer, LinkedList<PhoneTimeSuggestion>> entry
+ : mSuggestionByPhoneId.entrySet()) {
+ ipw.println("Phone " + entry.getKey());
+
+ ipw.increaseIndent(); // level 3
+ for (PhoneTimeSuggestion suggestion : entry.getValue()) {
+ ipw.println(suggestion);
+ }
+ ipw.decreaseIndent(); // level 3
+ }
+ ipw.decreaseIndent(); // level 2
+
+ ipw.decreaseIndent(); // level 1
+ ipw.flush();
}
- private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
- @Nullable PhoneTimeSuggestion lastSuggestion) {
-
- if (lastSuggestion != null) {
- long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
- newSuggestion.getUtcTime(), lastSuggestion.getUtcTime());
- if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
- // Out of order or bogus.
- Slog.w(LOG_TAG, "Bad NITZ signal received."
- + " referenceTimeDifference=" + referenceTimeDifference
- + " lastSuggestion=" + lastSuggestion
- + " newSuggestion=" + newSuggestion);
+ @GuardedBy("this")
+ private boolean validateAndStorePhoneSuggestion(@NonNull PhoneTimeSuggestion timeSuggestion) {
+ if (timeSuggestion.getUtcTime().getValue() == null) {
+ Slog.w(LOG_TAG, "Suggestion utcTime contains null value"
+ + " timeSuggestion=" + timeSuggestion);
+ return false;
+ }
+
+ int phoneId = timeSuggestion.getPhoneId();
+ LinkedList<PhoneTimeSuggestion> phoneSuggestions = mSuggestionByPhoneId.get(phoneId);
+ if (phoneSuggestions == null) {
+ // The first time we've seen this phoneId.
+ phoneSuggestions = new LinkedList<>();
+ mSuggestionByPhoneId.put(phoneId, phoneSuggestions);
+ } else if (phoneSuggestions.isEmpty()) {
+ Slog.w(LOG_TAG, "Suggestions unexpectedly empty when adding"
+ + " timeSuggestion=" + timeSuggestion);
+ }
+
+ if (!phoneSuggestions.isEmpty()) {
+ PhoneTimeSuggestion previousSuggestion = phoneSuggestions.getFirst();
+
+ // We can log / discard suggestions with obvious issues with the reference time clock.
+ long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+ TimestampedValue<Long> newTime = timeSuggestion.getUtcTime();
+ if (elapsedRealtimeMillis < newTime.getReferenceTimeMillis()) {
+ // elapsedRealtime clock went backwards?
+ Slog.w(LOG_TAG, "New reference time is in the future?"
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + ", timeSuggestion=" + timeSuggestion);
+ // There's probably nothing useful we can do: elsewhere we assume that reference
+ // times are in the past so just stop here.
return false;
}
+
+ if (previousSuggestion.getUtcTime() != null) {
+ long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
+ timeSuggestion.getUtcTime(), previousSuggestion.getUtcTime());
+ if (referenceTimeDifference < 0) {
+ // The reference time is before the previously received suggestion. Ignore it.
+ Slog.w(LOG_TAG, "Out of order phone suggestion received."
+ + " referenceTimeDifference=" + referenceTimeDifference
+ + " lastSuggestion=" + previousSuggestion
+ + " newSuggestion=" + timeSuggestion);
+ return false;
+ }
+ }
+ }
+
+ // Store the latest suggestion.
+ phoneSuggestions.addFirst(timeSuggestion);
+ if (phoneSuggestions.size() > KEEP_SUGGESTION_HISTORY_SIZE) {
+ phoneSuggestions.removeLast();
}
return true;
}
@GuardedBy("this")
+ private void doAutoTimeDetection(@NonNull String detectionReason) {
+ if (!mCallback.isAutoTimeDetectionEnabled()) {
+ // Avoid doing unnecessary work with this (race-prone) check.
+ return;
+ }
+
+ PhoneTimeSuggestion bestPhoneSuggestion = findBestPhoneSuggestion();
+
+ // Work out what to do with the best suggestion.
+ if (bestPhoneSuggestion == null) {
+ // There is no good phone suggestion.
+ if (DBG) {
+ Slog.d(LOG_TAG, "Could not determine time: No best phone suggestion."
+ + " detectionReason=" + detectionReason);
+ }
+ return;
+ }
+
+ final TimestampedValue<Long> newUtcTime = bestPhoneSuggestion.getUtcTime();
+ String cause = "Found good suggestion."
+ + ", bestPhoneSuggestion=" + bestPhoneSuggestion
+ + ", detectionReason=" + detectionReason;
+ setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, cause);
+ }
+
+ @GuardedBy("this")
+ @Nullable
+ private PhoneTimeSuggestion findBestPhoneSuggestion() {
+ long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+
+ // Phone time suggestions are assumed to be derived from NITZ or NITZ-like signals. These
+ // have a number of limitations:
+ // 1) No guarantee of accuracy ("accuracy of the time information is in the order of
+ // minutes") [1]
+ // 2) No guarantee of regular signals ("dependent on the handset crossing radio network
+ // boundaries") [1]
+ //
+ // [1] https://en.wikipedia.org/wiki/NITZ
+ //
+ // Generally, when there are suggestions from multiple phoneIds they should usually
+ // approximately agree. In cases where signals *are* inaccurate we don't want to vacillate
+ // between signals from two phoneIds. However, it is known for NITZ signals to be incorrect
+ // occasionally, which means we also don't want to stick forever with one phoneId. Without
+ // cross-referencing across sources (e.g. the current device time, NTP), or doing some kind
+ // of statistical analysis of consistency within and across phoneIds, we can't know which
+ // suggestions are more correct.
+ //
+ // For simplicity, we try to value recency, then consistency of phoneId.
+ //
+ // The heuristic works as follows:
+ // Recency: The most recent suggestion from each phone is scored. The score is based on a
+ // discrete age bucket, i.e. so signals received around the same time will be in the same
+ // bucket, thus applying a loose reference time ordering. The suggestion with the highest
+ // score is used.
+ // Consistency: If there a multiple suggestions with the same score, the suggestion with the
+ // lowest phoneId is always taken.
+ //
+ // In the trivial case with a single ID this will just mean that the latest received
+ // suggestion is used.
+
+ PhoneTimeSuggestion bestSuggestion = null;
+ int bestScore = PHONE_INVALID_SCORE;
+ for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
+ Integer phoneId = mSuggestionByPhoneId.keyAt(i);
+ LinkedList<PhoneTimeSuggestion> phoneSuggestions = mSuggestionByPhoneId.valueAt(i);
+ if (phoneSuggestions == null) {
+ // Unexpected - map is missing a value.
+ Slog.w(LOG_TAG, "Suggestions unexpectedly missing for phoneId."
+ + " phoneId=" + phoneId);
+ continue;
+ }
+
+ PhoneTimeSuggestion candidateSuggestion = phoneSuggestions.getFirst();
+ if (candidateSuggestion == null) {
+ // Unexpected - null suggestions should never be stored.
+ Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for phoneId."
+ + " phoneId=" + phoneId);
+ continue;
+ } else if (candidateSuggestion.getUtcTime() == null) {
+ // Unexpected - we do not store empty suggestions.
+ Slog.w(LOG_TAG, "Latest suggestion unexpectedly empty. "
+ + " candidateSuggestion=" + candidateSuggestion);
+ continue;
+ }
+
+ int candidateScore = scorePhoneSuggestion(elapsedRealtimeMillis, candidateSuggestion);
+ if (candidateScore == PHONE_INVALID_SCORE) {
+ // Expected: This means the suggestion is obviously invalid or just too old.
+ continue;
+ }
+
+ // Higher scores are better.
+ if (bestSuggestion == null || bestScore < candidateScore) {
+ bestSuggestion = candidateSuggestion;
+ bestScore = candidateScore;
+ } else if (bestScore == candidateScore) {
+ // Tie! Use the suggestion with the lowest phoneId.
+ int candidatePhoneId = candidateSuggestion.getPhoneId();
+ int bestPhoneId = bestSuggestion.getPhoneId();
+ if (candidatePhoneId < bestPhoneId) {
+ bestSuggestion = candidateSuggestion;
+ }
+ }
+ }
+ return bestSuggestion;
+ }
+
+ private static int scorePhoneSuggestion(
+ long elapsedRealtimeMillis, @NonNull PhoneTimeSuggestion timeSuggestion) {
+ // The score is based on the age since receipt. Suggestions are bucketed so two
+ // suggestions in the same bucket from different phoneIds are scored the same.
+ TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime();
+ long referenceTimeMillis = utcTime.getReferenceTimeMillis();
+ if (referenceTimeMillis > elapsedRealtimeMillis) {
+ // Future times are ignored. They imply the reference time was wrong, or the elapsed
+ // realtime clock has gone backwards, neither of which are supportable situations.
+ Slog.w(LOG_TAG, "Existing suggestion found to be in the future. "
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + ", timeSuggestion=" + timeSuggestion);
+ return PHONE_INVALID_SCORE;
+ }
+
+ long ageMillis = elapsedRealtimeMillis - referenceTimeMillis;
+
+ // Any suggestion > MAX_AGE_MILLIS is treated as too old. Although time is relentless and
+ // predictable, the accuracy of the reference time clock may be poor over long periods which
+ // would lead to errors creeping in. Also, in edge cases where a bad suggestion has been
+ // made and never replaced, it could also mean that the time detection code remains
+ // opinionated using a bad invalid suggestion. This caps that edge case at MAX_AGE_MILLIS.
+ if (ageMillis > PHONE_MAX_AGE_MILLIS) {
+ return PHONE_INVALID_SCORE;
+ }
+
+ // Turn the age into a discrete value: 0 <= bucketIndex < MAX_AGE_HOURS.
+ int bucketIndex = (int) (ageMillis / PHONE_BUCKET_SIZE_MILLIS);
+
+ // We want the lowest bucket index to have the highest score. 0 > score >= BUCKET_COUNT.
+ return PHONE_BUCKET_COUNT - bucketIndex;
+ }
+
+ @GuardedBy("this")
private void setSystemClockIfRequired(
- @Origin int origin, TimestampedValue<Long> time, Object cause) {
- // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
- // when setting the time using NITZ.
- boolean sendNetworkBroadcast = origin == ORIGIN_PHONE;
+ @Origin int origin, @NonNull TimestampedValue<Long> time, @NonNull String cause) {
boolean isOriginAutomatic = isOriginAutomatic(origin);
if (isOriginAutomatic) {
- // Store the last auto time candidate we've seen in all cases so we can set the system
- // clock when/if time detection is off but later enabled.
- mLastAutoSystemClockTime = time;
- mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
-
if (!mCallback.isAutoTimeDetectionEnabled()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is not enabled."
@@ -170,30 +428,7 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
mCallback.acquireWakeLock();
try {
- long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
- long actualTimeMillis = mCallback.systemClockMillis();
-
- if (isOriginAutomatic) {
- // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
- // may be setting the clock.
- if (mLastAutoSystemClockTimeSet != null) {
- long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
- mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
- long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
- if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
- Slog.w(LOG_TAG,
- "System clock has not tracked elapsed real time clock. A clock may"
- + " be inaccurate or something unexpectedly set the system"
- + " clock."
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + " expectedTimeMillis=" + expectedTimeMillis
- + " actualTimeMillis=" + actualTimeMillis);
- }
- }
- }
-
- adjustAndSetDeviceSystemClock(
- time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, cause);
+ setSystemClockUnderWakeLock(origin, time, cause);
} finally {
mCallback.releaseWakeLock();
}
@@ -203,61 +438,33 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
return origin == ORIGIN_PHONE;
}
- @Override
- public synchronized void handleAutoTimeDetectionChanged() {
- // If automatic time detection is enabled we update the system clock instantly if we can.
- // Conversely, if automatic time detection is disabled we leave the clock as it is.
- boolean enabled = mCallback.isAutoTimeDetectionEnabled();
- if (enabled) {
- if (mLastAutoSystemClockTime != null) {
- // Only send the network broadcast if the last candidate would have caused one.
- final boolean sendNetworkBroadcast = mLastAutoSystemClockTimeSendNetworkBroadcast;
-
- mCallback.acquireWakeLock();
- try {
- long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
- long actualTimeMillis = mCallback.systemClockMillis();
-
- final String reason = "Automatic time detection enabled.";
- adjustAndSetDeviceSystemClock(mLastAutoSystemClockTime, sendNetworkBroadcast,
- elapsedRealtimeMillis, actualTimeMillis, reason);
- } finally {
- mCallback.releaseWakeLock();
+ @GuardedBy("this")
+ private void setSystemClockUnderWakeLock(
+ int origin, @NonNull TimestampedValue<Long> newTime, @NonNull Object cause) {
+
+ long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+ boolean isOriginAutomatic = isOriginAutomatic(origin);
+ long actualSystemClockMillis = mCallback.systemClockMillis();
+ if (isOriginAutomatic) {
+ // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
+ // may be setting the clock.
+ if (mLastAutoSystemClockTimeSet != null) {
+ long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
+ mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
+ long absSystemClockDifference =
+ Math.abs(expectedTimeMillis - actualSystemClockMillis);
+ if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
+ Slog.w(LOG_TAG,
+ "System clock has not tracked elapsed real time clock. A clock may"
+ + " be inaccurate or something unexpectedly set the system"
+ + " clock."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " expectedTimeMillis=" + expectedTimeMillis
+ + " actualTimeMillis=" + actualSystemClockMillis
+ + " cause=" + cause);
}
}
- } else {
- // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
- // it should be in future.
- mLastAutoSystemClockTimeSet = null;
}
- }
-
- @Override
- public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
- IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println("TimeDetectorStrategy:");
- ipw.increaseIndent(); // level 1
-
- ipw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
- ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
- ipw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime);
- ipw.println("mLastAutoSystemClockTimeSendNetworkBroadcast="
- + mLastAutoSystemClockTimeSendNetworkBroadcast);
-
-
- ipw.println("Time change log:");
- ipw.increaseIndent(); // level 2
- mTimeChangesLog.dump(ipw);
- ipw.decreaseIndent(); // level 2
-
- ipw.decreaseIndent(); // level 1
- ipw.flush();
- }
-
- @GuardedBy("this")
- private void adjustAndSetDeviceSystemClock(
- TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
- long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) {
// Adjust for the time that has elapsed since the signal was received.
long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
@@ -289,10 +496,17 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
mTimeChangesLog.log(logMsg);
- // CLOCK_PARANOIA : Record the last time this class set the system clock.
- mLastAutoSystemClockTimeSet = newTime;
+ // CLOCK_PARANOIA : Record the last time this class set the system clock due to an auto-time
+ // signal, or clear the record it is being done manually.
+ if (isOriginAutomatic(origin)) {
+ mLastAutoSystemClockTimeSet = newTime;
+ } else {
+ mLastAutoSystemClockTimeSet = null;
+ }
- if (sendNetworkBroadcast) {
+ // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
+ // when setting the time using NITZ.
+ if (origin == ORIGIN_PHONE) {
// Send a broadcast that telephony code used to send after setting the clock.
// TODO Remove this broadcast as soon as there are no remaining listeners.
Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
@@ -301,4 +515,27 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
mCallback.sendStickyBroadcast(intent);
}
}
+
+ /**
+ * Returns the current best phone suggestion. Not intended for general use: it is used during
+ * tests to check strategy behavior.
+ */
+ @VisibleForTesting
+ @Nullable
+ public synchronized PhoneTimeSuggestion findBestPhoneSuggestionForTests() {
+ return findBestPhoneSuggestion();
+ }
+
+ /**
+ * A method used to inspect state during tests. Not intended for general use.
+ */
+ @VisibleForTesting
+ @Nullable
+ public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int phoneId) {
+ LinkedList<PhoneTimeSuggestion> suggestions = mSuggestionByPhoneId.get(phoneId);
+ if (suggestions == null) {
+ return null;
+ }
+ return suggestions.getFirst();
+ }
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index e034ad437555..adf6d7e51f4f 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -20,13 +20,9 @@ import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.provider.Settings;
-import com.android.internal.telephony.TelephonyIntents;
-
/**
* The real implementation of {@link TimeZoneDetectorStrategy.Callback}.
*/
@@ -66,16 +62,8 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
}
@Override
- public void setDeviceTimeZone(String zoneId, boolean sendNetworkBroadcast) {
+ public void setDeviceTimeZone(String zoneId) {
AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
alarmManager.setTimeZone(zoneId);
-
- if (sendNetworkBroadcast) {
- // TODO Nothing in the platform appears to listen for this. Remove it.
- Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra("time-zone", zoneId);
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- }
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 5db12c7ac872..b4d80531be54 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -86,7 +86,7 @@ public class TimeZoneDetectorStrategy {
/**
* Sets the device's time zone.
*/
- void setDeviceTimeZone(@NonNull String zoneId, boolean sendNetworkBroadcast);
+ void setDeviceTimeZone(@NonNull String zoneId);
}
private static final String LOG_TAG = "TimeZoneDetectorStrategy";
@@ -172,7 +172,7 @@ public class TimeZoneDetectorStrategy {
* (for use during debugging).
*/
@NonNull
- private final LocalLog mTimeZoneChangesLog = new LocalLog(30);
+ private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
/**
* A mapping from phoneId to a linked list of phone time zone suggestions (the head being the
@@ -333,7 +333,6 @@ public class TimeZoneDetectorStrategy {
Objects.requireNonNull(newZoneId);
Objects.requireNonNull(cause);
- boolean sendNetworkBroadcast = (origin == ORIGIN_PHONE);
boolean isOriginAutomatic = isOriginAutomatic(origin);
if (isOriginAutomatic) {
if (!mCallback.isAutoTimeZoneDetectionEnabled()) {
@@ -373,12 +372,11 @@ public class TimeZoneDetectorStrategy {
return;
}
- mCallback.setDeviceTimeZone(newZoneId, sendNetworkBroadcast);
+ mCallback.setDeviceTimeZone(newZoneId);
String msg = "Set device time zone."
+ " origin=" + origin
+ ", currentZoneId=" + currentZoneId
+ ", newZoneId=" + newZoneId
- + ", sendNetworkBroadcast" + sendNetworkBroadcast
+ ", cause=" + cause;
if (DBG) {
Slog.d(LOG_TAG, msg);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 84152e830c3f..35b64e73d162 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -468,7 +468,7 @@ class ActivityDisplay extends DisplayContent {
if (resumedActivity == null || resumedActivity.app == null) {
// If previously resumed activity doesn't work either - find the topmost running
// activity that can be focused.
- resumedActivity = focusedStack.topRunningActivityLocked(true /* focusableOnly */);
+ resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
}
}
return resumedActivity;
@@ -832,7 +832,7 @@ class ActivityDisplay extends DisplayContent {
ActivityRecord topRunning = null;
final ActivityStack focusedStack = getFocusedStack();
if (focusedStack != null) {
- topRunning = focusedStack.topRunningActivityLocked();
+ topRunning = focusedStack.topRunningActivity();
}
// Look in other focusable stacks.
@@ -843,7 +843,7 @@ class ActivityDisplay extends DisplayContent {
if (stack == focusedStack || !stack.isFocusable()) {
continue;
}
- topRunning = stack.topRunningActivityLocked();
+ topRunning = stack.topRunningActivity();
if (topRunning != null) {
break;
}
@@ -961,12 +961,6 @@ class ActivityDisplay extends DisplayContent {
super.onConfigurationChanged(newParentConfig);
}
- void onLockTaskPackagesUpdated() {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- getStackAt(i).onLockTaskPackagesUpdated();
- }
- }
-
/** Checks whether the given activity is in size compatibility mode and notifies the change. */
void handleActivitySizeCompatModeIfNeeded(ActivityRecord r) {
if (!r.isState(RESUMED) || r.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
@@ -1082,7 +1076,7 @@ class ActivityDisplay extends DisplayContent {
}
final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
- if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) {
+ if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) {
// Release this display if an empty home stack is the only thing left.
// Since it is the last stack, this display will be released along with the stack
// removal.
@@ -1318,13 +1312,7 @@ class ActivityDisplay extends DisplayContent {
@VisibleForTesting
void removeAllTasks() {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- final ArrayList<Task> tasks = stack.getAllTasks();
- for (int j = tasks.size() - 1; j >= 0; --j) {
- stack.removeChild(tasks.get(j), "removeAllTasks");
- }
- }
+ mDisplayContent.forAllTasks((t) -> { t.getStack().removeChild(t, "removeAllTasks"); });
}
public void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 83c854bae4b5..4e39daec0b83 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -547,7 +547,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
new WindowState.UpdateReportedVisibilityResults();
- private boolean mUseTransferredAnimation;
+ boolean mUseTransferredAnimation;
/**
* @see #currentLaunchCanTurnScreenOn()
@@ -2190,7 +2190,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Sets if this AWT is in the process of closing or entering PIP.
+ * Sets if this {@link ActivityRecord} is in the process of closing or entering PIP.
* {@link #mWillCloseOrEnterPip}}
*/
void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
@@ -2198,7 +2198,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Returns whether this AWT is considered closing. Conditions are either
+ * Returns whether this {@link ActivityRecord} is considered closing. Conditions are either
* 1. Is this app animating and was requested to be hidden
* 2. App is delayed closing since it might enter PIP.
*/
@@ -2406,7 +2406,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// We are finishing the top focused activity and its stack has nothing to be focused so
// the next focusable stack should be focused.
if (mayAdjustTop
- && (stack.topRunningActivityLocked() == null || !stack.isFocusable())) {
+ && (stack.topRunningActivity() == null || !stack.isFocusable())) {
if (shouldAdjustGlobalFocus) {
// Move the entire hierarchy to top with updating global top resumed activity
// and focused application if needed.
@@ -3000,7 +3000,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this);
- boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
+ commitVisibility(false /* visible */, true /* performLayout */);
getDisplayContent().mOpeningApps.remove(this);
getDisplayContent().mChangingApps.remove(this);
@@ -3008,6 +3008,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mWmService.mTaskSnapshotController.onAppRemoved(this);
mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
waitingToShow = false;
+
+ boolean delayed = isAnimating(TRANSITION | CHILDREN);
if (getDisplayContent().mClosingApps.contains(this)) {
delayed = true;
} else if (getDisplayContent().mAppTransition.isTransitionSet()) {
@@ -3152,16 +3154,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
updateLetterboxSurface(child);
}
- private boolean waitingForReplacement() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState candidate = mChildren.get(i);
- if (candidate.waitingForReplacement()) {
- return true;
- }
- }
- return false;
- }
-
void onWindowReplacementTimeout() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
(mChildren.get(i)).onWindowReplacementTimeout();
@@ -3417,7 +3409,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// before the non-exiting app tokens. So, we skip the exiting app tokens here.
// TODO: Investigate if we need to continue to do this or if we can just process them
// in-order.
- if (mIsExiting && !waitingForReplacement()) {
+ if (mIsExiting && !forAllWindowsUnchecked(WindowState::waitingForReplacement, true)) {
return false;
}
return forAllWindowsUnchecked(callback, traverseTopToBottom);
@@ -3440,7 +3432,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@Override
- ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {
+ ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
+ WindowContainer boundary) {
return callback.test(this) ? this : null;
}
@@ -3861,6 +3854,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ /**
+ * Set visibility on this {@link ActivityRecord}
+ *
+ * <p class="note"><strong>Note: </strong>This function might not update the visibility of
+ * this {@link ActivityRecord} immediately. In case we are preparing an app transition, we
+ * delay changing the visibility of this {@link ActivityRecord} until we execute that
+ * transition.</p>
+ *
+ * @param visible {@code true} if the {@link ActivityRecord} should become visible, otherwise
+ * this should become invisible.
+ */
void setVisibility(boolean visible) {
if (getParent() == null) {
Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
@@ -3997,153 +4001,169 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
- commitVisibility(null, visible, TRANSIT_UNSET, true, mVoiceInteraction);
+ commitVisibility(visible, true /* performLayout */);
updateReportedVisibilityLocked();
}
- boolean commitVisibility(WindowManager.LayoutParams lp,
- boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
+ @Override
+ boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+ boolean isVoiceInteraction) {
+ if (mUseTransferredAnimation) {
+ return false;
+ }
+ return super.applyAnimation(lp, transit, enter, isVoiceInteraction);
+ }
- boolean delayed = false;
- // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually
+ /**
+ * Update visibility to this {@link ActivityRecord}.
+ *
+ * <p class="note"><strong>Note: </strong> Unlike {@link #setVisibility}, this immediately
+ * updates the visibility without starting an app transition. Since this function may start
+ * animation on {@link WindowState} depending on app transition animation status, an app
+ * transition animation must be started before calling this function if necessary.</p>
+ *
+ * @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise
+ * this should become invisible.
+ * @param performLayout if {@code true}, perform surface placement after committing visibility.
+ */
+ void commitVisibility(boolean visible, boolean performLayout) {
+ // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
// been set by the app now.
mVisibleSetFromTransferredStartingWindow = false;
+ if (visible == isVisible()) {
+ return;
+ }
- // Allow for state changes and animation to be applied if:
- // * token is transitioning visibility state
- // * or the token was marked as hidden and is exiting before we had a chance to play the
- // transition animation
- // * or this is an opening app and windows are being replaced
- // * or the token is the opening app and visible while opening task behind existing one.
- final DisplayContent displayContent = getDisplayContent();
- boolean visibilityChanged = false;
- if (isVisible() != visible || (!isVisible() && mIsExiting)
- || (visible && waitingForReplacement())
- || (visible && displayContent.mOpeningApps.contains(this)
- && displayContent.mAppTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND)) {
- final AccessibilityController accessibilityController =
- mWmService.mAccessibilityController;
- boolean changed = false;
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "Changing app %s visible=%b performLayout=%b", this, isVisible(),
- performLayout);
-
- boolean runningAppAnimation = false;
-
- if (transit != WindowManager.TRANSIT_UNSET) {
- if (mUseTransferredAnimation) {
- runningAppAnimation = isAnimating();
- } else if (applyAnimation(lp, transit, visible, isVoiceInteraction)) {
- runningAppAnimation = true;
- }
- delayed = runningAppAnimation;
- final WindowState window = findMainWindow();
- if (window != null && accessibilityController != null) {
- accessibilityController.onAppWindowTransitionLocked(window, transit);
- }
- changed = true;
- }
-
- final int windowsCount = mChildren.size();
- for (int i = 0; i < windowsCount; i++) {
- final WindowState win = mChildren.get(i);
- changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
- }
-
- setVisible(visible);
- mVisibleRequested = visible;
- visibilityChanged = true;
- if (!visible) {
- stopFreezingScreen(true, true);
- } else {
- // If we are being set visible, and the starting window is not yet displayed,
- // then make sure it doesn't get displayed.
- if (startingWindow != null && !startingWindow.isDrawnLw()) {
- startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
- startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
- }
-
- // We are becoming visible, so better freeze the screen with the windows that are
- // getting visible so we also wait for them.
- forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
- }
-
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "commitVisibility: %s: visible=%b visibleRequested=%b", this,
- isVisible(), mVisibleRequested);
-
- if (changed) {
- displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
- if (performLayout) {
- mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
- false /*updateInputWindows*/);
- mWmService.mWindowPlacerLocked.performSurfacePlacement();
- }
- displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
+ final int windowsCount = mChildren.size();
+ for (int i = 0; i < windowsCount; i++) {
+ mChildren.get(i).onAppVisibilityChanged(visible, isAnimating(PARENTS));
+ }
+ setVisible(visible);
+ mVisibleRequested = visible;
+ if (!visible) {
+ stopFreezingScreen(true, true);
+ } else {
+ // If we are being set visible, and the starting window is not yet displayed,
+ // then make sure it doesn't get displayed.
+ if (startingWindow != null && !startingWindow.isDrawnLw()) {
+ startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
+ startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
}
+ // We are becoming visible, so better freeze the screen with the windows that are
+ // getting visible so we also wait for them.
+ forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
+ }
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+ "commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
+ isVisible(), mVisibleRequested);
+ final DisplayContent displayContent = getDisplayContent();
+ displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
+ if (performLayout) {
+ mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+ false /*updateInputWindows*/);
+ mWmService.mWindowPlacerLocked.performSurfacePlacement();
}
+ displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
mUseTransferredAnimation = false;
- delayed = isAnimating(CHILDREN);
+ postApplyAnimation(visible);
+ }
+
+ /**
+ * Post process after applying an app transition animation.
+ *
+ * <p class="note"><strong>Note: </strong> This function must be called after the animations
+ * have been applied and {@link #commitVisibility}.</p>
+ *
+ * @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise
+ * this has become invisible.
+ */
+ private void postApplyAnimation(boolean visible) {
+ final boolean delayed = isAnimating(PARENTS | CHILDREN);
if (!delayed) {
- // We aren't animating anything, but exiting windows rely on the animation finished
- // callback being called in case the ActivityRecord was pretending to be animating,
+ // We aren't delayed anything, but exiting windows rely on the animation finished
+ // callback being called in case the ActivityRecord was pretending to be delayed,
// which we might have done because we were in closing/opening apps list.
onAnimationFinished();
- }
-
- if (visibilityChanged) {
- if (visible && !delayed) {
+ if (visible) {
// The token was made immediately visible, there will be no entrance animation.
// We need to inform the client the enter animation was finished.
mEnteringAnimation = true;
mWmService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(
token);
}
+ }
- // If we're becoming visible, immediately change client visibility as well. there seem
- // to be some edge cases where we change our visibility but client visibility never gets
- // updated.
- // If we're becoming invisible, update the client visibility if we are not running an
- // animation. Otherwise, we'll update client visibility in onAnimationFinished.
- if (visible || !isAnimating()) {
- setClientVisible(visible);
- }
-
- if (!displayContent.mClosingApps.contains(this)
- && !displayContent.mOpeningApps.contains(this)) {
- // The token is not closing nor opening, so even if there is an animation set, that
- // doesn't mean that it goes through the normal app transition cycle so we have
- // to inform the docked controller about visibility change.
- // TODO(multi-display): notify docked divider on all displays where visibility was
- // affected.
- displayContent.getDockedDividerController().notifyAppVisibilityChanged();
-
- // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
- // will not be taken.
- mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
- }
-
- // If we are hidden but there is no delay needed we immediately
- // apply the Surface transaction so that the ActivityManager
- // can have some guarantee on the Surface state following
- // setting the visibility. This captures cases like dismissing
- // the docked or pinned stack where there is no app transition.
- //
- // In the case of a "Null" animation, there will be
- // no animation but there will still be a transition set.
- // We still need to delay hiding the surface such that it
- // can be synchronized with showing the next surface in the transition.
- if (!isVisible() && !delayed && !displayContent.mAppTransition.isTransitionSet()) {
- SurfaceControl.openTransaction();
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- mChildren.get(i).mWinAnimator.hide("immediately hidden");
- }
+ // If we're becoming visible, immediately change client visibility as well. there seem
+ // to be some edge cases where we change our visibility but client visibility never gets
+ // updated.
+ // If we're becoming invisible, update the client visibility if we are not running an
+ // animation. Otherwise, we'll update client visibility in onAnimationFinished.
+ if (visible || !isAnimating(PARENTS)) {
+ setClientVisible(visible);
+ }
+
+ final DisplayContent displayContent = getDisplayContent();
+ if (!displayContent.mClosingApps.contains(this)
+ && !displayContent.mOpeningApps.contains(this)) {
+ // The token is not closing nor opening, so even if there is an animation set, that
+ // doesn't mean that it goes through the normal app transition cycle so we have
+ // to inform the docked controller about visibility change.
+ // TODO(multi-display): notify docked divider on all displays where visibility was
+ // affected.
+ displayContent.getDockedDividerController().notifyAppVisibilityChanged();
+
+ // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
+ // will not be taken.
+ mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
+ }
+
+ // If we are hidden but there is no delay needed we immediately
+ // apply the Surface transaction so that the ActivityManager
+ // can have some guarantee on the Surface state following
+ // setting the visibility. This captures cases like dismissing
+ // the docked or pinned stack where there is no app transition.
+ //
+ // In the case of a "Null" animation, there will be
+ // no animation but there will still be a transition set.
+ // We still need to delay hiding the surface such that it
+ // can be synchronized with showing the next surface in the transition.
+ if (!isVisible() && !delayed && !displayContent.mAppTransition.isTransitionSet()) {
+ SurfaceControl.openTransaction();
+ try {
+ forAllWindows(win -> {
+ win.mWinAnimator.hide("immediately hidden"); }, true);
+ } finally {
SurfaceControl.closeTransaction();
}
}
+ }
- return delayed;
+ /**
+ * Check if visibility of this {@link ActivityRecord} should be updated as part of an app
+ * transition.
+ *
+ * <p class="note><strong>Note:</strong> If the visibility of this {@link ActivityRecord} is
+ * already set to {@link #visible}, we don't need to update the visibility. So {@code false} is
+ * returned.</p>
+ *
+ * @param visible {@code true} if this {@link ActivityRecord} should become visible,
+ * {@code false} if this should become invisible.
+ * @return {@code true} if visibility of this {@link ActivityRecord} should be updated, and
+ * an app transition animation should be run.
+ */
+ boolean shouldApplyAnimation(boolean visible) {
+ // Allow for state update and animation to be applied if:
+ // * token is transitioning visibility state
+ // * or the token was marked as hidden and is exiting before we had a chance to play the
+ // transition animation
+ // * or this is an opening app and windows are being replaced
+ // * or the token is the opening app and visible while opening task behind existing one.
+ final DisplayContent displayContent = getDisplayContent();
+ return isVisible() != visible || (!isVisible() && mIsExiting)
+ || (visible && forAllWindows(WindowState::waitingForReplacement, true))
+ || (visible && displayContent.mOpeningApps.contains(this)
+ && displayContent.mAppTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND);
}
/**
@@ -5634,19 +5654,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return task != null ? task.isChangingAppTransition() : super.isChangingAppTransition();
}
- @Override
- boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- boolean isVoiceInteraction) {
- if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
- "applyAnimation: transition animation is disabled or skipped. "
- + "container=%s", this);
- cancelAnimation();
- return false;
- }
- return super.applyAnimation(lp, transit, enter, isVoiceInteraction);
- }
-
/**
* Creates a layer to apply crop to an animation.
*/
@@ -5913,14 +5920,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
protected void onAnimationFinished() {
super.onAnimationFinished();
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#onAnimationFinished");
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
mTransit = TRANSIT_UNSET;
mTransitFlags = 0;
mNeedsZBoost = false;
mNeedsAnimationBoundsLayer = false;
setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
- "AppWindowToken");
+ "ActivityRecord");
clearThumbnail();
setClientVisible(isVisible() || mVisibleRequested);
@@ -6138,10 +6145,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode()) {
return false;
}
- final Configuration resolvedConfig = getResolvedOverrideConfiguration();
- final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
- if (resolvedAppBounds == null) {
- // The override configuration has not been resolved yet.
+ final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds();
+ if (appBounds == null) {
+ // The app bounds hasn't been computed yet.
return false;
}
@@ -6149,13 +6155,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
// fields should be changed with density and bounds, so here only compares the most
// significant field.
- if (parentConfig.densityDpi != resolvedConfig.densityDpi) {
+ if (parentConfig.densityDpi != getConfiguration().densityDpi) {
return true;
}
final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
- final int appWidth = resolvedAppBounds.width();
- final int appHeight = resolvedAppBounds.height();
+ final int appWidth = appBounds.width();
+ final int appHeight = appBounds.height();
final int parentAppWidth = parentAppBounds.width();
final int parentAppHeight = parentAppBounds.height();
if (parentAppWidth == appWidth && parentAppHeight == appHeight) {
@@ -6174,7 +6180,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// The rest of the condition is that only one side is smaller than the parent, but it still
// needs to exclude the cases where the size is limited by the fixed aspect ratio.
if (info.maxAspectRatio > 0) {
- final float aspectRatio = Math.max(appWidth, appHeight) / Math.min(appWidth, appHeight);
+ final float aspectRatio =
+ (float) Math.max(appWidth, appHeight) / Math.min(appWidth, appHeight);
if (aspectRatio >= info.maxAspectRatio) {
// The current size has reached the max aspect ratio.
return false;
@@ -6526,7 +6533,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else if (mCompatDisplayInsets != null) {
// The override changes can only be obtained from display, because we don't have the
// difference of full configuration in each hierarchy.
- final int displayChanges = display.getLastOverrideConfigurationChanges();
+ final int displayChanges = display.getCurrentOverrideConfigurationChanges();
final int orientationChanges = CONFIG_WINDOW_CONFIGURATION
| CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION;
final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges)
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index cc456717a0b2..eb1f6380913d 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
@@ -191,7 +192,7 @@ import java.util.function.Consumer;
/**
* State and management of a single stack of activities.
*/
-class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarget {
+class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAnimationTarget {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -583,7 +584,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
return true;
}
- final ActivityRecord topActivity = topRunningActivityLocked();
+ final ActivityRecord topActivity = topRunningActivity();
final PooledFunction f = PooledLambda.obtainFunction(
CheckBehindFullscreenActivityHelper::processActivity, this,
PooledLambda.__(ActivityRecord.class), topActivity);
@@ -870,7 +871,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
final boolean isMinimizedDock =
display.mDisplayContent.getDockedDividerController().isMinimizedDock();
if (isMinimizedDock) {
- Task topTask = display.getSplitScreenPrimaryStack().topTask();
+ Task topTask = display.getSplitScreenPrimaryStack().getTopMostTask();
if (topTask != null) {
dockedBounds = topTask.getBounds();
}
@@ -946,7 +947,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
final int currentMode = getWindowingMode();
final int currentOverrideMode = getRequestedOverrideWindowingMode();
final ActivityDisplay display = getDisplay();
- final Task topTask = topTask();
+ final Task topTask = getTopMostTask();
final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
int windowingMode = preferredWindowingMode;
if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
@@ -1174,11 +1175,11 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
return false;
}
- ActivityRecord topRunningActivityLocked() {
- return topRunningActivityLocked(false /* focusableOnly */);
+ ActivityRecord topRunningActivity() {
+ return topRunningActivity(false /* focusableOnly */);
}
- ActivityRecord topRunningActivityLocked(boolean focusableOnly) {
+ ActivityRecord topRunningActivity(boolean focusableOnly) {
// Split into 2 to avoid object creation due to variable capture.
if (focusableOnly) {
return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
@@ -1212,7 +1213,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
*
* @return Returns the HistoryRecord of the next activity on the stack.
*/
- final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
+ ActivityRecord topRunningActivity(IBinder token, int taskId) {
final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isTopRunning,
PooledLambda.__(ActivityRecord.class), taskId, token);
final ActivityRecord r = getActivity(p);
@@ -1221,31 +1222,13 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) {
- return r.getTask().mTaskId == taskId && r.appToken != notTop && r.canBeTopRunning();
+ return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning();
}
ActivityRecord getTopNonFinishingActivity() {
return getTopActivity(false /*includeFinishing*/, true /*includeOverlays*/);
}
- final Task topTask() {
- final int size = getChildCount();
- if (size > 0) {
- return getChildAt(size - 1);
- }
- return null;
- }
-
- Task taskForIdLocked(int id) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- if (task.mTaskId == id) {
- return task;
- }
- }
- return null;
- }
-
ActivityRecord isInStackLocked(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
return isInStackLocked(r);
@@ -1292,9 +1275,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
private boolean returnsToHomeStack() {
- return !inMultiWindowMode()
- && hasChild()
- && getChildAt(0).returnsToHomeStack();
+ return !inMultiWindowMode() && hasChild() && getBottomMostTask().returnsToHomeStack();
}
void moveToFront(String reason) {
@@ -1367,7 +1348,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
boolean isFocusable() {
- final ActivityRecord r = topRunningActivityLocked();
+ final ActivityRecord r = topRunningActivity();
return mRootActivityContainer.isFocusable(this, r != null && r.isFocusable());
}
@@ -1390,15 +1371,12 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
mCurrentUser = userId;
super.switchUser(userId);
- int top = mChildren.size();
- for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
- Task task = mChildren.get(taskNdx);
- if (mWmService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
- mChildren.remove(taskNdx);
- mChildren.add(task);
- --top;
+ forAllTasks((t) -> {
+ if (t.mWmService.isCurrentProfileLocked(t.mUserId) || t.showForAllUsers()) {
+ mChildren.remove(t);
+ mChildren.add(t);
}
- }
+ });
}
void minimalResumeActivityLocked(ActivityRecord r) {
@@ -1719,7 +1697,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
mRootActivityContainer.resumeFocusedStacksTopActivities(topStack, prev, null);
} else {
checkReadyForSleep();
- ActivityRecord top = topStack.topRunningActivityLocked();
+ ActivityRecord top = topStack.topRunningActivity();
if (top == null || (prev != null && top != prev)) {
// If there are no more activities available to run, do resume anyway to start
// something. Also if the top activity on the stack is not the just paused
@@ -1849,7 +1827,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
final boolean isAssistantType = isActivityTypeAssistant();
for (int i = display.getStackCount() - 1; i >= 0; --i) {
final ActivityStack other = display.getStackAt(i);
- final boolean hasRunningActivities = other.topRunningActivityLocked() != null;
+ final boolean hasRunningActivities = other.topRunningActivity() != null;
if (other == this) {
// Should be visible if there is no other stack occluding it, unless it doesn't
// have any running activities, not starting one and not home stack.
@@ -2001,7 +1979,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
@Override
public boolean supportsSplitScreenWindowingMode() {
- final Task topTask = topTask();
+ final Task topTask = getTopMostTask();
return super.supportsSplitScreenWindowingMode()
&& (topTask == null || topTask.supportsSplitScreenWindowingMode());
}
@@ -2185,7 +2163,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
// to ensure any necessary pause logic occurs. In the case where the Activity will be
// shown regardless of the lock screen, the call to
// {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
- final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
+ final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
@@ -2224,7 +2202,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
// Find the next top-most activity to resume in this stack that is not finishing and is
// focusable. If it is not focusable, we will fall into the case below to resume the
// top activity in the next focusable task.
- ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
+ ActivityRecord next = topRunningActivity(true /* focusableOnly */);
final boolean hasRunningActivity = next != null;
@@ -2535,7 +2513,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
// We should be all done, but let's just make sure our activity
// is still at the top and schedule another run if something
// weird happened.
- ActivityRecord nextNext = topRunningActivityLocked();
+ ActivityRecord nextNext = topRunningActivity();
if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
"Activity config changed during resume: " + next
+ ", new next: " + nextNext);
@@ -2672,41 +2650,28 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
Task rTask = r.getTask();
- final int taskId = rTask.mTaskId;
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
+ final boolean hasTask = hasChild(rTask);
// mLaunchTaskBehind tasks get placed at the back of the task stack.
- if (!r.mLaunchTaskBehind && allowMoveToFront
- && (taskForIdLocked(taskId) == null || newTask)) {
+ if (!r.mLaunchTaskBehind && allowMoveToFront && (!hasTask || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
positionChildAtTop(rTask);
}
Task task = null;
- if (!newTask) {
- // If starting in an existing task, find where that is...
- boolean isOccluded = false;
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- task = getChildAt(taskNdx);
- if (task.getTopNonFinishingActivity() == null) {
- // All activities in task are finishing.
- continue;
- }
- if (task == rTask) {
- // Here it is! Now, if this is not yet visible (occluded by another task) to
- // the user, then just add it without starting; it will get started when the
- // user navigates back to it.
- if (isOccluded) {
- if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
- + task, new RuntimeException("here").fillInStackTrace());
- rTask.positionChildAtTop(r);
- ActivityOptions.abort(options);
- return;
- }
- break;
- } else if (!isOccluded) {
- isOccluded = task.getActivity(ActivityRecord::occludesParent) != null;
- }
+ if (!newTask && hasTask) {
+ final ActivityRecord occludingActivity = getActivity(
+ (ar) -> !ar.finishing && ar.occludesParent(), true, rTask);
+ if (occludingActivity != null) {
+ // Here it is! Now, if this is not yet visible (occluded by another task) to the
+ // user, then just add it without starting; it will get started when the user
+ // navigates back to it.
+ if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task,
+ new RuntimeException("here").fillInStackTrace());
+ rTask.positionChildAtTop(r);
+ ActivityOptions.abort(options);
+ return;
}
}
@@ -2892,7 +2857,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
return null;
}
- final ActivityRecord top = stack.topRunningActivityLocked();
+ final ActivityRecord top = stack.topRunningActivity();
if (stack.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) {
// If we will be focusing on the home stack next and its current top activity isn't
@@ -2922,7 +2887,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* not belong to the crashed app.
*/
final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
- ActivityRecord r = topRunningActivityLocked();
+ final ActivityRecord r = topRunningActivity();
if (r == null || r.app != app) {
return null;
}
@@ -3033,12 +2998,11 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
return true;
}
// We now need to get the task below it to determine what to do.
- int taskIdx = mChildren.indexOf(task);
- if (taskIdx <= 0) {
+ final Task prevTask = getTaskBelow(task);
+ if (prevTask == null) {
Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec);
return false;
}
- final Task prevTask = getChildAt(taskIdx);
if (!task.affinity.equals(prevTask.affinity)) {
// These are different apps, so need to recreate.
return true;
@@ -3073,7 +3037,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
// We should consolidate.
IActivityController controller = mService.mController;
if (controller != null) {
- ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
+ ActivityRecord next = topRunningActivity(srec.appToken, INVALID_TASK_ID);
if (next != null) {
// ask watcher if this is allowed
boolean resumeOK = true;
@@ -3287,7 +3251,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
private void updateTransitLocked(int transit, ActivityOptions options) {
if (options != null) {
- ActivityRecord r = topRunningActivityLocked();
+ ActivityRecord r = topRunningActivity();
if (r != null && !r.isState(RESUMED)) {
r.updateOptionsLocked(options);
} else {
@@ -3344,7 +3308,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
// Set focus to the top running activity of this stack.
- final ActivityRecord r = topRunningActivityLocked();
+ final ActivityRecord r = topRunningActivity();
if (r != null) {
r.moveFocusableActivityToTop(reason);
}
@@ -3386,15 +3350,10 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* If a watcher is installed, the action is preflighted and the watcher has an opportunity
* to premeptively cancel the move.
*
- * @param taskId The taskId to collect and move to the bottom.
+ * @param tr The task to collect and move to the bottom.
* @return Returns true if the move completed, false if not.
*/
- final boolean moveTaskToBackLocked(int taskId) {
- final Task tr = taskForIdLocked(taskId);
- if (tr == null) {
- Slog.i(TAG, "moveTaskToBack: bad taskId=" + taskId);
- return false;
- }
+ boolean moveTaskToBack(Task tr) {
Slog.i(TAG, "moveTaskToBack: " + tr);
// In LockTask mode, moving a locked task to the back of the stack may expose unlocked
@@ -3407,9 +3366,9 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
if (isTopStackOnDisplay() && mService.mController != null) {
- ActivityRecord next = topRunningActivityLocked(null, taskId);
+ ActivityRecord next = topRunningActivity(null, tr.mTaskId);
if (next == null) {
- next = topRunningActivityLocked(null, 0);
+ next = topRunningActivity(null, INVALID_TASK_ID);
}
if (next != null) {
// ask watcher if this is allowed
@@ -3426,7 +3385,8 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
}
- if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task="
+ + tr.mTaskId);
getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
moveToBack("moveTaskToBackLocked", tr);
@@ -3471,24 +3431,16 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
try {
// Update override configurations of all tasks in the stack.
final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final Task task = getChildAt(i);
- if (task.isResizeable()) {
- if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) {
- task.setOverrideDisplayedBounds(taskBounds);
- task.setBounds(tempTaskInsetBounds);
- } else {
- task.setOverrideDisplayedBounds(null);
- task.setBounds(taskBounds);
- }
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityStack::processTaskResizeBounds, PooledLambda.__(Task.class),
+ taskBounds, tempTaskInsetBounds);
+ forAllTasks(c);
+ c.recycle();
setBounds(bounds);
if (!deferResume) {
- ensureVisibleActivitiesConfiguration(
- topRunningActivityLocked(), preserveWindows);
+ ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows);
}
} finally {
mService.continueWindowLayout();
@@ -3496,39 +3448,51 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
}
+ private static void processTaskResizeBounds(Task task, Rect bounds, Rect insetBounds) {
+ if (!task.isResizeable()) return;
+
+ if (insetBounds != null && !insetBounds.isEmpty()) {
+ task.setOverrideDisplayedBounds(bounds);
+ task.setBounds(insetBounds);
+ } else {
+ task.setOverrideDisplayedBounds(null);
+ task.setBounds(bounds);
+ }
+ }
+
/**
* Until we can break this "set task bounds to same as stack bounds" behavior, this
* basically resizes both stack and task bounds to the same bounds.
*/
- void setTaskBounds(Rect bounds) {
+ private void setTaskBounds(Rect bounds) {
if (!updateBoundsAllowed(bounds)) {
return;
}
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final Task task = getChildAt(i);
- if (task.isResizeable()) {
- task.setBounds(bounds);
- } else {
- task.setBounds(null);
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskBounds,
+ PooledLambda.__(Task.class), bounds);
+ forAllTasks(c);
+ c.recycle();
+ }
+
+ private static void setTaskBounds(Task task, Rect bounds) {
+ task.setBounds(task.isResizeable() ? bounds : null);
}
/** Helper to setDisplayedBounds on all child tasks */
- void setTaskDisplayedBounds(Rect bounds) {
+ private void setTaskDisplayedBounds(Rect bounds) {
if (!updateDisplayedBoundsAllowed(bounds)) {
return;
}
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final Task task = getChildAt(i);
- if (bounds == null || bounds.isEmpty()) {
- task.setOverrideDisplayedBounds(null);
- } else if (task.isResizeable()) {
- task.setOverrideDisplayedBounds(bounds);
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskDisplayedBounds,
+ PooledLambda.__(Task.class), bounds);
+ forAllTasks(c);
+ c.recycle();
+ }
+
+ private static void setTaskDisplayedBounds(Task task, Rect bounds) {
+ task.setOverrideDisplayedBounds(bounds == null || bounds.isEmpty() ? null : bounds);
}
boolean willActivityBeVisible(IBinder token) {
@@ -3548,56 +3512,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
return !r.finishing;
}
- /**
- * @return The set of running tasks through {@param tasksOut} that are available to the caller.
- * If {@param ignoreActivityType} or {@param ignoreWindowingMode} are not undefined,
- * then skip running tasks that match those types.
- */
- void getRunningTasks(List<Task> tasksOut, @ActivityType int ignoreActivityType,
- @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed,
- boolean crossUser, ArraySet<Integer> profileIds) {
- boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this;
- boolean topTask = true;
- int userId = UserHandle.getUserId(callingUid);
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- if (task.getTopNonFinishingActivity() == null) {
- // Skip if there are no activities in the task
- continue;
- }
- if (task.effectiveUid != callingUid) {
- if (task.mUserId != userId && !crossUser && !profileIds.contains(task.mUserId)) {
- // Skip if the caller does not have cross user permission or cannot access
- // the task's profile
- continue;
- }
- if (!allowed && !task.isActivityTypeHome()) {
- // Skip if the caller isn't allowed to fetch this task, except for the home
- // task which we always return.
- continue;
- }
- }
- if (ignoreActivityType != ACTIVITY_TYPE_UNDEFINED
- && task.getActivityType() == ignoreActivityType) {
- // Skip ignored activity type
- continue;
- }
- if (ignoreWindowingMode != WINDOWING_MODE_UNDEFINED
- && task.getWindowingMode() == ignoreWindowingMode) {
- // Skip ignored windowing mode
- continue;
- }
- if (focusedStack && topTask) {
- // For the focused stack top task, update the last stack active time so that it can
- // be used to determine the order of the tasks (it may not be set for newly created
- // tasks)
- task.touchActiveTime();
- topTask = false;
- }
- tasksOut.add(task);
- }
- }
-
void unhandledBackLocked() {
final ActivityRecord topActivity = getTopMostActivity();
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
@@ -3717,7 +3631,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
ActivityRecord restartPackage(String packageName) {
- ActivityRecord starting = topRunningActivityLocked();
+ ActivityRecord starting = topRunningActivity();
// All activities that came from the package must be
// restarted as if there was a config change.
@@ -3745,7 +3659,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* @param child to remove.
* @param reason for removal.
*/
- void removeChild(Task child, String reason) {
+ void removeChild(WindowContainer child, String reason) {
if (!mChildren.contains(child)) {
// Not really in this stack anymore...
return;
@@ -3757,7 +3671,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
super.removeChild(child);
- EventLogTags.writeWmRemoveTask(child.mTaskId, mStackId);
+ EventLogTags.writeWmRemoveTask(((Task) child).mTaskId, mStackId);
if (display.isSingleTaskInstance()) {
mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
@@ -3767,15 +3681,15 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
if (!hasChild()) {
// Stack is now empty...
- removeIfPossible();
+ removeIfPossible();
}
moveHomeStackToFrontIfNeeded(topFocused, display, reason);
}
@Override
- void removeChild(Task task) {
- removeChild(task, "removeChild");
+ void removeChild(WindowContainer child) {
+ removeChild(child, "removeChild");
}
void moveHomeStackToFrontIfNeeded(
@@ -3816,10 +3730,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
return task;
}
- ArrayList<Task> getAllTasks() {
- return new ArrayList<>(mChildren);
- }
-
void addChild(final Task task, final boolean toTop, boolean showForAllUsers) {
if (isSingleTaskInstance() && hasChild()) {
throw new IllegalStateException("Can only have one child on stack=" + this);
@@ -4015,7 +3925,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
mWindowManager.inSurfaceTransaction(() -> {
- final Task task = mChildren.get(0);
+ final Task task = getBottomMostTask();
setWindowingMode(WINDOWING_MODE_UNDEFINED);
getDisplay().positionStackAtTop(this, false /* includingParents */);
@@ -4026,7 +3936,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
});
}
- void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ private void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
boolean forceUpdate) {
// It is guaranteed that the activities requiring the update will be in the pinned stack at
// this point (either reparented before the animation into PiP, or before reparenting after
@@ -4034,29 +3944,19 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
if (!isAttached()) {
return;
}
- ArrayList<Task> tasks = getAllTasks();
- for (int i = 0; i < tasks.size(); i++) {
- mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
- forceUpdate);
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityStackSupervisor::updatePictureInPictureMode, mStackSupervisor,
+ PooledLambda.__(Task.class), targetStackBounds, forceUpdate);
+ forAllTasks(c);
+ c.recycle();
}
public int getStackId() {
return mStackId;
}
- Task findHomeTask() {
- if (!isActivityTypeHome() || mChildren.isEmpty()) {
- return null;
- }
- return mChildren.get(mChildren.size() - 1);
- }
-
void prepareFreezingTaskBounds() {
- for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = mChildren.get(taskNdx);
- task.prepareFreezingBounds();
- }
+ forAllTasks(Task::prepareFreezingBounds);
}
/**
@@ -4082,24 +3982,17 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
insetBounds = mFullyAdjustedImeBounds;
}
}
- alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : getRawBounds(), insetBounds);
- mDisplayContent.setLayoutNeeded();
-
- updateSurfaceBounds();
- }
- private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
- if (matchParentBounds()) {
- return;
+ if (!matchParentBounds()) {
+ final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::alignToAdjustedBounds,
+ PooledLambda.__(Task.class), adjusted ? mAdjustedBounds : getRawBounds(),
+ insetBounds, alignBottom);
+ c.recycle();
}
- final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
-
- // Update bounds of containing tasks.
- for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = mChildren.get(taskNdx);
- task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
- }
+ mDisplayContent.setLayoutNeeded();
+ updateSurfaceBounds();
}
@Override
@@ -4366,17 +4259,17 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* @param position Target position to add the task to.
* @param showForAllUsers Whether to show the task regardless of the current user.
*/
- void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) {
+ private void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) {
// Add child task.
addChild(task, null);
// Move child to a proper position, as some restriction for position might apply.
- position = positionChildAt(
- position, task, moveParents /* includingParents */, showForAllUsers);
+ positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
}
@Override
- void addChild(Task task, int position) {
+ void addChild(WindowContainer child, int position) {
+ final Task task = (Task) child;
addChild(task, position, task.showForAllUsers(), false /* includingParents */);
}
@@ -4415,14 +4308,15 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
@Override
- void positionChildAt(int position, Task child, boolean includingParents) {
- positionChildAt(position, child, includingParents, child.showForAllUsers());
+ void positionChildAt(int position, WindowContainer child, boolean includingParents) {
+ final Task task = (Task) child;
+ positionChildAt(position, task, includingParents, task.showForAllUsers());
}
/**
- * Overridden version of {@link ActivityStack#positionChildAt(int, Task, boolean)}. Used in
- * {@link ActivityStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can
- * receive showForAllUsers param from {@link ActivityRecord} instead of
+ * Overridden version of {@link ActivityStack#positionChildAt(int, WindowContainer, boolean)}.
+ * Used in {@link ActivityStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it
+ * can receive showForAllUsers param from {@link ActivityRecord} instead of
* {@link Task#showForAllUsers()}.
*/
private int positionChildAt(int position, Task child, boolean includingParents,
@@ -4538,9 +4432,10 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* We will start adjusting up from here.
* @param size The size of the current task list.
*/
+ // TODO(task-hierarchy): Move user to their own window container.
private int computeMinPosition(int minPosition, int size) {
while (minPosition < size) {
- final Task tmpTask = mChildren.get(minPosition);
+ final Task tmpTask = (Task) mChildren.get(minPosition);
final boolean canShowTmpTask =
tmpTask.showForAllUsers()
|| mWmService.isCurrentProfileLocked(tmpTask.mUserId);
@@ -4557,9 +4452,10 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* @param maxPosition The maximum position the caller is suggesting.
* We will start adjusting down from here.
*/
+ // TODO(task-hierarchy): Move user to their own window container.
private int computeMaxPosition(int maxPosition) {
while (maxPosition > 0) {
- final Task tmpTask = mChildren.get(maxPosition);
+ final Task tmpTask = (Task) mChildren.get(maxPosition);
final boolean canShowTmpTask =
tmpTask.showForAllUsers()
|| mWmService.isCurrentProfileLocked(tmpTask.mUserId);
@@ -4664,7 +4560,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
// When the home stack is resizable, should always have the same stack and task bounds
if (isActivityTypeHome()) {
- final Task homeTask = findHomeTask();
+ final Task homeTask = getTopMostTask();
if (homeTask == null || homeTask.isResizeable()) {
// Calculate the home stack bounds when in docked mode and the home stack is
// resizeable.
@@ -4894,25 +4790,20 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* to the list of to be drawn windows the service is waiting for.
*/
void beginImeAdjustAnimation() {
- for (int j = mChildren.size() - 1; j >= 0; j--) {
- final Task task = mChildren.get(j);
- if (task.hasContentToDisplay()) {
- task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
- task.setWaitingForDrawnIfResizingChanged();
+ forAllTasks((t) -> {
+ if (t.hasContentToDisplay()) {
+ t.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+ t.setWaitingForDrawnIfResizingChanged();
}
- }
+ });
}
- /**
- * Resets the resizing state of all windows.
- */
+ /** Resets the resizing state of all windows. */
void endImeAdjustAnimation() {
- for (int j = mChildren.size() - 1; j >= 0; j--) {
- mChildren.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
- }
+ forAllTasks((t) -> { t.setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER); });
}
- int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
+ private int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
return displayContentRect.top + (int)
((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
}
@@ -5024,7 +4915,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
return true;
}
- private boolean isMinimizedDockAndHomeStackResizable() {
+ boolean isMinimizedDockAndHomeStackResizable() {
return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
&& mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
}
@@ -5092,13 +4983,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
* recents animation); {@code false} otherwise.
*/
boolean isTaskAnimating() {
- for (int j = mChildren.size() - 1; j >= 0; j--) {
- final Task task = mChildren.get(j);
- if (task.isTaskAnimating()) {
- return true;
- }
- }
- return false;
+ return getTask(Task::isTaskAnimating) != null;
}
@Override
@@ -5173,102 +5058,11 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
boolean hasTaskForUser(int userId) {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final Task task = mChildren.get(i);
- if (task.mUserId == userId) {
- return true;
- }
- }
- return false;
- }
-
- void findTaskForResizePoint(int x, int y, int delta,
- DisplayContent.TaskForResizePointSearchResult results) {
- if (!getWindowConfiguration().canResizeTask()) {
- results.searchDone = true;
- return;
- }
-
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task task = mChildren.get(i);
- if (task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- results.searchDone = true;
- return;
- }
-
- // We need to use the task's dim bounds (which is derived from the visible bounds of
- // its apps windows) for any touch-related tests. Can't use the task's original
- // bounds because it might be adjusted to fit the content frame. One example is when
- // the task is put to top-left quadrant, the actual visible area would not start at
- // (0,0) after it's adjusted for the status bar.
- task.getDimBounds(mTmpRect);
- mTmpRect.inset(-delta, -delta);
- if (mTmpRect.contains(x, y)) {
- mTmpRect.inset(delta, delta);
-
- results.searchDone = true;
-
- if (!mTmpRect.contains(x, y)) {
- results.taskForResize = task;
- return;
- }
- // User touched inside the task. No need to look further,
- // focus transfer will be handled in ACTION_UP.
- return;
- }
- }
- }
-
- void setTouchExcludeRegion(Task focusedTask, int delta, Region touchExcludeRegion,
- Rect contentRect, Rect postExclude) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task task = mChildren.get(i);
- ActivityRecord topVisibleActivity = task.getTopVisibleActivity();
- if (topVisibleActivity == null || !topVisibleActivity.hasContentToDisplay()) {
- continue;
- }
-
- /**
- * Exclusion region is the region that TapDetector doesn't care about.
- * Here we want to remove all non-focused tasks from the exclusion region.
- * We also remove the outside touch area for resizing for all freeform
- * tasks (including the focused).
- *
- * We save the focused task region once we find it, and add it back at the end.
- *
- * If the task is home stack and it is resizable in the minimized state, we want to
- * exclude the docked stack from touch so we need the entire screen area and not just a
- * small portion which the home stack currently is resized to.
- */
-
- if (task.isActivityTypeHome() && isMinimizedDockAndHomeStackResizable()) {
- mDisplayContent.getBounds(mTmpRect);
- } else {
- task.getDimBounds(mTmpRect);
- }
-
- if (task == focusedTask) {
- // Add the focused task rect back into the exclude region once we are done
- // processing stacks.
- postExclude.set(mTmpRect);
- }
-
- final boolean isFreeformed = task.inFreeformWindowingMode();
- if (task != focusedTask || isFreeformed) {
- if (isFreeformed) {
- // If the task is freeformed, enlarge the area to account for outside
- // touch area for resize.
- mTmpRect.inset(-delta, -delta);
- // Intersect with display content rect. If we have system decor (status bar/
- // navigation bar), we want to exclude that from the tap detection.
- // Otherwise, if the app is partially placed under some system button (eg.
- // Recents, Home), pressing that button would cause a full series of
- // unwanted transfer focus/resume/pause, before we could go home.
- mTmpRect.intersect(contentRect);
- }
- touchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
- }
- }
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ Task::isTaskForUser, PooledLambda.__(Task.class), userId);
+ final Task task = getTask(p);
+ p.recycle();
+ return task != null;
}
public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) {
@@ -5429,10 +5223,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
/** Called immediately prior to resizing the tasks at the end of the pinned stack animation. */
void onPipAnimationEndResize() {
mBoundsAnimating = false;
- for (int i = 0; i < mChildren.size(); i++) {
- final Task t = mChildren.get(i);
- t.clearPreserveNonFloatingState();
- }
+ forAllTasks(Task::clearPreserveNonFloatingState, false);
mWmService.requestTraversal();
}
@@ -5453,7 +5244,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
if (homeStack == null) {
return true;
}
- final Task homeTask = homeStack.getTopChild();
+ final Task homeTask = homeStack.getTopMostTask();
if (homeTask == null) {
return true;
}
@@ -5585,7 +5376,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
@Override
void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
Rect outSurfaceInsets) {
- final Task task = getTopChild();
+ final Task task = getTopMostTask();
if (task != null) {
task.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
} else {
@@ -5596,7 +5387,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
@Override
RemoteAnimationTarget createRemoteAnimationTarget(
RemoteAnimationController.RemoteAnimationRecord record) {
- final Task task = getTopChild();
+ final Task task = getTopMostTask();
return task != null ? task.createRemoteAnimationTarget(record) : null;
}
@@ -5611,12 +5402,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
+ getChildCount() + " tasks}";
}
- void onLockTaskPackagesUpdated() {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- getChildAt(taskNdx).setLockTaskAuth();
- }
- }
-
void executeAppTransition(ActivityOptions options) {
getDisplay().mDisplayContent.executeAppTransition();
ActivityOptions.abort(options);
@@ -5644,10 +5429,10 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
final long token = proto.start(fieldId);
dumpDebugInnerStackOnly(proto, STACK, logLevel);
proto.write(com.android.server.am.ActivityStackProto.ID, mStackId);
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- task.dumpDebug(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel);
- }
+
+ forAllTasks((t) -> {
+ t.dumpDebug(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel);
+ });
if (mResumedActivity != null) {
mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
}
@@ -5672,9 +5457,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
proto.write(StackProto.ID, mStackId);
- for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
- mChildren.get(taskNdx).dumpDebugInnerTaskOnly(proto, StackProto.TASKS, logLevel);
- }
+ forAllTasks((t) -> { t.dumpDebugInnerTaskOnly(proto, StackProto.TASKS, logLevel); });
proto.write(FILLS_PARENT, matchParentBounds());
getRawBounds().dumpDebug(proto, StackProto.BOUNDS);
proto.write(DEFER_REMOVAL, mDeferRemoval);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 735636867d09..8c5fd8cc89a1 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -165,28 +165,28 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
static final String TAG_TASKS = TAG + POSTFIX_TASKS;
/** How long we wait until giving up on the last activity telling us it is idle. */
- static final int IDLE_TIMEOUT = 10 * 1000;
+ private static final int IDLE_TIMEOUT = 10 * 1000;
/** How long we can hold the sleep wake lock before giving up. */
- static final int SLEEP_TIMEOUT = 5 * 1000;
+ private static final int SLEEP_TIMEOUT = 5 * 1000;
// How long we can hold the launch wake lock before giving up.
- static final int LAUNCH_TIMEOUT = 10 * 1000;
+ private static final int LAUNCH_TIMEOUT = 10 * 1000;
/** How long we wait until giving up on the activity telling us it released the top state. */
- static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500;
-
- static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG;
- static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_STACK_MSG + 1;
- static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
- static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
- static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
- static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 12;
- static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 13;
- static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14;
- static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 15;
- static final int REPORT_HOME_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 16;
- static final int TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 17;
+ private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500;
+
+ private static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG;
+ private static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_STACK_MSG + 1;
+ private static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
+ private static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
+ private static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
+ private static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 12;
+ private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 13;
+ private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14;
+ private static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 15;
+ private static final int REPORT_HOME_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 16;
+ private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 17;
// Used to indicate that windows of activities should be preserved during the resize.
static final boolean PRESERVE_WINDOWS = true;
@@ -237,7 +237,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// For debugging to make sure the caller when acquiring/releasing our
// wake lock is the system process.
- static final boolean VALIDATE_WAKE_LOCK_CALLER = false;
+ private static final boolean VALIDATE_WAKE_LOCK_CALLER = false;
/** The number of distinct task ids that can be assigned to the tasks of a single user */
private static final int MAX_TASK_IDS_PER_USER = UserHandle.PER_USER_RANGE;
@@ -250,11 +250,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
/** Helper class to abstract out logic for fetching the set of currently running tasks */
private RunningTasks mRunningTasks;
- final ActivityStackSupervisorHandler mHandler;
+ private final ActivityStackSupervisorHandler mHandler;
final Looper mLooper;
/** Short cut */
- WindowManagerService mWindowManager;
+ private WindowManagerService mWindowManager;
/** Common synchronization logic used to save things to disks. */
PersisterQueue mPersisterQueue;
@@ -286,11 +286,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
/** List of activities whose multi-window mode changed that we need to report to the
* application */
- final ArrayList<ActivityRecord> mMultiWindowModeChangedActivities = new ArrayList<>();
+ private final ArrayList<ActivityRecord> mMultiWindowModeChangedActivities = new ArrayList<>();
/** List of activities whose picture-in-picture mode changed that we need to report to the
* application */
- final ArrayList<ActivityRecord> mPipModeChangedActivities = new ArrayList<>();
+ private final ArrayList<ActivityRecord> mPipModeChangedActivities = new ArrayList<>();
/**
* Animations that for the current transition have requested not to
@@ -312,7 +312,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
/** The target stack bounds for the picture-in-picture mode changed that we need to report to
* the application */
- Rect mPipModeChangedTargetStackBounds;
+ private Rect mPipModeChangedTargetStackBounds;
/** Used on user changes */
final ArrayList<UserState> mStartingUsers = new ArrayList<>();
@@ -398,6 +398,52 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
private boolean mInitialized;
+ private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper =
+ new MoveTaskToFullscreenHelper();
+ private class MoveTaskToFullscreenHelper {
+ private ActivityDisplay mToDisplay;
+ private boolean mOnTop;
+ private Task mTopTask;
+ private boolean mSchedulePictureInPictureModeChange;
+
+ void process(ActivityStack fromStack, ActivityDisplay toDisplay, boolean onTop,
+ boolean schedulePictureInPictureModeChange) {
+ mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange;
+ mToDisplay = toDisplay;
+ mOnTop = onTop;
+ mTopTask = fromStack.getTopMostTask();
+
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ MoveTaskToFullscreenHelper::processTask, this, PooledLambda.__(Task.class));
+ fromStack.forAllTasks(c, false);
+ c.recycle();
+ mToDisplay = null;
+ mTopTask = null;
+ }
+
+ private void processTask(Task task) {
+ final ActivityStack toStack = mToDisplay.getOrCreateStack(
+ null, mTmpOptions, task, task.getActivityType(), mOnTop);
+
+ if (mOnTop) {
+ final boolean isTopTask = task == mTopTask;
+ // Defer resume until all the tasks have been moved to the fullscreen stack
+ task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, isTopTask /*animate*/,
+ DEFER_RESUME, mSchedulePictureInPictureModeChange,
+ "moveTasksToFullscreenStack - onTop");
+ MetricsLoggerWrapper.logPictureInPictureFullScreen(mService.mContext,
+ task.effectiveUid, task.realActivity.flattenToString());
+ } else {
+ // Position the tasks in the fullscreen stack in order at the bottom of the
+ // stack. Also defer resume until all the tasks have been moved to the
+ // fullscreen stack.
+ task.reparent(toStack, ON_TOP, REPARENT_LEAVE_STACK_IN_PLACE,
+ !ANIMATE, DEFER_RESUME, mSchedulePictureInPictureModeChange,
+ "moveTasksToFullscreenStack - NOT_onTop");
+ }
+ }
+ }
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -1522,35 +1568,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// the picture-in-picture mode.
final boolean schedulePictureInPictureModeChange =
windowingMode == WINDOWING_MODE_PINNED;
- final ArrayList<Task> tasks = fromStack.getAllTasks();
- if (!tasks.isEmpty()) {
+ if (fromStack.hasChild()) {
mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
- final int size = tasks.size();
- for (int i = 0; i < size; ++i) {
- final Task task = tasks.get(i);
- final ActivityStack toStack = toDisplay.getOrCreateStack(
- null, mTmpOptions, task, task.getActivityType(), onTop);
-
- if (onTop) {
- final boolean isTopTask = i == (size - 1);
- // Defer resume until all the tasks have been moved to the fullscreen stack
- task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
- isTopTask /* animate */, DEFER_RESUME,
- schedulePictureInPictureModeChange,
- "moveTasksToFullscreenStack - onTop");
- MetricsLoggerWrapper.logPictureInPictureFullScreen(mService.mContext,
- task.effectiveUid, task.realActivity.flattenToString());
- } else {
- // Position the tasks in the fullscreen stack in order at the bottom of the
- // stack. Also defer resume until all the tasks have been moved to the
- // fullscreen stack.
- task.reparent(toStack, ON_TOP,
- REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME,
- schedulePictureInPictureModeChange,
- "moveTasksToFullscreenStack - NOT_onTop");
- }
- }
+ mMoveTaskToFullscreenHelper.process(
+ fromStack, toDisplay, onTop, schedulePictureInPictureModeChange);
}
mRootActivityContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
@@ -1562,12 +1584,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) {
- moveTasksToFullscreenStackLocked(fromStack, DEFAULT_DISPLAY, onTop);
- }
-
- void moveTasksToFullscreenStackLocked(ActivityStack fromStack, int toDisplayId, boolean onTop) {
mWindowManager.inSurfaceTransaction(() ->
- moveTasksToFullscreenStackInSurfaceTransaction(fromStack, toDisplayId, onTop));
+ moveTasksToFullscreenStackInSurfaceTransaction(fromStack, DEFAULT_DISPLAY, onTop));
}
void setSplitScreenResizing(boolean resizing) {
@@ -1630,7 +1648,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
try {
// Don't allow re-entry while resizing. E.g. due to docked stack detaching.
mAllowDockedStackResize = false;
- ActivityRecord r = stack.topRunningActivityLocked();
+ ActivityRecord r = stack.topRunningActivity();
stack.resize(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
!PRESERVE_WINDOWS, DEFER_RESUME);
@@ -1731,7 +1749,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
private void removeStackInSurfaceTransaction(ActivityStack stack) {
- final ArrayList<Task> tasks = stack.getAllTasks();
if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) {
/**
* Workaround: Force-stop all the activities in the pinned stack before we reparent them
@@ -1746,18 +1763,22 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
stack.mForceHidden = false;
activityIdleInternalLocked(null, false /* fromTimeout */,
- true /* processPausingActivites */, null /* configuration */);
+ true /* processPausingActivities */, null /* configuration */);
// Move all the tasks to the bottom of the fullscreen stack
moveTasksToFullscreenStackLocked(stack, !ON_TOP);
} else {
- for (int i = tasks.size() - 1; i >= 0; i--) {
- removeTaskByIdLocked(tasks.get(i).mTaskId, true /* killProcess */,
- REMOVE_FROM_RECENTS, "remove-stack");
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityStackSupervisor::processRemoveTask, this, PooledLambda.__(Task.class));
+ stack.forAllTasks(c);
+ c.recycle();
}
}
+ private void processRemoveTask(Task task) {
+ removeTask(task, true /* killProcess */, REMOVE_FROM_RECENTS, "remove-stack");
+ }
+
/**
* Removes the stack associated with the given {@param stack}. If the {@param stack} is the
* pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
@@ -1775,24 +1796,28 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
* @param removeFromRecents Whether to also remove the task from recents.
* @return Returns true if the given task was found and removed.
*/
- boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
+ boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,
String reason) {
final Task task =
mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task != null) {
- task.removeTaskActivitiesLocked(reason);
- cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
- mService.getLockTaskController().clearLockedTask(task);
- mService.getTaskChangeNotificationController().notifyTaskStackChanged();
- if (task.isPersistable) {
- mService.notifyTaskPersisterLocked(null, true);
- }
+ removeTask(task, killProcess, removeFromRecents, reason);
return true;
}
Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
return false;
}
+ void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason) {
+ task.removeTaskActivitiesLocked(reason);
+ cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
+ mService.getLockTaskController().clearLockedTask(task);
+ mService.getTaskChangeNotificationController().notifyTaskStackChanged();
+ if (task.isPersistable) {
+ mService.notifyTaskPersisterLocked(null, true);
+ }
+ }
+
void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
if (removeFromRecents) {
mRecentTasks.remove(task);
@@ -1899,7 +1924,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
if (wasTrimmed) {
// Task was trimmed from the recent tasks list -- remove the active task record as well
// since the user won't really be able to go back to it
- removeTaskByIdLocked(task.mTaskId, killProcess, false /* removeFromRecents */,
+ removeTaskById(task.mTaskId, killProcess, false /* removeFromRecents */,
"recent-task-trimmed");
}
task.removedFromRecents();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index baa295518c2d..23083c9fb7f7 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1434,7 +1434,7 @@ class ActivityStarter {
// If there is no state change (e.g. a resumed activity is reparented to top of
// another display) to trigger a visibility/configuration checking, we have to
// update the configuration for changing to different display.
- final ActivityRecord currentTop = startedActivityStack.topRunningActivityLocked();
+ final ActivityRecord currentTop = startedActivityStack.topRunningActivity();
if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) {
mRootActivityContainer.ensureVisibilityAndConfig(
currentTop, currentTop.getDisplayId(),
@@ -2307,7 +2307,7 @@ class ActivityStarter {
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final Task topTask = curTop != null ? curTop.getTask() : null;
differentTopTask = topTask != intentActivity.getTask()
- || (focusStack != null && topTask != focusStack.topTask());
+ || (focusStack != null && topTask != focusStack.getTopMostTask());
} else {
// The existing task should always be different from those in other displays.
differentTopTask = true;
@@ -2371,7 +2371,7 @@ class ActivityStarter {
mMovedToFront = true;
}
- if (launchStack != null && launchStack.topTask() == null) {
+ if (launchStack != null && launchStack.getTopMostTask() == null) {
// The task does not need to be reparented to the launch stack. Remove the
// launch stack if there is no activity in it.
Slog.w(TAG, "Removing an empty stack: " + launchStack);
@@ -2588,7 +2588,7 @@ class ActivityStarter {
// If task's parent stack is not focused - use it during adjacent launch.
return parentStack;
} else {
- if (focusedStack != null && task == focusedStack.topTask()) {
+ if (focusedStack != null && task == focusedStack.getTopMostTask()) {
// If task is already on top of focused stack - use it. We don't want to move the
// existing focused task to adjacent stack, just deliver new intent in this case.
return focusedStack;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index efd21ec83924..46c4d874cb53 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -698,7 +698,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private final Runnable mUpdateOomAdjRunnable = new Runnable() {
@Override
- public void run() {
+ public void run() {
mAmInternal.updateOomAdj();
}
};
@@ -1591,7 +1591,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// We should consolidate.
if (mController != null) {
// Find the first activity that is not finishing.
- final ActivityRecord next = r.getActivityStack().topRunningActivityLocked(token, 0);
+ final ActivityRecord next =
+ r.getActivityStack().topRunningActivity(token, INVALID_TASK_ID);
if (next != null) {
// ask watcher if this is allowed
boolean resumeOK = true;
@@ -1628,11 +1629,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// because we don't support returning them across task boundaries. Also, to
// keep backwards compatibility we remove the task from recents when finishing
// task with root activity.
- res = mStackSupervisor.removeTaskByIdLocked(tr.mTaskId, false /* killProcess */,
+ mStackSupervisor.removeTask(tr, false /*killProcess*/,
finishWithRootActivity, "finish-activity");
- if (!res) {
- Slog.i(TAG, "Removing task failed to finish activity");
- }
+ res = true;
// Explicitly dismissing the activity so reset its relaunch flag.
r.mRelaunchReason = RELAUNCH_REASON_NONE;
} else {
@@ -1901,7 +1900,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public boolean isTopActivityImmersive() {
enforceNotIsolatedCaller("isTopActivityImmersive");
synchronized (mGlobalLock) {
- final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivityLocked();
+ final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
return (r != null) ? r.immersive : false;
}
}
@@ -1931,7 +1930,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public int getFrontActivityScreenCompatMode() {
enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
synchronized (mGlobalLock) {
- final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivityLocked();
+ final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
if (r == null) {
return ActivityManager.COMPAT_MODE_UNKNOWN;
}
@@ -1945,7 +1944,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"setFrontActivityScreenCompatMode");
ApplicationInfo ai;
synchronized (mGlobalLock) {
- final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivityLocked();
+ final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
if (r == null) {
Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
return;
@@ -2078,7 +2077,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Slog.w(TAG, "setFocusedStack: No stack with id=" + stackId);
return;
}
- final ActivityRecord r = stack.topRunningActivityLocked();
+ final ActivityRecord r = stack.topRunningActivity();
if (r != null && r.moveFocusableActivityToTop("setFocusedStack")) {
mRootActivityContainer.resumeFocusedStacksTopActivities();
}
@@ -2133,7 +2132,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
- return mStackSupervisor.removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS,
+ return mStackSupervisor.removeTaskById(taskId, true, REMOVE_FROM_RECENTS,
"remove-task");
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2207,7 +2206,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
final Task task = mRootActivityContainer.anyTaskForId(taskId);
if (task != null) {
- return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId);
+ return ActivityRecord.getStackLocked(token).moveTaskToBack(task);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2918,7 +2917,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();
- if (stack == null || task != stack.topTask()) {
+ if (stack == null || task != stack.getTopMostTask()) {
throw new IllegalArgumentException("Invalid task, not in foreground");
}
@@ -5787,7 +5786,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// If the configuration changed, and the caller is not already
// in the process of starting an activity, then find the top
// activity to check if its configuration needs to change.
- starting = mainStack.topRunningActivityLocked();
+ starting = mainStack.topRunningActivity();
}
if (starting != null) {
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 93a22caa2757..6d9584c50b9c 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -62,7 +62,7 @@ class AppTaskImpl extends IAppTask.Stub {
long origId = Binder.clearCallingIdentity();
try {
// We remove the task from recents to preserve backwards
- if (!mService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false,
+ if (!mService.mStackSupervisor.removeTaskById(mTaskId, false,
REMOVE_FROM_RECENTS, "finish-and-remove-task")) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index e0c5fd055e7e..3a33a3d24433 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -130,6 +130,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils.Dump;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.AttributeCache;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.animation.ClipRectLRAnimation;
@@ -1897,7 +1898,10 @@ public class AppTransition implements Dump {
for (int i = 0; i < specs.length; i++) {
AppTransitionAnimationSpec spec = specs[i];
if (spec != null) {
- final WindowContainer container = findTask(spec.taskId);
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ Task::isTaskId, PooledLambda.__(Task.class), spec.taskId);
+ final WindowContainer container = mDisplayContent.getTask(p);
+ p.recycle();
if (container == null) {
continue;
}
@@ -1918,21 +1922,6 @@ public class AppTransition implements Dump {
}
}
- private Task findTask(int taskId) {
- if (taskId < 0) {
- return null;
- }
- final ArrayList<Task> tasks = new ArrayList<>();
- mDisplayContent.forAllTasks(task -> {
- if (task.mTaskId == taskId) {
- tasks.add(task);
- return true;
- }
- return false;
- });
- return tasks.size() == 1 ? tasks.get(0) : null;
- }
-
void overridePendingAppTransitionMultiThumbFuture(
IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
boolean scaleUp) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index d7f4b34ba56d..6ea0650df37a 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -48,6 +48,8 @@ import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_S
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -61,6 +63,7 @@ import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager.TransitionType;
import android.view.animation.Animation;
import com.android.internal.annotations.VisibleForTesting;
@@ -177,9 +180,15 @@ public class AppTransitionController {
final int layoutRedo;
mService.mSurfaceAnimationRunner.deferStartingAnimations();
try {
- handleClosingApps(transit, animLp, voiceInteraction);
- handleOpeningApps(transit, animLp, voiceInteraction);
- handleChangingApps(transit, animLp, voiceInteraction);
+ // TODO: Apply an app transition animation on TaskStack instead of ActivityRecord when
+ // appropriate.
+ applyAnimations(mDisplayContent.mClosingApps, transit, false /* visible */,
+ animLp, voiceInteraction);
+ applyAnimations(mDisplayContent.mOpeningApps, transit, true /* visible */,
+ animLp, voiceInteraction);
+ handleClosingApps();
+ handleOpeningApps();
+ handleChangingApps(transit);
appTransition.setLastAppTransition(transit, topOpeningApp,
topClosingApp, topChangingApp);
@@ -227,8 +236,8 @@ public class AppTransitionController {
return mainWindow != null ? mainWindow.mAttrs : null;
}
- RemoteAnimationAdapter getRemoteAnimationOverride(ActivityRecord animLpActivity, int transit,
- ArraySet<Integer> activityTypes) {
+ RemoteAnimationAdapter getRemoteAnimationOverride(ActivityRecord animLpActivity,
+ @TransitionType int transit, ArraySet<Integer> activityTypes) {
final RemoteAnimationDefinition definition = animLpActivity.getRemoteAnimationDefinition();
if (definition != null) {
final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
@@ -246,8 +255,8 @@ public class AppTransitionController {
* Overrides the pending transition with the remote animation defined for the transition in the
* set of defined remote animations in the app window token.
*/
- private void overrideWithRemoteAnimationIfSet(ActivityRecord animLpActivity, int transit,
- ArraySet<Integer> activityTypes) {
+ private void overrideWithRemoteAnimationIfSet(ActivityRecord animLpActivity,
+ @TransitionType int transit, ArraySet<Integer> activityTypes) {
if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
// The crash transition has higher priority than any involved remote animations.
return;
@@ -266,7 +275,7 @@ public class AppTransitionController {
/**
* @return The window token that determines the animation theme.
*/
- private ActivityRecord findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
+ private ActivityRecord findAnimLayoutParamsToken(@TransitionType int transit,
ArraySet<Integer> activityTypes) {
ActivityRecord result;
final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
@@ -340,26 +349,60 @@ public class AppTransitionController {
return false;
}
- private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
+ /**
+ * Apply an app transition animation on a set of {@link ActivityRecord}
+ *
+ * @param apps The list of apps to which an app transition animation applies.
+ * @param transit The current transition type.
+ * @param visible {@code true} if the apps becomes visible, {@code false} if the apps becomes
+ * invisible.
+ * @param animLp Layout parameters in which an app transition animation runs.
+ * @param voiceInteraction {@code true} if one of the apps in this transition belongs to a voice
+ * interaction session driving task.
+ */
+ private void applyAnimations(ArraySet<ActivityRecord> apps, @TransitionType int transit,
+ boolean visible, LayoutParams animLp, boolean voiceInteraction) {
+ final int appsCount = apps.size();
+ for (int i = 0; i < appsCount; i++) {
+ final ActivityRecord app = apps.valueAt(i);
+ if (transit != WindowManager.TRANSIT_UNSET && app.shouldApplyAnimation(visible)) {
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Changing app %s visible=%b performLayout=%b",
+ app, app.isVisible(), false);
+ if (!app.mUseTransferredAnimation) {
+ app.applyAnimation(animLp, transit, visible, voiceInteraction);
+ }
+ final WindowState window = app.findMainWindow();
+ final AccessibilityController accessibilityController =
+ app.mWmService.mAccessibilityController;
+ if (window != null && accessibilityController != null) {
+ accessibilityController.onAppWindowTransitionLocked(window, transit);
+ }
+ }
+ }
+ }
+
+ private void handleOpeningApps() {
final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
final int appsCount = openingApps.size();
+
for (int i = 0; i < appsCount; i++) {
- ActivityRecord wtoken = openingApps.valueAt(i);
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", wtoken);
+ final ActivityRecord app = openingApps.valueAt(i);
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app);
- if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
+ app.commitVisibility(true /* visible */, false /* performLayout */);
+ if (!app.isAnimating(PARENTS | CHILDREN)) {
// This token isn't going to be animating. Add it to the list of tokens to
// be notified of app transition complete since the notification will not be
// sent be the app window animator.
- mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
+ mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(app.token);
}
- wtoken.updateReportedVisibilityLocked();
- wtoken.waitingToShow = false;
+ app.updateReportedVisibilityLocked();
+ app.waitingToShow = false;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION handleAppTransitionReady()");
mService.openSurfaceTransaction();
try {
- wtoken.showAllWindowsLocked();
+ app.showAllWindowsLocked();
} finally {
mService.closeSurfaceTransaction("handleAppTransitionReady");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
@@ -367,41 +410,40 @@ public class AppTransitionController {
}
if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
- wtoken.attachThumbnailAnimation();
+ app.attachThumbnailAnimation();
} else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
- wtoken.attachCrossProfileAppsThumbnailAnimation();
+ app.attachCrossProfileAppsThumbnailAnimation();
}
}
}
- private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
+ private void handleClosingApps() {
final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
final int appsCount = closingApps.size();
+
for (int i = 0; i < appsCount; i++) {
- ActivityRecord wtoken = closingApps.valueAt(i);
+ final ActivityRecord app = closingApps.valueAt(i);
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", app);
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", wtoken);
- // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
- // animating?
- wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
- wtoken.updateReportedVisibilityLocked();
+ app.commitVisibility(false /* visible */, false /* performLayout */);
+ app.updateReportedVisibilityLocked();
// Force the allDrawn flag, because we want to start
// this guy's animations regardless of whether it's
// gotten drawn.
- wtoken.allDrawn = true;
+ app.allDrawn = true;
// Ensure that apps that are mid-starting are also scheduled to have their
// starting windows removed after the animation is complete
- if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
- wtoken.removeStartingWindow();
+ if (app.startingWindow != null && !app.startingWindow.mAnimatingExit) {
+ app.removeStartingWindow();
}
if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
- wtoken.attachThumbnailAnimation();
+ app.attachThumbnailAnimation();
}
}
}
- private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
+ private void handleChangingApps(@TransitionType int transit) {
final ArraySet<ActivityRecord> apps = mDisplayContent.mChangingApps;
final int appsCount = apps.size();
for (int i = 0; i < appsCount; i++) {
@@ -419,7 +461,7 @@ public class AppTransitionController {
}
}
- private void handleNonAppWindowsInTransition(int transit, int flags) {
+ private void handleNonAppWindowsInTransition(@TransitionType int transit, int flags) {
if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
&& (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
@@ -510,8 +552,8 @@ public class AppTransitionController {
return true;
}
- private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
- boolean closingAppHasWallpaper) {
+ private int maybeUpdateTransitToWallpaper(@TransitionType int transit,
+ boolean openingAppHasWallpaper, boolean closingAppHasWallpaper) {
// Given no app transition pass it through instead of a wallpaper transition.
// Never convert the crashing transition.
// Never update the transition for the wallpaper if we are just docking from recents
@@ -604,7 +646,7 @@ public class AppTransitionController {
* situation.
*/
@VisibleForTesting
- int maybeUpdateTransitToTranslucentAnim(int transit) {
+ int maybeUpdateTransitToTranslucentAnim(@TransitionType int transit) {
if (AppTransition.isChangeTransit(transit)) {
// There's no special animation to handle change animations with translucent apps
return transit;
@@ -644,7 +686,7 @@ public class AppTransitionController {
* to determine whether animations should be clipped to the task bounds instead of stack bounds.
*/
@VisibleForTesting
- boolean isTransitWithinTask(int transit, Task task) {
+ boolean isTransitWithinTask(@TransitionType int transit, Task task) {
if (task == null
|| !mDisplayContent.mChangingApps.isEmpty()) {
// if there is no task, then we can't constrain to the task.
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index bfa72e0eff78..bd0ea3d06853 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -81,9 +81,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
*/
private Configuration mFullConfiguration = new Configuration();
- /** The bit mask of the last override fields of full configuration. */
- private int mLastOverrideConfigurationChanges;
-
/**
* Contains merged override configuration settings from the top of the hierarchy down to this
* particular instance. It is different from {@link #mFullConfiguration} because it starts from
@@ -121,11 +118,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return mFullConfiguration;
}
- /** Returns the last changes from applying override configuration. */
- int getLastOverrideConfigurationChanges() {
- return mLastOverrideConfigurationChanges;
- }
-
/**
* Notify that parent config changed and we need to update full configuration.
* @see #mFullConfiguration
@@ -141,8 +133,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
resolveOverrideConfiguration(newParentConfig);
mFullConfiguration.setTo(newParentConfig);
- mLastOverrideConfigurationChanges =
- mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
+ mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
onMergedOverrideConfigurationChanged();
// This depends on the assumption that change-listeners don't do
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8e126b56a736..aa0e97318eed 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -55,9 +55,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
-import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
@@ -93,6 +92,7 @@ import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
import static com.android.server.wm.DisplayContentProto.ID;
import static com.android.server.wm.DisplayContentProto.IME_WINDOWS;
import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
+import static com.android.server.wm.DisplayContentProto.OVERLAY_WINDOWS;
import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER;
import static com.android.server.wm.DisplayContentProto.ROTATION;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
@@ -194,6 +194,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.function.TriConsumer;
import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AnimationThread;
import com.android.server.policy.WindowManagerPolicy;
@@ -240,7 +241,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
/** Unique identifier of this display. */
private final int mDisplayId;
- /** The containers below are the only child containers the display can have. */
+ /**
+ * Most surfaces will be a child of this window. There are some special layers and windows
+ * which are always on top of others and omitted from Screen-Magnification, for example the
+ * strict mode flash or the magnification overlay itself. Those layers will be children of
+ * {@link #mOverlayContainers} where mWindowContainers contains everything else.
+ */
+ private final WindowContainers mWindowContainers =
+ new WindowContainers("mWindowContainers", mWmService);
+
+ // Contains some special windows which are always on top of others and omitted from
+ // Screen-Magnification, for example the WindowMagnification windows.
+ private final NonAppWindowContainers mOverlayContainers =
+ new NonAppWindowContainers("mOverlayContainers", mWmService);
+
+ /** The containers below are the only child containers {@link #mWindowContainers} can have. */
// Contains all window containers that are related to apps (Activities)
private final TaskStackContainers mTaskStackContainers = new TaskStackContainers(mWmService);
// Contains all non-app window containers that should be displayed above the app containers
@@ -260,7 +275,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private WindowState mTmpWindow;
private WindowState mTmpWindow2;
- private boolean mTmpRecoveringMemory;
private boolean mUpdateImeTarget;
private boolean mTmpInitial;
private int mMaxUiWidth;
@@ -346,6 +360,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
/** The desired scaling factor for compatible apps. */
float mCompatibleScreenScale;
+ /** @see #getCurrentOverrideConfigurationChanges */
+ private int mCurrentOverrideConfigurationChanges;
+
/**
* Orientation forced by some window. If there is no visible window that specifies orientation
* it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
@@ -490,20 +507,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private ScreenRotationAnimation mScreenRotationAnimation;
/**
- * We organize all top-level Surfaces in to the following layers.
- * mOverlayLayer contains a few Surfaces which are always on top of others
- * and omitted from Screen-Magnification, for example the strict mode flash or
- * the magnification overlay itself.
- * {@link #mWindowingLayer} contains everything else.
- */
- private SurfaceControl mOverlayLayer;
-
- /**
- * See {@link #mOverlayLayer}
- */
- private SurfaceControl mWindowingLayer;
-
- /**
* Sequence number for the current layout pass.
*/
int mLayoutSeq = 0;
@@ -910,24 +913,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
.setOpaque(true)
.setContainerLayer();
mSurfaceControl = b.setName("Root").setContainerLayer().build();
- mWindowingLayer = b.setName("Display Windows").setParent(mSurfaceControl).build();
- mOverlayLayer = b.setName("Display Overlays").setParent(mSurfaceControl).build();
getPendingTransaction()
.setLayer(mSurfaceControl, 0)
.setLayerStack(mSurfaceControl, mDisplayId)
- .show(mSurfaceControl)
- .setLayer(mWindowingLayer, 0)
- .show(mWindowingLayer)
- .setLayer(mOverlayLayer, 1)
- .show(mOverlayLayer);
+ .show(mSurfaceControl);
getPendingTransaction().apply();
// These are the only direct children we should ever have and they are permanent.
- super.addChild(mBelowAppWindowsContainers, null);
- super.addChild(mTaskStackContainers, null);
- super.addChild(mAboveAppWindowsContainers, null);
- super.addChild(mImeWindowsContainers, null);
+ super.addChild(mWindowContainers, null);
+ super.addChild(mOverlayContainers, null);
+
+ mWindowContainers.addChildren();
+
// Sets the display content for the children.
onDisplayChanged(this);
@@ -1001,6 +999,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
case TYPE_INPUT_METHOD_DIALOG:
mImeWindowsContainers.addChild(token);
break;
+ case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
+ mOverlayContainers.addChild(token);
+ break;
default:
mAboveAppWindowsContainers.addChild(token);
break;
@@ -1867,6 +1868,25 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mTaskStackContainers.onStackWindowingModeChanged(stack);
}
+ /**
+ * The value is only valid in the scope {@link #onRequestedOverrideConfigurationChanged} of the
+ * changing hierarchy and the {@link #onConfigurationChanged} of its children.
+ *
+ * @return The current changes ({@link android.content.pm.ActivityInfo.Config}) of requested
+ * override configuration.
+ */
+ int getCurrentOverrideConfigurationChanges() {
+ return mCurrentOverrideConfigurationChanges;
+ }
+
+ @Override
+ public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ mCurrentOverrideConfigurationChanges =
+ getRequestedOverrideConfiguration().diff(overrideConfiguration);
+ super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+ mCurrentOverrideConfigurationChanges = 0;
+ }
+
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
final int lastOrientation = getConfiguration().orientation;
@@ -1878,8 +1898,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (lastOrientation != getConfiguration().orientation) {
getMetricsLogger().write(
new LogMaker(MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED)
- .setSubtype(getConfiguration().orientation)
- .addTaggedData(MetricsEvent.FIELD_DISPLAY_ID, getDisplayId()));
+ .setSubtype(getConfiguration().orientation)
+ .addTaggedData(MetricsEvent.FIELD_DISPLAY_ID, getDisplayId()));
}
// If there was no pinned stack, we still need to notify the controller of the display info
@@ -1936,49 +1956,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
setWindowingMode(windowingMode);
}
- /**
- * In split-screen mode we process the IME containers above the docked divider
- * rather than directly above their target.
- */
- private boolean skipTraverseChild(WindowContainer child) {
- if (child == mImeWindowsContainers && mInputMethodTarget != null
- && !hasSplitScreenPrimaryStack()) {
- return true;
- }
- return false;
- }
-
- @Override
- boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
- // Special handling so we can process IME windows with #forAllImeWindows above their IME
- // target, or here in order if there isn't an IME target.
- if (traverseTopToBottom) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final DisplayChildWindowContainer child = mChildren.get(i);
- if (skipTraverseChild(child)) {
- continue;
- }
-
- if (child.forAllWindows(callback, traverseTopToBottom)) {
- return true;
- }
- }
- } else {
- final int count = mChildren.size();
- for (int i = 0; i < count; i++) {
- final DisplayChildWindowContainer child = mChildren.get(i);
- if (skipTraverseChild(child)) {
- continue;
- }
-
- if (child.forAllWindows(callback, traverseTopToBottom)) {
- return true;
- }
- }
- }
- return false;
- }
-
boolean forAllImeWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
}
@@ -2000,7 +1977,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (mLastWindowForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Display id=%d is frozen, return %d", mDisplayId,
- mLastWindowForcedOrientation);
+ mLastWindowForcedOrientation);
// If the display is frozen, some activities may be in the middle of restarting, and
// thus have removed their old window. If the window has the flag to hide the lock
// screen, then the lock screen can re-appear and inflict its own orientation on us.
@@ -2014,7 +1991,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// momentarily unavailable due to activity relaunch.
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Display id=%d is frozen while keyguard locked, return %d",
- mDisplayId, getLastOrientation());
+ mDisplayId, getLastOrientation());
return getLastOrientation();
}
} else {
@@ -2268,7 +2245,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
forAllWindows(fn, true /* traverseTopToBottom */);
fn.recycle();
return FIRST_APPLICATION_WINDOW <= targetWindowType[0]
- && targetWindowType[0] <= LAST_APPLICATION_WINDOW;
+ && targetWindowType[0] <= LAST_APPLICATION_WINDOW;
}
/**
@@ -2277,19 +2254,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
Task findTaskForResizePoint(int x, int y) {
final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
- mTmpTaskForResizePointSearchResult.reset();
- for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
- if (!stack.getWindowConfiguration().canResizeTask()) {
- return null;
- }
-
- stack.findTaskForResizePoint(x, y, delta, mTmpTaskForResizePointSearchResult);
- if (mTmpTaskForResizePointSearchResult.searchDone) {
- return mTmpTaskForResizePointSearchResult.taskForResize;
- }
- }
- return null;
+ return mTmpTaskForResizePointSearchResult.process(mTaskStackContainers, x, y, delta);
}
void updateTouchExcludeRegion() {
@@ -2299,13 +2264,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
} else {
mTouchExcludeRegion.set(mBaseDisplayRect);
final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
+ mTmpRect.setEmpty();
mTmpRect2.setEmpty();
- for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0;
- --stackNdx) {
- final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
- stack.setTouchExcludeRegion(focusedTask, delta, mTouchExcludeRegion,
- mDisplayFrames.mContent, mTmpRect2);
- }
+
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ DisplayContent::processTaskForTouchExcludeRegion, this,
+ PooledLambda.__(Task.class), focusedTask, delta);
+ mTaskStackContainers.forAllTasks(c);
+ c.recycle();
+
// If we removed the focused task above, add it back and only leave its
// outside touch area in the exclusion. TapDetector is not interested in
// any touch inside the focused task itself.
@@ -2335,12 +2302,56 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
}
+ private void processTaskForTouchExcludeRegion(Task task, Task focusedTask, int delta) {
+ final ActivityRecord topVisibleActivity = task.getTopVisibleActivity();
+
+ if (topVisibleActivity == null || !topVisibleActivity.hasContentToDisplay()) {
+ return;
+ }
+
+ // Exclusion region is the region that TapDetector doesn't care about.
+ // Here we want to remove all non-focused tasks from the exclusion region.
+ // We also remove the outside touch area for resizing for all freeform
+ // tasks (including the focused).
+ // We save the focused task region once we find it, and add it back at the end.
+ // If the task is home stack and it is resizable in the minimized state, we want to
+ // exclude the docked stack from touch so we need the entire screen area and not just a
+ // small portion which the home stack currently is resized to.
+ if (task.isActivityTypeHome() && task.getStack().isMinimizedDockAndHomeStackResizable()) {
+ mDisplayContent.getBounds(mTmpRect);
+ } else {
+ task.getDimBounds(mTmpRect);
+ }
+
+ if (task == focusedTask) {
+ // Add the focused task rect back into the exclude region once we are done
+ // processing stacks.
+ mTmpRect2.set(mTmpRect);
+ }
+
+ final boolean isFreeformed = task.inFreeformWindowingMode();
+ if (task != focusedTask || isFreeformed) {
+ if (isFreeformed) {
+ // If the task is freeformed, enlarge the area to account for outside
+ // touch area for resize.
+ mTmpRect.inset(-delta, -delta);
+ // Intersect with display content rect. If we have system decor (status bar/
+ // navigation bar), we want to exclude that from the tap detection.
+ // Otherwise, if the app is partially placed under some system button (eg.
+ // Recents, Home), pressing that button would cause a full series of
+ // unwanted transfer focus/resume/pause, before we could go home.
+ mTmpRect.intersect(mDisplayFrames.mContent);
+ }
+ mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+ }
+ }
+
/**
* Union the region with all the tap exclude region provided by windows on this display.
*
* @param inOutRegion The region to be amended.
*/
- void amendWindowTapExcludeRegion(Region inOutRegion) {
+ private void amendWindowTapExcludeRegion(Region inOutRegion) {
for (int i = mTapExcludeProvidingWindows.size() - 1; i >= 0; i--) {
final WindowState win = mTapExcludeProvidingWindows.valueAt(i);
win.amendTapExcludeRegion(inOutRegion);
@@ -2383,8 +2394,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mPointerEventDispatcher.dispose();
setRotationAnimation(null);
mWmService.mAnimator.removeDisplayLocked(mDisplayId);
- mWindowingLayer.release();
- mOverlayLayer.release();
mInputMonitor.onDisplayRemoved();
// TODO(display-merge): Remove cast
mWmService.mDisplayNotificationController
@@ -2499,7 +2508,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// the minimized docked stack bounds.
final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock()
|| (topDockedTask != null && imeOnBottom && !dockedStack.isAdjustedForIme()
- && dockedStack.getBounds().height() < topDockedTask.getBounds().height());
+ && dockedStack.getBounds().height() < topDockedTask.getBounds().height());
// The divider could be adjusted for IME position, or be thinner than usual,
// or both. There are three possible cases:
@@ -2630,6 +2639,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final WindowToken windowToken = mImeWindowsContainers.getChildAt(i);
windowToken.dumpDebug(proto, IME_WINDOWS, logLevel);
}
+ for (int i = mOverlayContainers.getChildCount() - 1; i >= 0; --i) {
+ final WindowToken windowToken = mOverlayContainers.getChildAt(i);
+ windowToken.dumpDebug(proto, OVERLAY_WINDOWS, logLevel);
+ }
proto.write(DPI, mBaseDisplayDensity);
mDisplayInfo.dumpDebug(proto, DISPLAY_INFO);
proto.write(ROTATION, getRotation());
@@ -2660,31 +2673,31 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
final String subPrefix = " " + prefix;
pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
- pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
- pw.print("dpi");
- if (mInitialDisplayWidth != mBaseDisplayWidth
- || mInitialDisplayHeight != mBaseDisplayHeight
- || mInitialDisplayDensity != mBaseDisplayDensity) {
- pw.print(" base=");
- pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
- pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
- }
- if (mDisplayScalingDisabled) {
- pw.println(" noscale");
- }
- pw.print(" cur=");
- pw.print(mDisplayInfo.logicalWidth);
- pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
- pw.print(" app=");
- pw.print(mDisplayInfo.appWidth);
- pw.print("x"); pw.print(mDisplayInfo.appHeight);
- pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
- pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
- pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
- pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
- pw.print(subPrefix + "deferred=" + mDeferredRemoval
- + " mLayoutNeeded=" + mLayoutNeeded);
- pw.println(" mTouchExcludeRegion=" + mTouchExcludeRegion);
+ pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
+ pw.print("dpi");
+ if (mInitialDisplayWidth != mBaseDisplayWidth
+ || mInitialDisplayHeight != mBaseDisplayHeight
+ || mInitialDisplayDensity != mBaseDisplayDensity) {
+ pw.print(" base=");
+ pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
+ pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
+ }
+ if (mDisplayScalingDisabled) {
+ pw.println(" noscale");
+ }
+ pw.print(" cur=");
+ pw.print(mDisplayInfo.logicalWidth);
+ pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
+ pw.print(" app=");
+ pw.print(mDisplayInfo.appWidth);
+ pw.print("x"); pw.print(mDisplayInfo.appHeight);
+ pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
+ pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
+ pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
+ pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
+ pw.print(subPrefix + "deferred=" + mDeferredRemoval
+ + " mLayoutNeeded=" + mLayoutNeeded);
+ pw.println(" mTouchExcludeRegion=" + mTouchExcludeRegion);
pw.println();
pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
@@ -2841,7 +2854,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
final WindowState win = getWindow(w ->
w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == uid && !w.mPermanentlyHidden
- && !w.mWindowRemovalAllowed);
+ && !w.mWindowRemovalAllowed);
return win == null;
}
@@ -2921,7 +2934,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
- mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
+ mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
@@ -3223,7 +3236,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// target app together.
final boolean shouldAttachToDisplay = (mMagnificationSpec != null);
final SurfaceControl newParent =
- shouldAttachToDisplay ? mWindowingLayer : computeImeParent();
+ shouldAttachToDisplay ? mWindowContainers.getSurfaceControl() : computeImeParent();
if (newParent != null) {
getPendingTransaction().reparent(mImeWindowsContainers.mSurfaceControl, newParent);
scheduleAnimation();
@@ -3248,39 +3261,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
// Otherwise, we just attach it to the display.
- return mWindowingLayer;
- }
-
- boolean getNeedsMenu(WindowState top, WindowManagerPolicy.WindowState bottom) {
- if (top.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
- return top.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE;
- }
-
- // Used to indicate we have reached the first window in the range we are interested in.
- mTmpWindow = null;
-
- // TODO: Figure-out a more efficient way to do this.
- final WindowState candidate = getWindow(w -> {
- if (w == top) {
- // Reached the first window in the range we are interested in.
- mTmpWindow = w;
- }
- if (mTmpWindow == null) {
- return false;
- }
-
- if (w.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
- return true;
- }
- // If we reached the bottom of the range of windows we are considering,
- // assume no menu is needed.
- if (w == bottom) {
- return true;
- }
- return false;
- });
-
- return candidate != null && candidate.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE;
+ return mWindowContainers.getSurfaceControl();
}
void setLayoutNeeded() {
@@ -3395,7 +3376,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
boolean wallpaperEnabled = mWmService.mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableWallpaperService)
&& mWmService.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_checkWallpaperAtBoot)
+ com.android.internal.R.bool.config_checkWallpaperAtBoot)
&& !mWmService.mOnlyCore;
final boolean haveBootMsg = drawnWindowTypes.get(TYPE_BOOT_PROGRESS);
@@ -3586,13 +3567,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
"after finishPostLayoutPolicyLw", pendingLayoutChanges);
- mInsetsStateController.onPostLayout();
+ mInsetsStateController.onPostLayout();
} while (pendingLayoutChanges != 0);
mTmpApplySurfaceChangesTransactionState.reset();
- mTmpRecoveringMemory = recoveringMemory;
-
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
try {
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
@@ -3852,12 +3831,56 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
static final class TaskForResizePointSearchResult {
- boolean searchDone;
- Task taskForResize;
+ private Task taskForResize;
+ private int x;
+ private int y;
+ private int delta;
+ private Rect mTmpRect = new Rect();
- void reset() {
- searchDone = false;
+ Task process(WindowContainer root, int x, int y, int delta) {
taskForResize = null;
+ this.x = x;
+ this.y = y;
+ this.delta = delta;
+ mTmpRect.setEmpty();
+
+ final PooledFunction f = PooledLambda.obtainFunction(
+ TaskForResizePointSearchResult::processTask, this, PooledLambda.__(Task.class));
+ root.forAllTasks(f);
+ f.recycle();
+
+ return taskForResize;
+ }
+
+ private boolean processTask(Task task) {
+ if (!task.getStack().getWindowConfiguration().canResizeTask()) {
+ return true;
+ }
+
+ if (task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+ return true;
+ }
+
+ // We need to use the task's dim bounds (which is derived from the visible bounds of
+ // its apps windows) for any touch-related tests. Can't use the task's original
+ // bounds because it might be adjusted to fit the content frame. One example is when
+ // the task is put to top-left quadrant, the actual visible area would not start at
+ // (0,0) after it's adjusted for the status bar.
+ task.getDimBounds(mTmpRect);
+ mTmpRect.inset(-delta, -delta);
+ if (mTmpRect.contains(x, y)) {
+ mTmpRect.inset(delta, delta);
+
+ if (!mTmpRect.contains(x, y)) {
+ taskForResize = task;
+ return true;
+ }
+ // User touched inside the task. No need to look further,
+ // focus transfer will be handled in ACTION_UP.
+ return true;
+ }
+
+ return false;
}
}
@@ -4297,7 +4320,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (mHomeStack != null && mHomeStack.isVisible()
&& mDividerControllerLocked.isMinimizedDock()
&& !(mDividerControllerLocked.isHomeStackResizable()
- && mHomeStack.matchParentBounds())) {
+ && mHomeStack.matchParentBounds())) {
final int orientation = mHomeStack.getOrientation();
if (orientation != SCREEN_ORIENTATION_UNSET) {
return orientation;
@@ -4310,14 +4333,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (orientation != SCREEN_ORIENTATION_UNSET
&& orientation != SCREEN_ORIENTATION_BEHIND) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
- "App is requesting an orientation, return %d for display id=%d",
- orientation, mDisplayId);
+ "App is requesting an orientation, return %d for display id=%d",
+ orientation, mDisplayId);
return orientation;
}
ProtoLog.v(WM_DEBUG_ORIENTATION,
- "No app is requesting an orientation, return %d for display id=%d",
- getLastOrientation(), mDisplayId);
+ "No app is requesting an orientation, return %d for display id=%d",
+ getLastOrientation(), mDisplayId);
// The next app has not been requested to be visible, so we keep the current orientation
// to prevent freezing/unfreezing the display too early.
return getLastOrientation();
@@ -4486,7 +4509,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
wt.windowType, wt.mOwnerCanManageAppTokens);
if (needAssignIme && layer >= mWmService.mPolicy.getWindowLayerFromTypeLw(
- TYPE_INPUT_METHOD_DIALOG, true)) {
+ TYPE_INPUT_METHOD_DIALOG, true)) {
imeContainer.assignRelativeLayer(t, wt.getSurfaceControl(), -1);
needAssignIme = false;
}
@@ -4497,6 +4520,126 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
+ private class WindowContainers extends DisplayChildWindowContainer<WindowContainer> {
+ private final String mName;
+
+ WindowContainers(String name, WindowManagerService service) {
+ super(service);
+ mName = name;
+ }
+
+ @Override
+ void assignChildLayers(SurfaceControl.Transaction t) {
+ mBelowAppWindowsContainers.assignLayer(t, 0);
+ mTaskStackContainers.assignLayer(t, 1);
+ mAboveAppWindowsContainers.assignLayer(t, 2);
+
+ final WindowState imeTarget = mInputMethodTarget;
+ boolean needAssignIme = true;
+
+ // In the case where we have an IME target that is not in split-screen mode IME
+ // assignment is easy. We just need the IME to go directly above the target. This way
+ // children of the target will naturally go above the IME and everyone is happy.
+ //
+ // In the case of split-screen windowing mode, we need to elevate the IME above the
+ // docked divider while keeping the app itself below the docked divider, so instead
+ // we use relative layering of the IME targets child windows, and place the IME in
+ // the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}).
+ //
+ // In the case the IME target is animating, the animation Z order may be different
+ // than the WindowContainer Z order, so it's difficult to be sure we have the correct
+ // IME target. In this case we just layer the IME over all transitions by placing it
+ // in the above applications layer.
+ //
+ // In the case where we have no IME target we assign it where its base layer would
+ // place it in the AboveAppWindowContainers.
+ //
+ // Keep IME window in mAboveAppWindowsContainers as long as app's starting window
+ // exists so it get's layered above the starting window.
+ if (imeTarget != null && !(imeTarget.mActivityRecord != null
+ && imeTarget.mActivityRecord.hasStartingWindow()) && (
+ !(imeTarget.inSplitScreenWindowingMode()
+ || imeTarget.mToken.isAppTransitioning()) && (
+ imeTarget.getSurfaceControl() != null))) {
+ mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
+ // TODO: We need to use an extra level on the app surface to ensure
+ // this is always above SurfaceView but always below attached window.
+ 1);
+ needAssignIme = false;
+ }
+
+ // Above we have assigned layers to our children, now we ask them to assign
+ // layers to their children.
+ mBelowAppWindowsContainers.assignChildLayers(t);
+ mTaskStackContainers.assignChildLayers(t);
+ mAboveAppWindowsContainers.assignChildLayers(t,
+ needAssignIme ? mImeWindowsContainers : null);
+ mImeWindowsContainers.assignChildLayers(t);
+ }
+
+ @Override
+ String getName() {
+ return mName;
+ }
+
+ void addChildren() {
+ addChild(mBelowAppWindowsContainers, null);
+ addChild(mTaskStackContainers, null);
+ addChild(mAboveAppWindowsContainers, null);
+ addChild(mImeWindowsContainers, null);
+ }
+
+ /**
+ * In split-screen mode we process the IME containers above the docked divider
+ * rather than directly above their target.
+ */
+ private boolean skipTraverseChild(WindowContainer child) {
+ return child == mImeWindowsContainers && mInputMethodTarget != null
+ && !hasSplitScreenPrimaryStack();
+ }
+
+ @Override
+ boolean forAllWindows(ToBooleanFunction<WindowState> callback,
+ boolean traverseTopToBottom) {
+ // Special handling so we can process IME windows with #forAllImeWindows above their IME
+ // target, or here in order if there isn't an IME target.
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ if (skipTraverseChild(child)) {
+ continue;
+ }
+
+ if (child.forAllWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ Slog.d(TAG, "child " + mChildren.get(i));
+ final WindowContainer child = mChildren.get(i);
+ if (skipTraverseChild(child)) {
+ Slog.d(TAG, "child skipped");
+ continue;
+ }
+
+ if (child.forAllWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ void positionChildAt(int position, WindowContainer child, boolean includingParents) {
+ // Children of the WindowContainers are statically ordered, so the real intention here
+ // is to perform the operation on the display and not the static direct children.
+ getParent().positionChildAt(position, this, includingParents);
+ }
+ }
+
/**
* Window container class that contains all containers on this display that are not related to
* Apps. E.g. status bar.
@@ -4510,7 +4653,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// Tokens with higher base layer are z-ordered on-top.
mWmService.mPolicy.getWindowLayerFromTypeLw(token1.windowType,
token1.mOwnerCanManageAppTokens)
- < mWmService.mPolicy.getWindowLayerFromTypeLw(token2.windowType,
+ < mWmService.mPolicy.getWindowLayerFromTypeLw(token2.windowType,
token2.mOwnerCanManageAppTokens) ? -1 : 1;
private final Predicate<WindowState> mGetOrientingWindow = w -> {
@@ -4562,7 +4705,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
ProtoLog.v(WM_DEBUG_ORIENTATION,
"%s forcing orientation to %d for display id=%d", win, req,
- mDisplayId);
+ mDisplayId);
return (mLastWindowForcedOrientation = req);
}
@@ -4602,11 +4745,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
- SurfaceControl.Builder makeSurface(SurfaceSession s) {
- return mWmService.makeSurfaceBuilder(s)
- .setParent(mWindowingLayer);
- }
-
@Override
SurfaceSession getSession() {
return mSession;
@@ -4621,7 +4759,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
return b.setName(child.getName())
- .setParent(mWindowingLayer);
+ .setParent(mSurfaceControl);
}
/**
@@ -4632,14 +4770,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
SurfaceControl.Builder makeOverlay() {
return mWmService.makeSurfaceBuilder(mSession)
- .setParent(mOverlayLayer);
+ .setParent(mOverlayContainers.getSurfaceControl());
}
/**
- * Reparents the given surface to mOverlayLayer.
+ * Reparents the given surface to {@link #mOverlayContainers}' SurfaceControl.
*/
void reparentToOverlay(Transaction transaction, SurfaceControl surface) {
- transaction.reparent(surface, mOverlayLayer);
+ transaction.reparent(surface, mOverlayContainers.getSurfaceControl());
}
void applyMagnificationSpec(MagnificationSpec spec) {
@@ -4671,54 +4809,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
+ mWindowContainers.assignLayer(t, 0);
+ mOverlayContainers.assignLayer(t, 1);
- // These are layers as children of "mWindowingLayer"
- mBelowAppWindowsContainers.assignLayer(t, 0);
- mTaskStackContainers.assignLayer(t, 1);
- mAboveAppWindowsContainers.assignLayer(t, 2);
-
- final WindowState imeTarget = mInputMethodTarget;
- boolean needAssignIme = true;
-
- // In the case where we have an IME target that is not in split-screen
- // mode IME assignment is easy. We just need the IME to go directly above
- // the target. This way children of the target will naturally go above the IME
- // and everyone is happy.
- //
- // In the case of split-screen windowing mode, we need to elevate the IME above the
- // docked divider while keeping the app itself below the docked divider, so instead
- // we use relative layering of the IME targets child windows, and place the
- // IME in the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}).
- //
- // In the case the IME target is animating, the animation Z order may be different
- // than the WindowContainer Z order, so it's difficult to be sure we have the correct
- // IME target. In this case we just layer the IME over all transitions by placing it in the
- // above applications layer.
- //
- // In the case where we have no IME target we assign it where it's base layer would
- // place it in the AboveAppWindowContainers.
- //
- // Keep IME window in mAboveAppWindowsContainers as long as app's starting window exists
- // so it get's layered above the starting window.
- if (imeTarget != null
- && !(imeTarget.mActivityRecord != null && imeTarget.mActivityRecord.hasStartingWindow())
- && (!(imeTarget.inSplitScreenWindowingMode()
- || imeTarget.mToken.isAppTransitioning())
- && (imeTarget.getSurfaceControl() != null))) {
- mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
- // TODO: We need to use an extra level on the app surface to ensure
- // this is always above SurfaceView but always below attached window.
- 1);
- needAssignIme = false;
- }
-
- // Above we have assigned layers to our children, now we ask them to assign
- // layers to their children.
- mBelowAppWindowsContainers.assignChildLayers(t);
- mTaskStackContainers.assignChildLayers(t);
- mAboveAppWindowsContainers.assignChildLayers(t,
- needAssignIme == true ? mImeWindowsContainers : null);
- mImeWindowsContainers.assignChildLayers(t);
+ mWindowContainers.assignChildLayers(t);
+ mOverlayContainers.assignChildLayers(t);
}
/**
@@ -4820,7 +4915,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (mAppTransition.isTransitionSet()) {
ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
"Execute app transition: %s, displayId: %d Callers=%s",
- mAppTransition, mDisplayId, Debug.getCallers(5));
+ mAppTransition, mDisplayId, Debug.getCallers(5));
mAppTransition.setReady();
mWmService.mWindowPlacerLocked.requestTraversal();
}
@@ -4885,8 +4980,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
/**
- * Re-parent the DisplayContent's top surfaces, {@link #mWindowingLayer} and
- * {@link #mOverlayLayer} to the specified SurfaceControl.
+ * Re-parent the DisplayContent's top surface, {@link #mSurfaceControl} to the specified
+ * SurfaceControl.
*
* @param win The window which owns the SurfaceControl. This indicates the z-order of the
* windows of this display against the windows on the parent display.
@@ -4964,11 +5059,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@VisibleForTesting
SurfaceControl getWindowingLayer() {
- return mWindowingLayer;
+ return mWindowContainers.getSurfaceControl();
}
SurfaceControl getOverlayLayer() {
- return mOverlayLayer;
+ return mOverlayContainers.getSurfaceControl();
}
/**
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 1a1a7d4d8e0c..6b5859d418ec 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -259,7 +259,7 @@ public class DockedStackDividerController {
if (homeStack == null) {
return false;
}
- final Task homeTask = homeStack.findHomeTask();
+ final Task homeTask = homeStack.getTopMostTask();
return homeTask != null && homeTask.isResizeable();
}
@@ -708,7 +708,7 @@ public class DockedStackDividerController {
if (homeStack == null) {
return;
}
- final Task homeTask = homeStack.findHomeTask();
+ final Task homeTask = homeStack.getTopMostTask();
if (homeTask == null || !isWithinDisplay(homeTask)) {
return;
}
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 3aae1b1d7c8f..949ff195d731 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -45,7 +45,7 @@ class EnsureActivitiesVisibleHelper {
void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
boolean notifyClients) {
mStarting = starting;
- mTop = mContiner.topRunningActivityLocked();
+ mTop = mContiner.topRunningActivity();
// If the top activity is not fullscreen, then we need to make sure any activities under it
// are now visible.
mAboveTop = mTop != null;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index ac5c96b83e56..3a0696fb3ed5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -494,7 +494,7 @@ class KeyguardController {
if (stack != null) {
final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
- && stack.topRunningActivityLocked() == topDismissing
+ && stack.topRunningActivity() == topDismissing
&& controller.canShowWhileOccluded(
true /* dismissKeyguard */,
false /* showWhenLocked */));
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 2ece6e21b2c5..7a72b435ac8a 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -150,7 +150,7 @@ public class LockTaskController {
* The first task in the list, which started the current LockTask session, is called the root
* task. It coincides with the Home task in a typical multi-app kiosk deployment. When there are
* more than one locked tasks, the root task can't be finished. Nor can it be moved to the back
- * of the stack by {@link ActivityStack#moveTaskToBackLocked(int)};
+ * of the stack by {@link ActivityStack#moveTaskToBack(Task)};
*
* Calling {@link Activity#stopLockTask()} on the root task will finish all tasks but itself in
* this list, and the device will exit LockTask mode.
@@ -251,7 +251,7 @@ public class LockTaskController {
/**
* @return whether the given task can be moved to the back of the stack with
- * {@link ActivityStack#moveTaskToBackLocked(int)}
+ * {@link ActivityStack#moveTaskToBack(Task)}
* @see #mLockTaskModeTasks
*/
boolean canMoveTaskToBack(Task task) {
@@ -653,10 +653,7 @@ public class LockTaskController {
taskChanged = true;
}
- for (int displayNdx = mSupervisor.mRootActivityContainer.getChildCount() - 1;
- displayNdx >= 0; --displayNdx) {
- mSupervisor.mRootActivityContainer.getChildAt(displayNdx).onLockTaskPackagesUpdated();
- }
+ mSupervisor.mRootActivityContainer.mRootWindowContainer.forAllTasks(Task::setLockTaskAuth);
final ActivityRecord r = mSupervisor.mRootActivityContainer.topRunningActivity();
final Task task = (r != null) ? r.getTask() : null;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index f0e441fe77b1..c54fbd6b1726 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -211,7 +211,7 @@ class RecentTasks {
final DisplayContent dc = rac.getActivityDisplay(displayId).mDisplayContent;
if (dc.pointWithinAppWindow(x, y)) {
final ActivityStack stack = mService.getTopDisplayFocusedStack();
- final Task topTask = stack != null ? stack.topTask() : null;
+ final Task topTask = stack != null ? stack.getTopMostTask() : null;
resetFreezeTaskListReordering(topTask);
}
}
@@ -319,7 +319,7 @@ class RecentTasks {
void resetFreezeTaskListReorderingOnTimeout() {
synchronized (mService.mGlobalLock) {
final ActivityStack focusedStack = mService.getTopDisplayFocusedStack();
- final Task topTask = focusedStack != null ? focusedStack.topTask() : null;
+ final Task topTask = focusedStack != null ? focusedStack.getTopMostTask() : null;
resetFreezeTaskListReordering(topTask);
}
}
@@ -630,8 +630,7 @@ class RecentTasks {
&& task.realActivitySuspended != suspended) {
task.realActivitySuspended = suspended;
if (suspended) {
- mSupervisor.removeTaskByIdLocked(task.mTaskId, false,
- REMOVE_FROM_RECENTS, "suspended-package");
+ mSupervisor.removeTask(task, false, REMOVE_FROM_RECENTS, "suspended-package");
}
notifyTaskPersisterLocked(task, false);
}
@@ -658,8 +657,7 @@ class RecentTasks {
if (task.mUserId != userId) continue;
if (!taskPackageName.equals(packageName)) continue;
- mSupervisor.removeTaskByIdLocked(task.mTaskId, true, REMOVE_FROM_RECENTS,
- "remove-package-task");
+ mSupervisor.removeTask(task, true, REMOVE_FROM_RECENTS, "remove-package-task");
}
}
@@ -687,8 +685,7 @@ class RecentTasks {
final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
&& (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
if (sameComponent) {
- mSupervisor.removeTaskByIdLocked(task.mTaskId, false,
- REMOVE_FROM_RECENTS, "disabled-package");
+ mSupervisor.removeTask(task, false, REMOVE_FROM_RECENTS, "disabled-package");
}
}
}
@@ -1306,9 +1303,9 @@ class RecentTasks {
case WINDOWING_MODE_PINNED:
return false;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().topTask());
+ if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask());
final ActivityStack stack = task.getStack();
- if (stack != null && stack.topTask() == task) {
+ if (stack != null && stack.getTopMostTask() == task) {
// Only the non-top task of the primary split screen mode is visible
return false;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index d5bbe6bb8b9c..b39862633809 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -216,7 +216,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// and default launchers coexisting), then move the task to the top as a part of
// moving the stack to the front
final Task task = targetActivity.getTask();
- if (targetStack.topTask() != task) {
+ if (targetStack.getTopMostTask() != task) {
targetStack.positionChildAtTop(task);
}
} else {
@@ -432,7 +432,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// cases:
// 1) The next launching task is not being animated by the recents animation
// 2) The next task is home activity. (i.e. pressing home key to back home in recents).
- if ((!controller.isAnimatingTask(stack.getTopChild())
+ if ((!controller.isAnimatingTask(stack.getTopMostTask())
|| controller.isTargetApp(stack.getTopNonFinishingActivity()))
&& controller.shouldDeferCancelUntilNextTransition()) {
// Always prepare an app transition since we rely on the transition callbacks to cleanup
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 5653ec07a340..704a4b7e65ea 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -129,6 +129,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Function;
/**
* Root node for activity containers.
@@ -168,8 +169,8 @@ class RootActivityContainer extends ConfigurationContainer
WindowManagerService mWindowManager;
DisplayManager mDisplayManager;
private DisplayManagerInternal mDisplayManagerInternal;
- // TODO: Remove after object merge with RootWindowContainer.
- private RootWindowContainer mRootWindowContainer;
+ // TODO(root-unify): Remove after object merge with RootWindowContainer.
+ RootWindowContainer mRootWindowContainer;
/**
* List of displays which contain activities, sorted by z-order.
@@ -214,7 +215,7 @@ class RootActivityContainer extends ConfigurationContainer
private RemoteException mTmpRemoteException;
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
- static class FindTaskResult implements ToBooleanFunction<Task> {
+ static class FindTaskResult implements Function<Task, Boolean> {
ActivityRecord mRecord;
boolean mIdealMatch;
@@ -259,7 +260,7 @@ class RootActivityContainer extends ConfigurationContainer
}
@Override
- public boolean apply(Task task) {
+ public Boolean apply(Task task) {
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
@@ -899,7 +900,7 @@ class RootActivityContainer extends ConfigurationContainer
mTmpBoolean = false; // Set to true if an activity was started.
final PooledFunction c = PooledLambda.obtainFunction(
RootActivityContainer::startActivityForAttachedApplicationIfNeeded, this,
- PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivityLocked());
+ PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivity());
stack.forAllActivities(c);
c.recycle();
if (mTmpRemoteException != null) {
@@ -992,7 +993,7 @@ class RootActivityContainer extends ConfigurationContainer
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
stack.switchUser(userId);
- Task task = stack.topTask();
+ Task task = stack.getTopMostTask();
if (task != null) {
stack.positionChildAtTop(task);
}
@@ -1075,7 +1076,7 @@ class RootActivityContainer extends ConfigurationContainer
"moveTopStackActivityToPinnedStack: Unknown stackId=" + stackId);
}
- final ActivityRecord r = stack.topRunningActivityLocked();
+ final ActivityRecord r = stack.topRunningActivity();
if (r == null) {
Slog.w(TAG, "moveTopStackActivityToPinnedStack: No top running activity"
+ " in stack=" + stack);
@@ -1263,7 +1264,7 @@ class RootActivityContainer extends ConfigurationContainer
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
- final ActivityRecord topRunningActivity = stack.topRunningActivityLocked();
+ final ActivityRecord topRunningActivity = stack.topRunningActivity();
if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
continue;
}
@@ -1401,32 +1402,37 @@ class RootActivityContainer extends ConfigurationContainer
info.position = display != null ? display.getIndexOf(stack) : 0;
info.configuration.setTo(stack.getConfiguration());
- ArrayList<Task> tasks = stack.getAllTasks();
- final int numTasks = tasks.size();
- int[] taskIds = new int[numTasks];
- String[] taskNames = new String[numTasks];
- Rect[] taskBounds = new Rect[numTasks];
- int[] taskUserIds = new int[numTasks];
- for (int i = 0; i < numTasks; ++i) {
- final Task task = tasks.get(i);
- taskIds[i] = task.mTaskId;
- taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
- : task.realActivity != null ? task.realActivity.flattenToString()
- : task.getTopNonFinishingActivity() != null
- ? task.getTopNonFinishingActivity().packageName : "unknown";
- taskBounds[i] = mService.getTaskBounds(task.mTaskId);
- taskUserIds[i] = task.mUserId;
- }
- info.taskIds = taskIds;
- info.taskNames = taskNames;
- info.taskBounds = taskBounds;
- info.taskUserIds = taskUserIds;
-
- final ActivityRecord top = stack.topRunningActivityLocked();
+ final int numTasks = stack.getChildCount();
+ info.taskIds = new int[numTasks];
+ info.taskNames = new String[numTasks];
+ info.taskBounds = new Rect[numTasks];
+ info.taskUserIds = new int[numTasks];
+ final int[] currenIndex = {0};
+
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ RootActivityContainer::processTaskForStackInfo, PooledLambda.__(Task.class), info,
+ currenIndex);
+ stack.forAllTasks(c, false);
+ c.recycle();
+
+ final ActivityRecord top = stack.topRunningActivity();
info.topActivity = top != null ? top.intent.getComponent() : null;
return info;
}
+ private static void processTaskForStackInfo(
+ Task task, ActivityManager.StackInfo info, int[] currentIndex) {
+ int i = currentIndex[0];
+ info.taskIds[i] = task.mTaskId;
+ info.taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
+ : task.realActivity != null ? task.realActivity.flattenToString()
+ : task.getTopNonFinishingActivity() != null
+ ? task.getTopNonFinishingActivity().packageName : "unknown";
+ info.taskBounds[i] = task.mAtmService.getTaskBounds(task.mTaskId);
+ info.taskUserIds[i] = task.mUserId;
+ currentIndex[0] = ++i;
+ }
+
ActivityManager.StackInfo getStackInfo(int stackId) {
ActivityStack stack = getStack(stackId);
if (stack != null) {
@@ -1905,7 +1911,7 @@ class RootActivityContainer extends ConfigurationContainer
}
if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
&& display.getSplitScreenPrimaryStack() == stack
- && candidateTask == stack.topTask()) {
+ && candidateTask == stack.getTopMostTask()) {
// This is a special case when we try to launch an activity that is currently on
// top of split-screen primary stack, but is targeting split-screen secondary.
// In this case we don't want to move it to another stack.
@@ -2338,24 +2344,11 @@ class RootActivityContainer extends ConfigurationContainer
void lockAllProfileTasks(@UserIdInt int userId) {
mService.deferWindowLayout();
try {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- final List<Task> tasks = stack.getAllTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
- final Task task = tasks.get(taskNdx);
-
- // Check the task for a top activity belonging to userId, or returning a
- // result to an activity belonging to userId. Example case: a document
- // picker for personal files, opened by a work app, should still get locked.
- if (taskTopActivityIsUser(task, userId)) {
- mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
- task.mTaskId, userId);
- }
- }
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ RootActivityContainer::taskTopActivityIsUser, this, PooledLambda.__(Task.class),
+ userId);
+ mRootWindowContainer.forAllTasks(c);
+ c.recycle();
} finally {
mService.continueWindowLayout();
}
@@ -2372,13 +2365,19 @@ class RootActivityContainer extends ConfigurationContainer
*
* @return {@code true} if the top activity looks like it belongs to {@param userId}.
*/
- private boolean taskTopActivityIsUser(Task task, @UserIdInt int userId) {
+ private void taskTopActivityIsUser(Task task, @UserIdInt int userId) {
// To handle the case that work app is in the task but just is not the top one.
final ActivityRecord activityRecord = task.getTopNonFinishingActivity();
final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null);
- return (activityRecord != null && activityRecord.mUserId == userId)
- || (resultTo != null && resultTo.mUserId == userId);
+ // Check the task for a top activity belonging to userId, or returning a
+ // result to an activity belonging to userId. Example case: a document
+ // picker for personal files, opened by a work app, should still get locked.
+ if ((activityRecord != null && activityRecord.mUserId == userId)
+ || (resultTo != null && resultTo.mUserId == userId)) {
+ mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
+ task.mTaskId, userId);
+ }
}
void cancelInitializingActivities() {
@@ -2414,29 +2413,25 @@ class RootActivityContainer extends ConfigurationContainer
+ " lookup");
}
- int numDisplays = mActivityDisplays.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- final Task task = stack.taskForIdLocked(id);
- if (task == null) {
- continue;
- }
- if (aOptions != null) {
- // Resolve the stack the task should be placed in now based on options
- // and reparent if needed.
- final ActivityStack launchStack =
- getLaunchStack(null, aOptions, task, onTop);
- if (launchStack != null && stack != launchStack) {
- final int reparentMode = onTop
- ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE;
- task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME,
- "anyTaskForId");
- }
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ Task::isTaskId, PooledLambda.__(Task.class), id);
+ Task task = mRootWindowContainer.getTask(p);
+ p.recycle();
+
+ if (task != null) {
+ if (aOptions != null) {
+ // Resolve the stack the task should be placed in now based on options
+ // and reparent if needed.
+ final ActivityStack launchStack =
+ getLaunchStack(null, aOptions, task, onTop);
+ if (launchStack != null && task.getStack() != launchStack) {
+ final int reparentMode = onTop
+ ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE;
+ task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME,
+ "anyTaskForId");
}
- return task;
}
+ return task;
}
// If we are matching stack tasks only, return now
@@ -2447,7 +2442,7 @@ class RootActivityContainer extends ConfigurationContainer
// Otherwise, check the recent tasks and return if we find it there and we are not restoring
// the task from recents
if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents");
- final Task task = mStackSupervisor.mRecentTasks.getTask(id);
+ task = mStackSupervisor.mRecentTasks.getTask(id);
if (task == null) {
if (DEBUG_RECENTS) {
@@ -2492,7 +2487,7 @@ class RootActivityContainer extends ConfigurationContainer
@WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid,
boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType,
- ignoreWindowingMode, mActivityDisplays, callingUid, allowed, crossUser, profileIds);
+ ignoreWindowingMode, this, callingUid, allowed, crossUser, profileIds);
}
void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index ca9d91e9bcab..5783713b17b1 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -16,11 +16,18 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
+import android.os.UserHandle;
import android.util.ArraySet;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
+
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
@@ -39,8 +46,17 @@ class RunningTasks {
private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
private final ArrayList<Task> mTmpStackTasks = new ArrayList<>();
+ private int mCallingUid;
+ private int mUserId;
+ private boolean mCrossUser;
+ private ArraySet<Integer> mProfileIds;
+ private boolean mAllowed;
+ private int mIgnoreActivityType;
+ private int mIgnoreWindowingMode;
+ private ActivityStack mTopDisplayFocusStack;
+
void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
- @WindowingMode int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays,
+ @WindowingMode int ignoreWindowingMode, RootActivityContainer root,
int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
// Return early if there are no tasks to fetch
if (maxNum <= 0) {
@@ -49,17 +65,19 @@ class RunningTasks {
// Gather all of the tasks across all of the tasks, and add them to the sorted set
mTmpSortedSet.clear();
- final int numDisplays = activityDisplays.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ActivityDisplay display = activityDisplays.get(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- mTmpStackTasks.clear();
- stack.getRunningTasks(mTmpStackTasks, ignoreActivityType, ignoreWindowingMode,
- callingUid, allowed, crossUser, profileIds);
- mTmpSortedSet.addAll(mTmpStackTasks);
- }
- }
+ mCallingUid = callingUid;
+ mUserId = UserHandle.getUserId(callingUid);
+ mCrossUser = crossUser;
+ mProfileIds = profileIds;
+ mAllowed = allowed;
+ mIgnoreActivityType = ignoreActivityType;
+ mIgnoreWindowingMode = ignoreWindowingMode;
+ mTopDisplayFocusStack = root.getTopDisplayFocusedStack();
+
+ final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
+ PooledLambda.__(Task.class));
+ root.mRootWindowContainer.forAllTasks(c, false);
+ c.recycle();
// Take the first {@param maxNum} tasks and create running task infos for them
final Iterator<Task> iter = mTmpSortedSet.iterator();
@@ -74,9 +92,45 @@ class RunningTasks {
}
}
- /**
- * Constructs a {@link RunningTaskInfo} from a given {@param task}.
- */
+ private void processTask(Task task) {
+ if (task.getTopNonFinishingActivity() == null) {
+ // Skip if there are no activities in the task
+ return;
+ }
+ if (task.effectiveUid != mCallingUid) {
+ if (task.mUserId != mUserId && !mCrossUser && !mProfileIds.contains(task.mUserId)) {
+ // Skip if the caller does not have cross user permission or cannot access
+ // the task's profile
+ return;
+ }
+ if (!mAllowed && !task.isActivityTypeHome()) {
+ // Skip if the caller isn't allowed to fetch this task, except for the home
+ // task which we always return.
+ return;
+ }
+ }
+ if (mIgnoreActivityType != ACTIVITY_TYPE_UNDEFINED
+ && task.getActivityType() == mIgnoreActivityType) {
+ // Skip ignored activity type
+ return;
+ }
+ if (mIgnoreWindowingMode != WINDOWING_MODE_UNDEFINED
+ && task.getWindowingMode() == mIgnoreWindowingMode) {
+ // Skip ignored windowing mode
+ return;
+ }
+
+ final ActivityStack stack = task.getStack();
+ if (stack == mTopDisplayFocusStack && stack.getTopMostTask() == task) {
+ // For the focused stack top task, update the last stack active time so that it can be
+ // used to determine the order of the tasks (it may not be set for newly created tasks)
+ task.touchActiveTime();
+ }
+
+ mTmpSortedSet.add(task);
+ }
+
+ /** Constructs a {@link RunningTaskInfo} from a given {@param task}. */
private RunningTaskInfo createRunningTaskInfo(Task task) {
final RunningTaskInfo rti = new RunningTaskInfo();
task.fillTaskInfo(rti);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 1a7d21406e55..399c5d3ae45f 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -172,7 +172,7 @@ class ScreenRotationAnimation {
.setContainerLayer()
.build();
- mSurfaceControl = displayContent.makeSurface(null)
+ mSurfaceControl = mService.makeSurfaceBuilder(null)
.setName("ScreenshotSurface")
.setParent(mRotationLayer)
.setBufferSize(mWidth, mHeight)
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b1d06923fd2f..0e07e526faac 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -155,6 +155,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
class Task extends WindowContainer<WindowContainer> {
@@ -684,7 +685,7 @@ class Task extends WindowContainer<WindowContainer> {
final boolean toTopOfStack = position == MAX_VALUE;
if (toTopOfStack && toStack.getResumedActivity() != null
- && toStack.topRunningActivityLocked() != null) {
+ && toStack.topRunningActivity() != null) {
// Pause the resumed activity on the target stack while re-parenting task on top of it.
toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
null /* resuming */);
@@ -720,7 +721,7 @@ class Task extends WindowContainer<WindowContainer> {
// Whenever we are moving the top activity from the front stack we want to make sure to
// move the stack to the front.
final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
- && (sourceStack.topRunningActivityLocked() == r);
+ && (sourceStack.topRunningActivity() == r);
final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
|| (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
@@ -1256,7 +1257,7 @@ class Task extends WindowContainer<WindowContainer> {
// work.
// TODO: If the callers to removeChild() changes such that we have multiple places
// where we are destroying the task, move this back into removeChild()
- mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
+ mAtmService.mStackSupervisor.removeTask(this, false /* killProcess */,
!REMOVE_FROM_RECENTS, reason);
}
} else if (!mReuseTask) {
@@ -2659,12 +2660,13 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
- void forAllTasks(Consumer<Task> callback) {
+ void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
+ // TODO(task-hierarchy): Change to traverse children when tasks can contain other tasks.
callback.accept(this);
}
@Override
- boolean forAllTasks(ToBooleanFunction<Task> callback) {
+ boolean forAllTasks(Function<Task, Boolean> callback) {
return callback.apply(this);
}
@@ -2707,6 +2709,10 @@ class Task extends WindowContainer<WindowContainer> {
return mDimmer;
}
+ boolean isTaskForUser(int userId) {
+ return mUserId == userId;
+ }
+
@Override
void prepareSurfaces() {
mDimmer.resetDimStates();
@@ -2800,6 +2806,10 @@ class Task extends WindowContainer<WindowContainer> {
return info;
}
+ boolean isTaskId(int taskId) {
+ return mTaskId == taskId;
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("userId="); pw.print(mUserId);
pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e80f3b8577d3..d73cb50fe107 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1202,9 +1202,17 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {
+ return getActivity(callback, traverseTopToBottom, null /*boundary*/);
+ }
+
+ ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
+ WindowContainer boundary) {
if (traverseTopToBottom) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final ActivityRecord r = mChildren.get(i).getActivity(callback, traverseTopToBottom);
+ final WindowContainer wc = mChildren.get(i);
+ if (wc == boundary) return null;
+
+ final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary);
if (r != null) {
return r;
}
@@ -1212,7 +1220,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
} else {
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
- final ActivityRecord r = mChildren.get(i).getActivity(callback, traverseTopToBottom);
+ final WindowContainer wc = mChildren.get(i);
+ if (wc == boundary) return null;
+
+ final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary);
if (r != null) {
return r;
}
@@ -1320,14 +1331,57 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
/**
* For all tasks at or below this container call the callback.
*
+ * @param callback Calls the {@link ToBooleanFunction#apply} method for each task found and
+ * stops the search if {@link ToBooleanFunction#apply} returns {@code true}.
+ */
+ boolean forAllTasks(Function<Task, Boolean> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ if (mChildren.get(i).forAllTasks(callback)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * For all tasks at or below this container call the callback.
+ *
* @param callback Callback to be called for every task.
*/
void forAllTasks(Consumer<Task> callback) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- mChildren.get(i).forAllTasks(callback);
+ forAllTasks(callback, true /*traverseTopToBottom*/);
+ }
+
+ void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
+ final int count = mChildren.size();
+ if (traverseTopToBottom) {
+ for (int i = count - 1; i >= 0; --i) {
+ mChildren.get(i).forAllTasks(callback, traverseTopToBottom);
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ mChildren.get(i).forAllTasks(callback, traverseTopToBottom);
+ }
}
}
+ Task getTaskAbove(Task t) {
+ return getTask(
+ (above) -> true, t, false /*includeBoundary*/, false /*traverseTopToBottom*/);
+ }
+
+ Task getTaskBelow(Task t) {
+ return getTask((below) -> true, t, false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ }
+
+ Task getBottomMostTask() {
+ return getTask((t) -> true, false /*traverseTopToBottom*/);
+ }
+
+ Task getTopMostTask() {
+ return getTask((t) -> true, true /*traverseTopToBottom*/);
+ }
+
Task getTask(Predicate<Task> callback) {
return getTask(callback, true /*traverseTopToBottom*/);
}
@@ -1354,18 +1408,59 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
/**
- * For all tasks at or below this container call the callback.
+ * Gets an task in a branch of the tree.
*
- * @param callback Calls the {@link ToBooleanFunction#apply} method for each task found and
- * stops the search if {@link ToBooleanFunction#apply} returns {@code true}.
+ * @param callback called to test if this is the task that should be returned.
+ * @param boundary We don't return tasks via {@param callback} until we get to this node in
+ * the tree.
+ * @param includeBoundary If the boundary from be processed to return tasks.
+ * @param traverseTopToBottom direction to traverse the tree.
+ * @return The task if found or null.
*/
- boolean forAllTasks(ToBooleanFunction<Task> callback) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- if (mChildren.get(i).forAllTasks(callback)) {
- return true;
+ final Task getTask(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary,
+ boolean traverseTopToBottom) {
+ return getTask(callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
+ }
+
+ private Task getTask(Predicate<Task> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+ boolean[] boundaryFound) {
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final Task t = processGetTaskWithBoundary(callback, boundary,
+ includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
+ if (t != null) {
+ return t;
+ }
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ final Task t = processGetTaskWithBoundary(callback, boundary,
+ includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
+ if (t != null) {
+ return t;
+ }
}
}
- return false;
+
+ return null;
+ }
+
+ private Task processGetTaskWithBoundary(Predicate<Task> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+ boolean[] boundaryFound, WindowContainer wc) {
+ if (wc == boundary || boundary == null) {
+ boundaryFound[0] = true;
+ if (!includeBoundary) return null;
+ }
+
+ if (boundaryFound[0]) {
+ return wc.getTask(callback, traverseTopToBottom);
+ }
+
+ return wc.getTask(
+ callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
}
WindowState getWindow(Predicate<WindowState> callback) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 95eb4ddceb45..f45eb50f7f6c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.Manifest.permission.ACCESS_SURFACE_FLINGER;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
@@ -7815,8 +7814,8 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean mirrorDisplay(int displayId, SurfaceControl outSurfaceControl) {
- if (!checkCallingPermission(ACCESS_SURFACE_FLINGER, "mirrorDisplay()")) {
- throw new SecurityException("Requires ACCESS_SURFACE_FLINGER permission");
+ if (!checkCallingPermission(READ_FRAME_BUFFER, "mirrorDisplay()")) {
+ throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
final SurfaceControl displaySc;
@@ -7827,7 +7826,7 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
- displaySc = displayContent.getSurfaceControl();
+ displaySc = displayContent.getWindowingLayer();
}
final SurfaceControl mirror = SurfaceControl.mirrorSurface(displaySc);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6a1aa02a6c79..5b7f36d62094 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1239,11 +1239,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
@Override
- public boolean getNeedsMenuLw(WindowManagerPolicy.WindowState bottom) {
- return getDisplayContent().getNeedsMenu(this, bottom);
- }
-
- @Override
public int getSystemUiVisibility() {
return mSystemUiVisibility;
}
@@ -1738,28 +1733,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
super.onMovedByResize();
}
- boolean onAppVisibilityChanged(boolean visible, boolean runningAppAnimation) {
- boolean changed = false;
-
+ void onAppVisibilityChanged(boolean visible, boolean runningAppAnimation) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- changed |= c.onAppVisibilityChanged(visible, runningAppAnimation);
+ mChildren.get(i).onAppVisibilityChanged(visible, runningAppAnimation);
}
+ final boolean isVisibleNow = isVisibleNow();
if (mAttrs.type == TYPE_APPLICATION_STARTING) {
// Starting window that's exiting will be removed when the animation finishes.
// Mark all relevant flags for that onExitAnimationDone will proceed all the way
// to actually remove it.
- if (!visible && isVisibleNow() && mActivityRecord.isAnimating(TRANSITION)) {
+ if (!visible && isVisibleNow && mActivityRecord.isAnimating(TRANSITION)) {
mAnimatingExit = true;
mRemoveOnExit = true;
mWindowRemovalAllowed = true;
}
- return changed;
- }
-
- final boolean isVisibleNow = isVisibleNow();
- if (visible != isVisibleNow) {
+ } else if (visible != isVisibleNow) {
// Run exit animation if:
// 1. App visibility and WS visibility are different
// 2. App is not running an animation
@@ -1773,11 +1762,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
accessibilityController.onWindowTransitionLocked(this, winTransit);
}
}
- changed = true;
setDisplayLayoutNeeded();
}
-
- return changed;
}
boolean onSetAppExiting() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 21cacd45dcb5..b6e501a785ef 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -109,6 +109,7 @@ import com.android.server.input.InputManagerService;
import com.android.server.inputmethod.InputMethodManagerService;
import com.android.server.inputmethod.InputMethodSystemProperty;
import com.android.server.inputmethod.MultiClientInputMethodManagerService;
+import com.android.server.integrity.AppIntegrityManagerService;
import com.android.server.lights.LightsService;
import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.MediaRouterService;
@@ -1129,6 +1130,10 @@ public final class SystemServer {
SignedConfigService.registerUpdateReceiver(mSystemContext);
t.traceEnd();
+ t.traceBegin("AppIntegrityService");
+ mSystemServiceManager.startService(AppIntegrityManagerService.class);
+ t.traceEnd();
+
} catch (Throwable e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service");
diff --git a/services/net/java/android/net/NetworkMonitorManager.java b/services/net/java/android/net/NetworkMonitorManager.java
index 0f41302c0b15..0f669817f52e 100644
--- a/services/net/java/android/net/NetworkMonitorManager.java
+++ b/services/net/java/android/net/NetworkMonitorManager.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.Hide;
import android.annotation.NonNull;
import android.os.Binder;
import android.os.RemoteException;
@@ -33,6 +34,7 @@ import android.util.Log;
* wrapper methods in this class return a boolean that callers can use to determine whether
* RemoteException was thrown.
*/
+@Hide
public class NetworkMonitorManager {
@NonNull private final INetworkMonitor mNetworkMonitor;
diff --git a/services/net/java/android/net/ip/IpClientManager.java b/services/net/java/android/net/ip/IpClientManager.java
index 4b7ed3c7b72f..09e333ee3471 100644
--- a/services/net/java/android/net/ip/IpClientManager.java
+++ b/services/net/java/android/net/ip/IpClientManager.java
@@ -16,6 +16,7 @@
package android.net.ip;
+import android.annotation.Hide;
import android.annotation.NonNull;
import android.net.NattKeepalivePacketData;
import android.net.ProxyInfo;
@@ -38,6 +39,7 @@ import android.util.Log;
* wrapper methods in this class return a boolean that callers can use to determine whether
* RemoteException was thrown.
*/
+@Hide
public class IpClientManager {
@NonNull private final IIpClient mIpClient;
@NonNull private final String mTag;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 8e6114aaeffe..4635c08b36c2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -142,7 +142,7 @@ public class MockingOomAdjusterTests {
sService.mConstants = new ActivityManagerConstants(sContext, sService,
sContext.getMainThreadHandler());
ProcessList pr = new ProcessList();
- pr.init(sService, new ActiveUids(sService, false));
+ pr.init(sService, new ActiveUids(sService, false), null);
setFieldValue(ActivityManagerService.class, sService, "mProcessList",
pr);
setFieldValue(ActivityManagerService.class, sService, "mHandler",
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 3518dc599cef..05b655af65ed 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -120,11 +120,14 @@ public class LocalDisplayAdapterTest {
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
// This should be public
- assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, false);
- // This should be private
- assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_B, true);
+ assertDisplayPrivateFlag(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(),
+ PORT_A, false);
// This should be public
- assertDisplay(mListener.addedDisplays.get(2).getDisplayDeviceInfoLocked(), PORT_C, false);
+ assertDisplayPrivateFlag(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(),
+ PORT_B, true);
+ // This should be public
+ assertDisplayPrivateFlag(mListener.addedDisplays.get(2).getDisplayDeviceInfoLocked(),
+ PORT_C, false);
}
/**
@@ -141,12 +144,14 @@ public class LocalDisplayAdapterTest {
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
// This should be public
- assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, false);
+ assertDisplayPrivateFlag(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(),
+ PORT_A, false);
// This should be public
- assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_C, false);
+ assertDisplayPrivateFlag(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(),
+ PORT_C, false);
}
- private static void assertDisplay(
+ private static void assertDisplayPrivateFlag(
DisplayDeviceInfo info, int expectedPort, boolean shouldBePrivate) {
final DisplayAddress.Physical address = (DisplayAddress.Physical) info.address;
assertNotNull(address);
@@ -155,6 +160,39 @@ public class LocalDisplayAdapterTest {
assertEquals(shouldBePrivate, (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0);
}
+ /**
+ * Confirm that external display uses physical density.
+ */
+ @Test
+ public void testDpiValues() throws Exception {
+ // needs default one always
+ setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo()));
+ setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_B), createDummyDisplayInfo()));
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertDisplayDpi(
+ mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, 100, 100,
+ 16000);
+ assertDisplayDpi(
+ mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_B, 100, 100,
+ 16000);
+ }
+
+ private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort,
+ float expectedXdpi,
+ float expectedYDpi,
+ int expectedDensityDpi) {
+ final DisplayAddress.Physical physical = (DisplayAddress.Physical) info.address;
+ assertNotNull(physical);
+ assertEquals((byte) expectedPort, physical.getPort());
+ assertEquals(expectedXdpi, info.xDpi, 0.01);
+ assertEquals(expectedYDpi, info.yDpi, 0.01);
+ assertEquals(expectedDensityDpi, info.densityDpi);
+ }
+
private class DisplayConfig {
public final DisplayAddress.Physical address;
public final IBinder displayToken = new Binder();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index d70e1648f719..96d9c476bcde 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -73,7 +73,7 @@ public class AccessibilityUserStateTest {
@Mock private AccessibilityUserState.ServiceInfoChangeListener mMockListener;
- @Mock private Context mContext;
+ @Mock private Context mMockContext;
private MockContentResolver mMockResolver;
@@ -85,11 +85,11 @@ public class AccessibilityUserStateTest {
FakeSettingsProvider.clearSettingsProvider();
mMockResolver = new MockContentResolver();
mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
- when(mContext.getContentResolver()).thenReturn(mMockResolver);
+ when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
when(mMockServiceInfo.getComponentName()).thenReturn(COMPONENT_NAME);
when(mMockConnection.getServiceInfo()).thenReturn(mMockServiceInfo);
- mUserState = new AccessibilityUserState(USER_ID, mContext, mMockListener);
+ mUserState = new AccessibilityUserState(USER_ID, mMockContext, mMockListener);
}
@After
@@ -109,11 +109,11 @@ public class AccessibilityUserStateTest {
mUserState.setInteractiveUiTimeoutLocked(30);
mUserState.mEnabledServices.add(COMPONENT_NAME);
mUserState.mTouchExplorationGrantedServices.add(COMPONENT_NAME);
+ mUserState.mAccessibilityShortcutKeyTargets.add(COMPONENT_NAME.flattenToString());
+ mUserState.mAccessibilityButtonTargets.add(COMPONENT_NAME.flattenToString());
mUserState.setTouchExplorationEnabledLocked(true);
mUserState.setDisplayMagnificationEnabledLocked(true);
mUserState.setNavBarMagnificationEnabledLocked(true);
- mUserState.setServiceAssignedToAccessibilityButtonLocked(COMPONENT_NAME);
- mUserState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(true);
mUserState.setAutoclickEnabledLocked(true);
mUserState.setUserNonInteractiveUiTimeoutLocked(30);
mUserState.setUserInteractiveUiTimeoutLocked(30);
@@ -128,11 +128,11 @@ public class AccessibilityUserStateTest {
assertEquals(0, mUserState.getInteractiveUiTimeoutLocked());
assertTrue(mUserState.mEnabledServices.isEmpty());
assertTrue(mUserState.mTouchExplorationGrantedServices.isEmpty());
+ assertTrue(mUserState.mAccessibilityShortcutKeyTargets.isEmpty());
+ assertTrue(mUserState.mAccessibilityButtonTargets.isEmpty());
assertFalse(mUserState.isTouchExplorationEnabledLocked());
assertFalse(mUserState.isDisplayMagnificationEnabledLocked());
assertFalse(mUserState.isNavBarMagnificationEnabledLocked());
- assertNull(mUserState.getServiceAssignedToAccessibilityButtonLocked());
- assertFalse(mUserState.isNavBarMagnificationAssignedToAccessibilityButtonLocked());
assertFalse(mUserState.isAutoclickEnabledLocked());
assertEquals(0, mUserState.getUserNonInteractiveUiTimeoutLocked());
assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked());
@@ -287,6 +287,19 @@ public class AccessibilityUserStateTest {
verify(mMockConnection).notifySoftKeyboardShowModeChangedLocked(eq(SHOW_MODE_HIDDEN));
}
+ @Test
+ public void isShortcutTargetInstalledLocked_returnTrue() {
+ mUserState.mInstalledServices.add(mMockServiceInfo);
+ assertTrue(mUserState.isShortcutTargetInstalledLocked(COMPONENT_NAME.flattenToString()));
+ }
+
+ @Test
+ public void isShortcutTargetInstalledLocked_invalidTarget_returnFalse() {
+ final ComponentName invalidTarget =
+ new ComponentName("com.android.server.accessibility", "InvalidTarget");
+ assertFalse(mUserState.isShortcutTargetInstalledLocked(invalidTarget.flattenToString()));
+ }
+
private int getSecureIntForUser(String key, int userId) {
return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId);
}
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
new file mode 100644
index 000000000000..f6c4d3aa5f5f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.Handler;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AutomaticBrightnessControllerTest {
+
+ private static final int BRIGHTNESS_MIN = 1;
+ private static final int BRIGHTNESS_MAX = 255;
+ private static final int LIGHT_SENSOR_RATE = 20;
+ private static final int INITIAL_LIGHT_SENSOR_RATE = 20;
+ private static final int BRIGHTENING_LIGHT_DEBOUNCE_CONFIG = 0;
+ private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG = 0;
+ private static final int SHORT_TERM_MODEL_TIMEOUT = 0;
+ private static final float DOZE_SCALE_FACTOR = 0.0f;
+ private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false;
+
+ private Context mContext;
+ @Mock SensorManager mSensorManager;
+ @Mock BrightnessMappingStrategy mBrightnessMappingStrategy;
+ @Mock HysteresisLevels mAmbientBrightnessThresholds;
+ @Mock HysteresisLevels mScreenBrightnessThresholds;
+ @Mock PackageManager mPackageManager;
+ @Mock Handler mNoopHandler;
+
+ private static final int LIGHT_SENSOR_WARMUP_TIME = 0;
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ private AutomaticBrightnessController setupController(Sensor lightSensor) {
+ AutomaticBrightnessController controller = new AutomaticBrightnessController(
+ new AutomaticBrightnessController.Injector() {
+ @Override
+ public Handler getBackgroundThreadHandler() {
+ return mNoopHandler;
+ }
+ },
+ () -> { }, mContext.getMainLooper(), mSensorManager, lightSensor,
+ mBrightnessMappingStrategy, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN,
+ BRIGHTNESS_MAX, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE, INITIAL_LIGHT_SENSOR_RATE,
+ BRIGHTENING_LIGHT_DEBOUNCE_CONFIG, DARKENING_LIGHT_DEBOUNCE_CONFIG,
+ RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, mAmbientBrightnessThresholds,
+ mScreenBrightnessThresholds, SHORT_TERM_MODEL_TIMEOUT, mPackageManager);
+ controller.setLoggingEnabled(true);
+
+ // Configure the brightness controller and grab an instance of the sensor listener,
+ // through which we can deliver fake (for test) sensor values.
+ controller.configure(true /* enable */, null /* configuration */,
+ 0 /* brightness */, false /* userChangedBrightness */, 0 /* adjustment */,
+ false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
+
+ return controller;
+ }
+
+ @Test
+ public void testNoHysteresisAtMinBrightness() throws Exception {
+ Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
+ AutomaticBrightnessController controller = setupController(lightSensor);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Set up system to return 5 as a brightness value
+ float lux1 = 100.0f;
+ float normalizedBrightness1 = 0.02f;
+ when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1))
+ .thenReturn(lux1);
+ when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1))
+ .thenReturn(lux1);
+ when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt()))
+ .thenReturn(normalizedBrightness1);
+
+ // This is the important bit: When the new brightness is set, make sure the new
+ // brightening threshold is beyond the maximum brightness value...so that we can test that
+ // our threshold clamping works.
+ when(mScreenBrightnessThresholds.getBrighteningThreshold(5)).thenReturn(1.0f);
+
+ // Send new sensor value and verify
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux1));
+ assertEquals(5, controller.getAutomaticScreenBrightness());
+
+
+ // Set up system to return 255 as a brightness value
+ float lux2 = 10.0f;
+ float normalizedBrightness2 = 0.0f;
+ when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2))
+ .thenReturn(lux2);
+ when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2))
+ .thenReturn(lux2);
+ when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt()))
+ .thenReturn(normalizedBrightness2);
+
+ // Send new sensor value and verify
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux2));
+ assertEquals(1, controller.getAutomaticScreenBrightness());
+ }
+
+ @Test
+ public void testNoHysteresisAtMaxBrightness() throws Exception {
+ Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
+ AutomaticBrightnessController controller = setupController(lightSensor);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Set up system to return 250 as a brightness value
+ float lux1 = 100.0f;
+ float normalizedBrightness1 = 0.98f;
+ when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1))
+ .thenReturn(lux1);
+ when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1))
+ .thenReturn(lux1);
+ when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt()))
+ .thenReturn(normalizedBrightness1);
+
+ // This is the important bit: When the new brightness is set, make sure the new
+ // brightening threshold is beyond the maximum brightness value...so that we can test that
+ // our threshold clamping works.
+ when(mScreenBrightnessThresholds.getBrighteningThreshold(250)).thenReturn(260.0f);
+
+ // Send new sensor value and verify
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux1));
+ assertEquals(250, controller.getAutomaticScreenBrightness());
+
+
+ // Set up system to return 255 as a brightness value
+ float lux2 = 110.0f;
+ float normalizedBrightness2 = 1.0f;
+ when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2))
+ .thenReturn(lux2);
+ when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2))
+ .thenReturn(lux2);
+ when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt()))
+ .thenReturn(normalizedBrightness2);
+
+ // Send new sensor value and verify
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux2));
+ assertEquals(255, controller.getAutomaticScreenBrightness());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 4742a73b17a8..8d5939ad6ef6 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.display;
diff --git a/services/tests/servicestests/src/com/android/server/display/TestUtils.java b/services/tests/servicestests/src/com/android/server/display/TestUtils.java
new file mode 100644
index 000000000000..859dfe3c3fa4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/TestUtils.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.os.SystemClock;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public final class TestUtils {
+
+ public static SensorEvent createSensorEvent(Sensor sensor, int lux) throws Exception {
+ final Constructor<SensorEvent> constructor =
+ SensorEvent.class.getDeclaredConstructor(int.class);
+ constructor.setAccessible(true);
+ final SensorEvent event = constructor.newInstance(1);
+ event.sensor = sensor;
+ event.values[0] = lux;
+ event.timestamp = SystemClock.elapsedRealtimeNanos();
+ return event;
+ }
+
+
+ public static void setSensorType(Sensor sensor, int type, String strType) throws Exception {
+ Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
+ setter.setAccessible(true);
+ setter.invoke(sensor, type);
+ if (strType != null) {
+ Field f = sensor.getClass().getDeclaredField("mStringType");
+ f.setAccessible(true);
+ f.set(sensor, strType);
+ }
+ }
+
+ public static Sensor createSensor(int type, String strType) throws Exception {
+ Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
+ constr.setAccessible(true);
+ Sensor sensor = constr.newInstance();
+ setSensorType(sensor, type, strType);
+ return sensor;
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
index acf2d0e700d4..2565ae3b4a85 100644
--- a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
@@ -16,31 +16,19 @@
package com.android.server.display.whitebalance;
-import com.android.internal.R;
-import com.android.server.display.utils.AmbientFilter;
-import com.android.server.display.utils.AmbientFilterStubber;
-import com.google.common.collect.ImmutableList;
-
import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
-import org.mockito.stubbing.Answer;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Looper;
@@ -48,15 +36,22 @@ import android.util.TypedValue;
import androidx.test.InstrumentationRegistry;
+import com.android.internal.R;
+import com.android.server.display.TestUtils;
+import com.android.server.display.utils.AmbientFilter;
+import com.android.server.display.utils.AmbientFilterStubber;
+
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
-import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.List;
@RunWith(JUnit4.class)
@@ -84,8 +79,8 @@ public final class AmbientLuxTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mLightSensor = createSensor(Sensor.TYPE_LIGHT, null);
- mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
+ mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, null);
+ mAmbientColorSensor = TestUtils.createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
mResourcesSpy = spy(mContextSpy.getResources());
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
@@ -482,25 +477,6 @@ public final class AmbientLuxTest {
}
}
- private void setSensorType(Sensor sensor, int type, String strType) throws Exception {
- Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
- setter.setAccessible(true);
- setter.invoke(sensor, type);
- if (strType != null) {
- Field f = sensor.getClass().getDeclaredField("mStringType");
- f.setAccessible(true);
- f.set(sensor, strType);
- }
- }
-
- private Sensor createSensor(int type, String strType) throws Exception {
- Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
- constr.setAccessible(true);
- Sensor sensor = constr.newInstance();
- setSensorType(sensor, type, strType);
- return sensor;
- }
-
private TypedArray createTypedArray() throws Exception {
TypedArray mockArray = mock(TypedArray.class);
return mockArray;
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java
index 6ff4f3b22b9c..3e3e535df986 100644
--- a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java
@@ -28,15 +28,14 @@ import static org.mockito.Mockito.when;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.hardware.Sensor;
-import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Looper;
-import android.os.SystemClock;
import androidx.test.InstrumentationRegistry;
+import com.android.server.display.TestUtils;
import com.android.server.display.whitebalance.AmbientSensor.AmbientBrightnessSensor;
import com.android.server.display.whitebalance.AmbientSensor.AmbientColorTemperatureSensor;
@@ -50,9 +49,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -73,8 +69,8 @@ public final class AmbientSensorTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mLightSensor = createSensor(Sensor.TYPE_LIGHT, null);
- mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
+ mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, null);
+ mAmbientColorSensor = TestUtils.createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
mResourcesSpy = spy(mContextSpy.getResources());
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
@@ -96,7 +92,7 @@ public final class AmbientSensorTest {
// There should be no issues when we callback the listener, even if there is no callback
// set.
SensorEventListener listener = captor.getValue();
- listener.onSensorChanged(createSensorEvent(mLightSensor, 100));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 100));
}
@Test
@@ -122,7 +118,7 @@ public final class AmbientSensorTest {
verify(mSensorManagerMock).registerListener(captor.capture(), eq(mLightSensor),
anyInt(), eq(mHandler));
SensorEventListener listener = captor.getValue();
- listener.onSensorChanged(createSensorEvent(mLightSensor, luxValue));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, luxValue));
assertTrue(changeSignal.await(5, TimeUnit.SECONDS));
assertEquals(luxValue, luxReturned[0]);
}
@@ -155,39 +151,8 @@ public final class AmbientSensorTest {
verify(mSensorManagerMock).registerListener(captor.capture(), eq(mAmbientColorSensor),
anyInt(), eq(mHandler));
SensorEventListener listener = captor.getValue();
- listener.onSensorChanged(createSensorEvent(mAmbientColorSensor, colorTempValue));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mAmbientColorSensor, colorTempValue));
assertTrue(changeSignal.await(5, TimeUnit.SECONDS));
assertEquals(colorTempValue, colorTempReturned[0]);
}
-
- private SensorEvent createSensorEvent(Sensor sensor, int lux) throws Exception {
- final Constructor<SensorEvent> constructor =
- SensorEvent.class.getDeclaredConstructor(int.class);
- constructor.setAccessible(true);
- final SensorEvent event = constructor.newInstance(1);
- event.sensor = sensor;
- event.values[0] = lux;
- event.timestamp = SystemClock.elapsedRealtimeNanos();
- return event;
- }
-
-
- private void setSensorType(Sensor sensor, int type, String strType) throws Exception {
- Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
- setter.setAccessible(true);
- setter.invoke(sensor, type);
- if (strType != null) {
- Field f = sensor.getClass().getDeclaredField("mStringType");
- f.setAccessible(true);
- f.set(sensor, strType);
- }
- }
-
- private Sensor createSensor(int type, String strType) throws Exception {
- Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
- constr.setAccessible(true);
- Sensor sensor = constr.newInstance();
- setSensorType(sensor, type, strType);
- return sensor;
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
new file mode 100644
index 000000000000..37ff06a18492
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity;
+
+import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
+
+import static org.mockito.Mockito.verify;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */
+@RunWith(AndroidJUnit4.class)
+public class AppIntegrityManagerServiceImplTest {
+
+ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock PackageManagerInternal mPackageManagerInternal;
+
+ // under test
+ private AppIntegrityManagerServiceImpl mService;
+
+ @Before
+ public void setup() {
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
+
+ mService = new AppIntegrityManagerServiceImpl(InstrumentationRegistry.getContext());
+ }
+
+ @Test
+ public void integrityVerification_allow() {
+ int verificationId = 2;
+ Intent integrityVerificationIntent = new Intent();
+ integrityVerificationIntent.setAction(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
+ integrityVerificationIntent.putExtra(EXTRA_VERIFICATION_ID, verificationId);
+
+ // We cannot send the broadcast using the context since it is a protected broadcast and
+ // we will get a security exception.
+ mService.handleIntegrityVerification(integrityVerificationIntent);
+
+ verify(mPackageManagerInternal)
+ .setIntegrityVerificationResult(verificationId, PackageManager.VERIFICATION_ALLOW);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java
new file mode 100644
index 000000000000..18b91b0b1009
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.serializer;
+
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+/** Unit tests for {@link RuleIndexTypeIdentifier}. */
+@RunWith(JUnit4.class)
+public class RuleIndexTypeIdentifierTest {
+
+ @Test
+ public void getIndexType_nullRule() {
+ Rule rule = null;
+
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex= */
+ "Indexing type cannot be determined for null rule.",
+ () -> RuleIndexTypeIdentifier.getIndexType(rule));
+ }
+
+ @Test
+ public void getIndexType_invalidFormula() {
+ Rule rule = new Rule(getInvalidFormula(), Rule.DENY);
+
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex= */ "Invalid formula tag type.",
+ () -> RuleIndexTypeIdentifier.getIndexType(rule));
+ }
+
+ @Test
+ public void getIndexType_ruleContainingPackageNameFormula() {
+ String packageName = "com.test.app";
+ String installerName = "com.test.installer";
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ packageName,
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.INSTALLER_NAME,
+ installerName,
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+
+ assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+ .isEqualTo(RuleIndexTypeIdentifier.PACKAGE_NAME_INDEXED);
+ }
+
+ @Test
+ public void getIndexType_ruleContainingAppCertificateFormula() {
+ String appCertificate = "cert1";
+ String installerName = "com.test.installer";
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE,
+ appCertificate,
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.INSTALLER_NAME,
+ installerName,
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+
+ assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+ .isEqualTo(RuleIndexTypeIdentifier.APP_CERTIFICATE_INDEXED);
+ }
+
+ @Test
+ public void getIndexType_ruleWithUnindexedCompoundFormula() {
+ String installerCertificate = "cert1";
+ String installerName = "com.test.installer";
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.INSTALLER_CERTIFICATE,
+ installerCertificate,
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.INSTALLER_NAME,
+ installerName,
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+
+ assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+ .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
+ }
+
+ @Test
+ public void getIndexType_rulContainingCompoundFormulaWithIntAndBoolean() {
+ int appVersion = 12;
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(
+ new AtomicFormula.BooleanAtomicFormula(
+ AtomicFormula.PRE_INSTALLED,
+ /* booleanValue= */ true),
+ new AtomicFormula.IntAtomicFormula(
+ AtomicFormula.VERSION_CODE,
+ AtomicFormula.EQ,
+ appVersion))),
+ Rule.DENY);
+
+ assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+ .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
+ }
+
+ @Test
+ public void getIndexType_negatedRuleContainingPackageNameFormula() {
+ String packageName = "com.test.app";
+ String installerName = "com.test.installer";
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.NOT,
+ Arrays.asList(
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ packageName,
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.INSTALLER_NAME,
+ installerName,
+ /* isHashedValue= */ false))))),
+ Rule.DENY);
+
+ assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+ .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
+ }
+
+ private Formula getInvalidFormula() {
+ return new Formula() {
+ @Override
+ public boolean isSatisfied(AppInstallMetadata appInstallMetadata) {
+ return false;
+ }
+
+ @Override
+ public int getTag() {
+ return 4;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ @NonNull
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ }
+ };
+ }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index f6fb6e23ccfb..4fc625a1e1fb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -26,9 +26,12 @@ import static org.mockito.Mockito.when;
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.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsingPackage;
import android.os.Build;
import android.os.Process;
import android.util.ArrayMap;
@@ -51,45 +54,54 @@ public class AppsFilterTest {
private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>();
- private static PackageBuilder pkg(String packageName) {
- return new PackageBuilder(packageName)
- .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.R);
+ private static ParsingPackage pkg(String packageName) {
+ return PackageImpl.forParsing(packageName)
+ .setTargetSdkVersion(Build.VERSION_CODES.R);
}
- private static PackageBuilder pkg(String packageName, Intent... queries) {
- return pkg(packageName).setQueriesIntents(queries);
+ private static ParsingPackage pkg(String packageName, Intent... queries) {
+ ParsingPackage pkg = pkg(packageName);
+ if (queries != null) {
+ for (Intent intent : queries) {
+ pkg.addQueriesIntent(intent);
+ }
+ }
+ return pkg;
}
- private static PackageBuilder pkg(String packageName, String... queriesPackages) {
- return pkg(packageName).setQueriesPackages(queriesPackages);
+ private static ParsingPackage pkg(String packageName, String... queriesPackages) {
+ ParsingPackage pkg = pkg(packageName);
+ if (queriesPackages != null) {
+ for (String queryPackageName : queriesPackages) {
+ pkg.addQueriesPackage(queryPackageName);
+ }
+ }
+ return pkg;
}
- private static PackageBuilder pkg(String packageName, IntentFilter... filters) {
- final ActivityInfo activityInfo = new ActivityInfo();
- final PackageBuilder packageBuilder = pkg(packageName).addActivity(
- pkg -> new PackageParser.ParseComponentArgs(pkg, new String[1], 0, 0, 0, 0, 0, 0,
- new String[]{packageName}, 0, 0, 0), activityInfo);
+ private static ParsingPackage pkg(String packageName, IntentFilter... filters) {
+ ParsedActivity activity = new ParsedActivity();
+ activity.setPackageName(packageName);
for (IntentFilter filter : filters) {
- packageBuilder.addActivityIntentInfo(0 /* index */, activity -> {
- final PackageParser.ActivityIntentInfo info =
- new PackageParser.ActivityIntentInfo(activity);
- if (filter.countActions() > 0) {
- filter.actionsIterator().forEachRemaining(info::addAction);
- }
- if (filter.countCategories() > 0) {
- filter.actionsIterator().forEachRemaining(info::addCategory);
- }
- if (filter.countDataAuthorities() > 0) {
- filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
- }
- if (filter.countDataSchemes() > 0) {
- filter.schemesIterator().forEachRemaining(info::addDataScheme);
- }
- activityInfo.exported = true;
- return info;
- });
+ final ParsedActivityIntentInfo info = new ParsedActivityIntentInfo(packageName, null);
+ if (filter.countActions() > 0) {
+ filter.actionsIterator().forEachRemaining(info::addAction);
+ }
+ if (filter.countCategories() > 0) {
+ filter.actionsIterator().forEachRemaining(info::addAction);
+ }
+ if (filter.countDataAuthorities() > 0) {
+ filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
+ }
+ if (filter.countDataSchemes() > 0) {
+ filter.schemesIterator().forEachRemaining(info::addDataScheme);
+ }
+ activity.addIntent(info);
+ activity.exported = true;
}
- return packageBuilder;
+
+ return pkg(packageName)
+ .addActivity(activity);
}
@Before
@@ -98,7 +110,7 @@ public class AppsFilterTest {
MockitoAnnotations.initMocks(this);
when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
- when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+ when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
.thenReturn(true);
}
@@ -146,7 +158,7 @@ public class AppsFilterTest {
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.some.other.package",
new Intent("TEST_ACTION"))
- .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.P),
+ .setTargetSdkVersion(Build.VERSION_CODES.P),
DUMMY_CALLING_UID);
when(mFeatureConfigMock.packageIsEnabled(calling.pkg)).thenReturn(false);
@@ -238,7 +250,7 @@ public class AppsFilterTest {
@Test
public void testNoQueries_FeatureOff_DoesntFilter() {
- when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+ when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
.thenReturn(false);
final AppsFilter appsFilter =
new AppsFilter(mFeatureConfigMock, new String[]{}, false);
@@ -297,25 +309,25 @@ public class AppsFilterTest {
}
private PackageSetting simulateAddPackage(AppsFilter filter,
- PackageBuilder newPkgBuilder, int appId) {
+ ParsingPackage newPkgBuilder, int appId) {
return simulateAddPackage(filter, newPkgBuilder, appId, null);
}
private PackageSetting simulateAddPackage(AppsFilter filter,
- PackageBuilder newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
- PackageParser.Package newPkg = newPkgBuilder.build();
+ ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
+ AndroidPackage newPkg = newPkgBuilder.hideAsParsed().hideAsFinal();
final PackageSettingBuilder settingBuilder = new PackageSettingBuilder()
.setPackage(newPkg)
.setAppId(appId)
- .setName(newPkg.packageName)
+ .setName(newPkg.getPackageName())
.setCodePath("/")
.setResourcePath("/")
.setPVersionCode(1L);
final PackageSetting setting =
(action == null ? settingBuilder : action.withBuilder(settingBuilder)).build();
filter.addPackage(setting, mExisting);
- mExisting.put(newPkg.packageName, setting);
+ mExisting.put(newPkg.getPackageName(), setting);
return setting;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index fec3267c2649..0273a1c5d86e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -19,17 +19,17 @@ package com.android.server.pm;
import android.content.pm.PackageParser;
import android.content.pm.Signature;
+import android.test.AndroidTestCase;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseArray;
+
import com.android.internal.util.ArrayUtils;
import java.io.File;
import java.io.IOException;
-import java.security.cert.CertificateException;
import java.security.PublicKey;
-
-import android.test.AndroidTestCase;
+import java.security.cert.CertificateException;
public class KeySetManagerServiceTest extends AndroidTestCase {
@@ -39,7 +39,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase {
public PackageSetting generateFakePackageSetting(String name) {
return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
- "", 1, 0, 0, null, null, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
+ "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
deleted file mode 100644
index c38672cfc93c..000000000000
--- a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageParser;
-
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-
-class PackageBuilder {
- final PackageParser.Package mPkg;
-
- PackageBuilder(String packageName) {
- mPkg = new PackageParser.Package(packageName);
- }
-
- PackageBuilder setApplicationInfoCodePath(String codePath) {
- mPkg.applicationInfo.setCodePath(codePath);
- return this;
- }
-
- PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
- mPkg.applicationInfo.setResourcePath(resourcePath);
- return this;
- }
-
- PackageBuilder setCodePath(String codePath) {
- mPkg.codePath = codePath;
- return this;
- }
-
- PackageBuilder setBaseCodePath(String baseCodePath) {
- mPkg.baseCodePath = baseCodePath;
- return this;
- }
-
- PackageBuilder addUsesStaticLibrary(String name, long version) {
- mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
- mPkg.usesStaticLibrariesVersions =
- ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
- return this;
- }
-
- PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
- mPkg.applicationInfo.nativeLibraryRootDir = dir;
- return this;
- }
-
- PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
- mPkg.staticSharedLibVersion = staticSharedLibVersion;
- mPkg.staticSharedLibName = staticSharedLibName;
- return this;
- }
-
- PackageBuilder setManifestPackageName(String manifestPackageName) {
- mPkg.manifestPackageName = manifestPackageName;
- return this;
- }
-
- PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
- mPkg.mVersionCodeMajor = versionCodeMajor;
- return this;
- }
-
- PackageBuilder setVersionCode(int versionCode) {
- mPkg.mVersionCode = versionCode;
- return this;
- }
-
- PackageBuilder addSplitCodePath(String splitCodePath) {
- mPkg.splitCodePaths =
- ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
- return this;
- }
-
- PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
- mPkg.applicationInfo.volumeUuid = volumeUuid;
- return this;
- }
-
- PackageBuilder addLibraryName(String libraryName) {
- mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
- return this;
- }
-
- PackageBuilder setRealPackageName(String realPackageName) {
- mPkg.mRealPackage = realPackageName;
- return this;
- }
-
- PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
- mPkg.cpuAbiOverride = cpuAbiOverride;
- return this;
- }
-
- PackageBuilder addPermissionRequest(String permissionName) {
- mPkg.requestedPermissions.add(permissionName);
- return this;
- }
-
- PackageParser.Package build() {
- return mPkg;
- }
-
- public PackageBuilder addApplicationInfoFlag(int flag) {
- mPkg.applicationInfo.flags |= flag;
- return this;
- }
-
- public PackageBuilder setApplicationInfoTargetSdkVersion(int versionCode) {
- mPkg.applicationInfo.targetSdkVersion = versionCode;
- return this;
- }
-
- public PackageBuilder setQueriesIntents(Collection<Intent> queriesIntents) {
- mPkg.mQueriesIntents = new ArrayList<>(queriesIntents);
- return this;
- }
-
- public PackageBuilder setQueriesIntents(Intent... intents) {
- return setQueriesIntents(Arrays.asList(intents));
- }
-
- public PackageBuilder setQueriesPackages(Collection<String> queriesPackages) {
- mPkg.mQueriesPackages = new ArrayList<>(queriesPackages);
- return this;
- }
-
- public PackageBuilder setQueriesPackages(String... queriesPackages) {
- return setQueriesPackages(Arrays.asList(queriesPackages));
- }
-
- public PackageBuilder setForceQueryable(boolean forceQueryable) {
- mPkg.mForceQueryable = forceQueryable;
- return this;
- }
-
- public interface ParseComponentArgsCreator {
- PackageParser.ParseComponentArgs create(PackageParser.Package pkg);
- }
-
- public PackageBuilder addActivity(ParseComponentArgsCreator argsCreator, ActivityInfo info) {
- mPkg.activities.add(new PackageParser.Activity(argsCreator.create(mPkg), info));
- return this;
- }
-
- public interface ActivityIntentInfoCreator {
- PackageParser.ActivityIntentInfo create(PackageParser.Activity activity);
- }
-
- public PackageBuilder addActivityIntentInfo(
- int activityIndex, ActivityIntentInfoCreator creator) {
- final PackageParser.Activity activity = mPkg.activities.get(activityIndex);
- activity.intents.add(creator.create(activity));
- return this;
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 0a310d193675..85840e135909 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -87,7 +87,7 @@ public class PackageManagerServiceTest {
setting = new PackageSetting("name", "realName", new File("codePath"),
new File("resourcePath"), "legacyNativeLibraryPathString",
"primaryCpuAbiString", "secondaryCpuAbiString",
- "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0,
+ "cpuAbiOverrideString", 0, 0, 0, 0,
null, null);
pri.populateUsers(new int[] {
1, 2, 3, 4, 5
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 1106be2d5f6b..8329227360e7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -403,10 +403,6 @@ public class PackageManagerSettingsTests {
private static final String PACKAGE_NAME = "com.android.bar";
private static final String REAL_PACKAGE_NAME = "com.android.foo";
- private static final String PARENT_PACKAGE_NAME = "com.android.bar.parent";
- private static final String CHILD_PACKAGE_NAME_01 = "com.android.bar.child01";
- private static final String CHILD_PACKAGE_NAME_02 = "com.android.bar.child02";
- private static final String CHILD_PACKAGE_NAME_03 = "com.android.bar.child03";
private static final File INITIAL_CODE_PATH =
new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1");
private static final File UPDATED_CODE_PATH =
@@ -416,10 +412,6 @@ public class PackageManagerSettingsTests {
@Test
public void testPackageStateCopy01() {
- final List<String> childPackageNames = new ArrayList<>();
- childPackageNames.add(CHILD_PACKAGE_NAME_01);
- childPackageNames.add(CHILD_PACKAGE_NAME_02);
- childPackageNames.add(CHILD_PACKAGE_NAME_03);
final PackageSetting origPkgSetting01 = new PackageSetting(
PACKAGE_NAME,
REAL_PACKAGE_NAME,
@@ -432,8 +424,6 @@ public class PackageManagerSettingsTests {
INITIAL_VERSION_CODE,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
- PARENT_PACKAGE_NAME,
- childPackageNames,
0,
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -443,10 +433,6 @@ public class PackageManagerSettingsTests {
@Test
public void testPackageStateCopy02() {
- final List<String> childPackageNames = new ArrayList<>();
- childPackageNames.add(CHILD_PACKAGE_NAME_01);
- childPackageNames.add(CHILD_PACKAGE_NAME_02);
- childPackageNames.add(CHILD_PACKAGE_NAME_03);
final PackageSetting origPkgSetting01 = new PackageSetting(
PACKAGE_NAME /*pkgName*/,
REAL_PACKAGE_NAME /*realPkgName*/,
@@ -459,8 +445,6 @@ public class PackageManagerSettingsTests {
INITIAL_VERSION_CODE,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
- PARENT_PACKAGE_NAME,
- childPackageNames,
0,
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -476,8 +460,6 @@ public class PackageManagerSettingsTests {
UPDATED_VERSION_CODE,
0 /*pkgFlags*/,
0 /*pkgPrivateFlags*/,
- null /*parentPkgName*/,
- null /*childPkgNames*/,
0,
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -505,7 +487,6 @@ public class PackageManagerSettingsTests {
"armeabi" /*secondaryCpuAbi*/,
0 /*pkgFlags*/,
0 /*pkgPrivateFlags*/,
- null /*childPkgNames*/,
UserManagerService.getInstance(),
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -539,7 +520,6 @@ public class PackageManagerSettingsTests {
"armeabi" /*secondaryCpuAbi*/,
ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/,
ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/,
- null /*childPkgNames*/,
UserManagerService.getInstance(),
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -579,7 +559,6 @@ public class PackageManagerSettingsTests {
"armeabi" /*secondaryCpuAbi*/,
0 /*pkgFlags*/,
0 /*pkgPrivateFlags*/,
- null /*childPkgNames*/,
UserManagerService.getInstance(),
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -612,8 +591,6 @@ public class PackageManagerSettingsTests {
false /*allowInstall*/,
false /*instantApp*/,
false /*virtualPreload*/,
- null /*parentPkgName*/,
- null /*childPkgNames*/,
UserManagerService.getInstance(),
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -653,8 +630,6 @@ public class PackageManagerSettingsTests {
true /*allowInstall*/,
false /*instantApp*/,
false /*virtualPreload*/,
- null /*parentPkgName*/,
- null /*childPkgNames*/,
UserManagerService.getInstance(),
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -700,8 +675,6 @@ public class PackageManagerSettingsTests {
false /*allowInstall*/,
false /*instantApp*/,
false /*virtualPreload*/,
- null /*parentPkgName*/,
- null /*childPkgNames*/,
UserManagerService.getInstance(),
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -744,8 +717,6 @@ public class PackageManagerSettingsTests {
false /*allowInstall*/,
false /*instantApp*/,
false /*virtualPreload*/,
- null /*parentPkgName*/,
- null /*childPkgNames*/,
UserManagerService.getInstance(),
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -802,9 +773,6 @@ public class PackageManagerSettingsTests {
private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
assertThat(origPkgSetting, is(not(testPkgSetting)));
assertThat(origPkgSetting.appId, is(testPkgSetting.appId));
- // different but equal objects
- assertNotSame(origPkgSetting.childPackageNames, testPkgSetting.childPackageNames);
- assertThat(origPkgSetting.childPackageNames, is(testPkgSetting.childPackageNames));
assertSame(origPkgSetting.codePath, testPkgSetting.codePath);
assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath));
assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString);
@@ -828,8 +796,6 @@ public class PackageManagerSettingsTests {
// mOldCodePaths is _not_ copied
// assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths);
// assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths)));
- assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName);
- assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName));
assertSame(origPkgSetting.pkg, testPkgSetting.pkg);
// No equals() method for this object
// assertThat(origPkgSetting.pkg, is(testPkgSetting.pkg));
@@ -881,8 +847,6 @@ public class PackageManagerSettingsTests {
INITIAL_VERSION_CODE,
pkgFlags,
0 /*privateFlags*/,
- null /*parentPackageName*/,
- null /*childPackageNames*/,
sharedUserId,
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
@@ -901,8 +865,6 @@ public class PackageManagerSettingsTests {
INITIAL_VERSION_CODE,
0,
0 /*privateFlags*/,
- null /*parentPackageName*/,
- null /*childPackageNames*/,
0,
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e33d8ca66ed0..56ac7c55443e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,35 +15,49 @@
*/
package com.android.server.pm;
-import static android.content.res.Resources.ID_NULL;
-
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
-import android.content.Intent;
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.InstrumentationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
import android.os.Bundle;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.util.ArrayMap;
import android.util.ArraySet;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.ArrayUtils;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -57,6 +71,7 @@ import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -64,6 +79,9 @@ import java.util.Set;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class PackageParserTest {
+ // TODO(b/135203078): Update this test with all fields and validate equality. Initial change
+ // was just migrating to new interfaces. Consider adding actual equals() methods.
+
@Rule
public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -79,12 +97,12 @@ public class PackageParserTest {
@Test
public void testParse_noCache() throws Exception {
PackageParser pp = new CachePackageNameParser();
- PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+ ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
false /* useCaches */);
assertNotNull(pkg);
pp.setCacheDir(mTmpDir);
- pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+ pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
false /* useCaches */);
assertNotNull(pkg);
@@ -99,27 +117,27 @@ public class PackageParserTest {
pp.setCacheDir(mTmpDir);
// The first parse will write this package to the cache.
- pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+ pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
// Now attempt to parse the package again, should return the
// cached result.
- PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+ ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
true /* useCaches */);
- assertEquals("cache_android", pkg.packageName);
+ assertEquals("cache_android", pkg.getPackageName());
// Try again, with useCaches == false, shouldn't return the parsed
// result.
- pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
- assertEquals("android", pkg.packageName);
+ pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+ assertEquals("android", pkg.getPackageName());
// We haven't set a cache directory here : the parse should still succeed,
// just not using the cached results.
pp = new CachePackageNameParser();
- pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
- assertEquals("android", pkg.packageName);
+ pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+ assertEquals("android", pkg.getPackageName());
- pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
- assertEquals("android", pkg.packageName);
+ pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+ assertEquals("android", pkg.getPackageName());
}
@Test
@@ -127,14 +145,14 @@ public class PackageParserTest {
PackageParser pp = new PackageParser();
pp.setCacheDir(mTmpDir);
- PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
- true /* useCaches */);
+ ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
+ true /* useCaches */);
Parcel p = Parcel.obtain();
pkg.writeToParcel(p, 0 /* flags */);
p.setDataPosition(0);
- PackageParser.Package deserialized = new PackageParser.Package(p);
+ ParsedPackage deserialized = new PackageImpl(p);
assertPackagesEqual(pkg, deserialized);
}
@@ -143,46 +161,52 @@ public class PackageParserTest {
@SmallTest
@Presubmit
public void test_roundTripKnownFields() throws Exception {
- PackageParser.Package pkg = new PackageParser.Package("foo");
+ ParsingPackage pkg = PackageImpl.forParsing("foo");
setKnownFields(pkg);
Parcel p = Parcel.obtain();
pkg.writeToParcel(p, 0 /* flags */);
p.setDataPosition(0);
- PackageParser.Package deserialized = new PackageParser.Package(p);
+ ParsedPackage deserialized = new PackageImpl(p);
assertAllFieldsExist(deserialized);
}
@Test
public void test_stringInterning() throws Exception {
- PackageParser.Package pkg = new PackageParser.Package("foo");
+ ParsingPackage pkg = PackageImpl.forParsing("foo");
setKnownFields(pkg);
Parcel p = Parcel.obtain();
pkg.writeToParcel(p, 0 /* flags */);
p.setDataPosition(0);
- PackageParser.Package deserialized = new PackageParser.Package(p);
+ ParsingPackage deserialized = new PackageImpl(p);
p.setDataPosition(0);
- PackageParser.Package deserialized2 = new PackageParser.Package(p);
-
- assertSame(deserialized.packageName, deserialized2.packageName);
- assertSame(deserialized.applicationInfo.permission,
- deserialized2.applicationInfo.permission);
- assertSame(deserialized.requestedPermissions.get(0),
- deserialized2.requestedPermissions.get(0));
- assertSame(deserialized.protectedBroadcasts.get(0),
- deserialized2.protectedBroadcasts.get(0));
- assertSame(deserialized.usesLibraries.get(0),
- deserialized2.usesLibraries.get(0));
- assertSame(deserialized.usesOptionalLibraries.get(0),
- deserialized2.usesOptionalLibraries.get(0));
- assertSame(deserialized.mVersionName, deserialized2.mVersionName);
- assertSame(deserialized.mSharedUserId, deserialized2.mSharedUserId);
- }
+ ParsingPackage deserialized2 = new PackageImpl(p);
+ assertSame(deserialized.getPackageName(), deserialized2.getPackageName());
+ assertSame(deserialized.getPermission(),
+ deserialized2.getPermission());
+ assertSame(deserialized.getRequestedPermissions().get(0),
+ deserialized2.getRequestedPermissions().get(0));
+
+ List<String> protectedBroadcastsOne = new ArrayList<>(1);
+ protectedBroadcastsOne.addAll(deserialized.getProtectedBroadcasts());
+
+ List<String> protectedBroadcastsTwo = new ArrayList<>(1);
+ protectedBroadcastsTwo.addAll(deserialized2.getProtectedBroadcasts());
+
+ assertSame(protectedBroadcastsOne.get(0), protectedBroadcastsTwo.get(0));
+
+ assertSame(deserialized.getUsesLibraries().get(0),
+ deserialized2.getUsesLibraries().get(0));
+ assertSame(deserialized.getUsesOptionalLibraries().get(0),
+ deserialized2.getUsesOptionalLibraries().get(0));
+ assertSame(deserialized.getVersionName(), deserialized2.getVersionName());
+ assertSame(deserialized.getSharedUserId(), deserialized2.getSharedUserId());
+ }
/**
* A trivial subclass of package parser that only caches the package name, and throws away
@@ -190,107 +214,111 @@ public class PackageParserTest {
*/
public static class CachePackageNameParser extends PackageParser {
@Override
- public byte[] toCacheEntry(Package pkg) {
- return ("cache_" + pkg.packageName).getBytes(StandardCharsets.UTF_8);
+ public byte[] toCacheEntry(ParsedPackage pkg) {
+ return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8);
}
@Override
- public Package fromCacheEntry(byte[] cacheEntry) {
- return new Package(new String(cacheEntry, StandardCharsets.UTF_8));
+ public ParsedPackage fromCacheEntry(byte[] cacheEntry) {
+ return PackageImpl.forParsing(new String(cacheEntry, StandardCharsets.UTF_8))
+ .hideAsParsed();
}
}
// NOTE: The equality assertions below are based on code autogenerated by IntelliJ.
- public static void assertPackagesEqual(PackageParser.Package a, PackageParser.Package b) {
- assertEquals(a.baseRevisionCode, b.baseRevisionCode);
- assertEquals(a.baseHardwareAccelerated, b.baseHardwareAccelerated);
- assertEquals(a.mVersionCode, b.mVersionCode);
- assertEquals(a.mSharedUserLabel, b.mSharedUserLabel);
- assertEquals(a.mPreferredOrder, b.mPreferredOrder);
- assertEquals(a.installLocation, b.installLocation);
- assertEquals(a.coreApp, b.coreApp);
- assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers);
- assertEquals(a.mCompileSdkVersion, b.mCompileSdkVersion);
- assertEquals(a.mCompileSdkVersionCodename, b.mCompileSdkVersionCodename);
- assertEquals(a.use32bitAbi, b.use32bitAbi);
- assertEquals(a.packageName, b.packageName);
- assertTrue(Arrays.equals(a.splitNames, b.splitNames));
- assertEquals(a.volumeUuid, b.volumeUuid);
- assertEquals(a.codePath, b.codePath);
- assertEquals(a.baseCodePath, b.baseCodePath);
- assertTrue(Arrays.equals(a.splitCodePaths, b.splitCodePaths));
- assertTrue(Arrays.equals(a.splitRevisionCodes, b.splitRevisionCodes));
- assertTrue(Arrays.equals(a.splitFlags, b.splitFlags));
- assertTrue(Arrays.equals(a.splitPrivateFlags, b.splitPrivateFlags));
- assertApplicationInfoEqual(a.applicationInfo, b.applicationInfo);
-
- assertEquals(a.permissions.size(), b.permissions.size());
- for (int i = 0; i < a.permissions.size(); ++i) {
- assertPermissionsEqual(a.permissions.get(i), b.permissions.get(i));
- assertSame(a.permissions.get(i).owner, a);
- assertSame(b.permissions.get(i).owner, b);
+ public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) {
+ assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
+ assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated());
+ assertEquals(a.getVersionCode(), b.getVersionCode());
+ assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel());
+ assertEquals(a.getPreferredOrder(), b.getPreferredOrder());
+ assertEquals(a.getInstallLocation(), b.getInstallLocation());
+ assertEquals(a.isCoreApp(), b.isCoreApp());
+ assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
+ assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion());
+ assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName());
+ assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi());
+ assertEquals(a.getPackageName(), b.getPackageName());
+ assertArrayEquals(a.getSplitNames(), b.getSplitNames());
+ assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
+ assertEquals(a.getCodePath(), b.getCodePath());
+ assertEquals(a.getBaseCodePath(), b.getBaseCodePath());
+ assertArrayEquals(a.getSplitCodePaths(), b.getSplitCodePaths());
+ assertArrayEquals(a.getSplitRevisionCodes(), b.getSplitRevisionCodes());
+ assertArrayEquals(a.getSplitFlags(), b.getSplitFlags());
+
+ PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0,
+ Collections.emptySet(), new PackageUserState(), 0);
+ PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0,
+ Collections.emptySet(), new PackageUserState(), 0);
+ assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+
+ assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions()));
+ for (int i = 0; i < ArrayUtils.size(a.getPermissions()); ++i) {
+ assertPermissionsEqual(a.getPermissions().get(i), b.getPermissions().get(i));
}
- assertEquals(a.permissionGroups.size(), b.permissionGroups.size());
- for (int i = 0; i < a.permissionGroups.size(); ++i) {
- assertPermissionGroupsEqual(a.permissionGroups.get(i), b.permissionGroups.get(i));
+ assertEquals(ArrayUtils.size(a.getPermissionGroups()),
+ ArrayUtils.size(b.getPermissionGroups()));
+ for (int i = 0; i < a.getPermissionGroups().size(); ++i) {
+ assertPermissionGroupsEqual(a.getPermissionGroups().get(i),
+ b.getPermissionGroups().get(i));
}
- assertEquals(a.activities.size(), b.activities.size());
- for (int i = 0; i < a.activities.size(); ++i) {
- assertActivitiesEqual(a.activities.get(i), b.activities.get(i));
+ assertEquals(ArrayUtils.size(a.getActivities()), ArrayUtils.size(b.getActivities()));
+ for (int i = 0; i < ArrayUtils.size(a.getActivities()); ++i) {
+ assertActivitiesEqual(a, a.getActivities().get(i), b, b.getActivities().get(i));
}
- assertEquals(a.receivers.size(), b.receivers.size());
- for (int i = 0; i < a.receivers.size(); ++i) {
- assertActivitiesEqual(a.receivers.get(i), b.receivers.get(i));
+ assertEquals(ArrayUtils.size(a.getReceivers()), ArrayUtils.size(b.getReceivers()));
+ for (int i = 0; i < ArrayUtils.size(a.getReceivers()); ++i) {
+ assertActivitiesEqual(a, a.getReceivers().get(i), b, b.getReceivers().get(i));
}
- assertEquals(a.providers.size(), b.providers.size());
- for (int i = 0; i < a.providers.size(); ++i) {
- assertProvidersEqual(a.providers.get(i), b.providers.get(i));
+ assertEquals(ArrayUtils.size(a.getProviders()), ArrayUtils.size(b.getProviders()));
+ for (int i = 0; i < ArrayUtils.size(a.getProviders()); ++i) {
+ assertProvidersEqual(a, a.getProviders().get(i), b, b.getProviders().get(i));
}
- assertEquals(a.services.size(), b.services.size());
- for (int i = 0; i < a.services.size(); ++i) {
- assertServicesEqual(a.services.get(i), b.services.get(i));
+ assertEquals(ArrayUtils.size(a.getServices()), ArrayUtils.size(b.getServices()));
+ for (int i = 0; i < ArrayUtils.size(a.getServices()); ++i) {
+ assertServicesEqual(a, a.getServices().get(i), b, b.getServices().get(i));
}
- assertEquals(a.instrumentation.size(), b.instrumentation.size());
- for (int i = 0; i < a.instrumentation.size(); ++i) {
- assertInstrumentationEqual(a.instrumentation.get(i), b.instrumentation.get(i));
+ assertEquals(ArrayUtils.size(a.getInstrumentations()),
+ ArrayUtils.size(b.getInstrumentations()));
+ for (int i = 0; i < ArrayUtils.size(a.getInstrumentations()); ++i) {
+ assertInstrumentationEqual(a.getInstrumentations().get(i),
+ b.getInstrumentations().get(i));
}
- assertEquals(a.requestedPermissions, b.requestedPermissions);
- assertEquals(a.protectedBroadcasts, b.protectedBroadcasts);
- assertEquals(a.parentPackage, b.parentPackage);
- assertEquals(a.childPackages, b.childPackages);
- assertEquals(a.libraryNames, b.libraryNames);
- assertEquals(a.usesLibraries, b.usesLibraries);
- assertEquals(a.usesOptionalLibraries, b.usesOptionalLibraries);
- assertTrue(Arrays.equals(a.usesLibraryFiles, b.usesLibraryFiles));
- assertEquals(a.mOriginalPackages, b.mOriginalPackages);
- assertEquals(a.mRealPackage, b.mRealPackage);
- assertEquals(a.mAdoptPermissions, b.mAdoptPermissions);
- assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData);
- assertEquals(a.mVersionName, b.mVersionName);
- assertEquals(a.mSharedUserId, b.mSharedUserId);
- assertTrue(Arrays.equals(a.mSigningDetails.signatures, b.mSigningDetails.signatures));
- assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills));
- assertEquals(a.mExtras, b.mExtras);
- assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType);
- assertEquals(a.mRequiredAccountType, b.mRequiredAccountType);
- assertEquals(a.mOverlayTarget, b.mOverlayTarget);
- assertEquals(a.mOverlayTargetName, b.mOverlayTargetName);
- assertEquals(a.mOverlayCategory, b.mOverlayCategory);
- assertEquals(a.mOverlayPriority, b.mOverlayPriority);
- assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic);
- assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys);
- assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets);
- assertEquals(a.mKeySetMapping, b.mKeySetMapping);
- assertEquals(a.cpuAbiOverride, b.cpuAbiOverride);
- assertTrue(Arrays.equals(a.restrictUpdateHash, b.restrictUpdateHash));
+ assertEquals(a.getRequestedPermissions(), b.getRequestedPermissions());
+ assertEquals(a.getProtectedBroadcasts(), b.getProtectedBroadcasts());
+ assertEquals(a.getLibraryNames(), b.getLibraryNames());
+ assertEquals(a.getUsesLibraries(), b.getUsesLibraries());
+ assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries());
+ assertArrayEquals(a.getUsesLibraryFiles(), b.getUsesLibraryFiles());
+ assertEquals(a.getOriginalPackages(), b.getOriginalPackages());
+ assertEquals(a.getRealPackage(), b.getRealPackage());
+ assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions());
+ assertBundleApproximateEquals(a.getAppMetaData(), b.getAppMetaData());
+ assertEquals(a.getVersionName(), b.getVersionName());
+ assertEquals(a.getSharedUserId(), b.getSharedUserId());
+ assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures);
+ assertArrayEquals(a.getLastPackageUsageTimeInMills(), b.getLastPackageUsageTimeInMills());
+ assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType());
+ assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType());
+ assertEquals(a.getOverlayTarget(), b.getOverlayTarget());
+ assertEquals(a.getOverlayTargetName(), b.getOverlayTargetName());
+ assertEquals(a.getOverlayCategory(), b.getOverlayCategory());
+ assertEquals(a.getOverlayPriority(), b.getOverlayPriority());
+ assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic());
+ assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys);
+ assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets());
+ assertEquals(a.getKeySetMapping(), b.getKeySetMapping());
+ assertEquals(a.getCpuAbiOverride(), b.getCpuAbiOverride());
+ assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash());
}
private static void assertBundleApproximateEquals(Bundle a, Bundle b) {
@@ -305,10 +333,10 @@ public class PackageParserTest {
assertEquals(a.toString(), b.toString());
}
- private static void assertComponentsEqual(PackageParser.Component<?> a,
- PackageParser.Component<?> b) {
+ private static void assertComponentsEqual(ParsedComponent<?> a,
+ ParsedComponent<?> b) {
assertEquals(a.className, b.className);
- assertBundleApproximateEquals(a.metaData, b.metaData);
+ assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
assertEquals(a.getComponentName(), b.getComponentName());
if (a.intents != null && b.intents != null) {
@@ -318,80 +346,102 @@ public class PackageParserTest {
}
for (int i = 0; i < a.intents.size(); ++i) {
- PackageParser.IntentInfo aIntent = a.intents.get(i);
- PackageParser.IntentInfo bIntent = b.intents.get(i);
+ ParsedIntentInfo aIntent = a.intents.get(i);
+ ParsedIntentInfo bIntent = b.intents.get(i);
assertEquals(aIntent.hasDefault, bIntent.hasDefault);
assertEquals(aIntent.labelRes, bIntent.labelRes);
assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel);
assertEquals(aIntent.icon, bIntent.icon);
- assertEquals(aIntent.logo, bIntent.logo);
- assertEquals(aIntent.banner, bIntent.banner);
- assertEquals(aIntent.preferred, bIntent.preferred);
}
}
- private static void assertPermissionsEqual(PackageParser.Permission a,
- PackageParser.Permission b) {
+ private static void assertPermissionsEqual(ParsedPermission a,
+ ParsedPermission b) {
assertComponentsEqual(a, b);
assertEquals(a.tree, b.tree);
// Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform
// a full structural equality here because the code that serializes them isn't parser
// specific and is tested elsewhere.
- assertEquals(a.info.protectionLevel, b.info.protectionLevel);
- assertEquals(a.info.group, b.info.group);
- assertEquals(a.info.flags, b.info.flags);
+ assertEquals(a.getProtection(), b.getProtection());
+ assertEquals(a.getGroup(), b.getGroup());
+ assertEquals(a.flags, b.flags);
- if (a.group != null && b.group != null) {
- assertPermissionGroupsEqual(a.group, b.group);
- } else if (a.group != null || b.group != null) {
+ if (a.parsedPermissionGroup != null && b.parsedPermissionGroup != null) {
+ assertPermissionGroupsEqual(a.parsedPermissionGroup, b.parsedPermissionGroup);
+ } else if (a.parsedPermissionGroup != null || b.parsedPermissionGroup != null) {
throw new AssertionError();
}
}
- private static void assertInstrumentationEqual(PackageParser.Instrumentation a,
- PackageParser.Instrumentation b) {
+ private static void assertInstrumentationEqual(ParsedInstrumentation a,
+ ParsedInstrumentation b) {
assertComponentsEqual(a, b);
// Sanity check for InstrumentationInfo.
- assertEquals(a.info.targetPackage, b.info.targetPackage);
- assertEquals(a.info.targetProcesses, b.info.targetProcesses);
- assertEquals(a.info.sourceDir, b.info.sourceDir);
- assertEquals(a.info.publicSourceDir, b.info.publicSourceDir);
+ assertEquals(a.getTargetPackage(), b.getTargetPackage());
+ assertEquals(a.getTargetProcesses(), b.getTargetProcesses());
}
- private static void assertServicesEqual(PackageParser.Service a, PackageParser.Service b) {
+ private static void assertServicesEqual(
+ AndroidPackage aPkg,
+ ParsedService a,
+ AndroidPackage bPkg,
+ ParsedService b
+ ) {
assertComponentsEqual(a, b);
// Sanity check for ServiceInfo.
- assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
- assertEquals(a.info.name, b.info.name);
+ ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, new PackageUserState(),
+ 0);
+ ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, new PackageUserState(),
+ 0);
+ assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+ assertEquals(a.getName(), b.getName());
}
- private static void assertProvidersEqual(PackageParser.Provider a, PackageParser.Provider b) {
+ private static void assertProvidersEqual(
+ AndroidPackage aPkg,
+ ParsedProvider a,
+ AndroidPackage bPkg,
+ ParsedProvider b
+ ) {
assertComponentsEqual(a, b);
// Sanity check for ProviderInfo
- assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
- assertEquals(a.info.name, b.info.name);
+ ProviderInfo aInfo = PackageInfoUtils.generateProviderInfo(aPkg, a, 0,
+ new PackageUserState(), 0);
+ ProviderInfo bInfo = PackageInfoUtils.generateProviderInfo(bPkg, b, 0,
+ new PackageUserState(), 0);
+ assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+ assertEquals(a.getName(), b.getName());
}
- private static void assertActivitiesEqual(PackageParser.Activity a, PackageParser.Activity b) {
+ private static void assertActivitiesEqual(
+ AndroidPackage aPkg,
+ ParsedActivity a,
+ AndroidPackage bPkg,
+ ParsedActivity b
+ ) {
assertComponentsEqual(a, b);
// Sanity check for ActivityInfo.
- assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
- assertEquals(a.info.name, b.info.name);
+ ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0,
+ new PackageUserState(), 0);
+ ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0,
+ new PackageUserState(), 0);
+ assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+ assertEquals(a.getName(), b.getName());
}
- private static void assertPermissionGroupsEqual(PackageParser.PermissionGroup a,
- PackageParser.PermissionGroup b) {
+ private static void assertPermissionGroupsEqual(ParsedPermissionGroup a,
+ ParsedPermissionGroup b) {
assertComponentsEqual(a, b);
// Sanity check for PermissionGroupInfo.
- assertEquals(a.info.name, b.info.name);
- assertEquals(a.info.descriptionRes, b.info.descriptionRes);
+ assertEquals(a.getName(), b.getName());
+ assertEquals(a.descriptionRes, b.descriptionRes);
}
private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) {
@@ -424,11 +474,11 @@ public class PackageParserTest {
assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir);
assertEquals(a.sourceDir, that.sourceDir);
assertEquals(a.publicSourceDir, that.publicSourceDir);
- assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs));
- assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs));
- assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs));
+ assertArrayEquals(a.splitSourceDirs, that.splitSourceDirs);
+ assertArrayEquals(a.splitPublicSourceDirs, that.splitPublicSourceDirs);
+ assertArrayEquals(a.resourceDirs, that.resourceDirs);
assertEquals(a.seInfo, that.seInfo);
- assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles));
+ assertArrayEquals(a.sharedLibraryFiles, that.sharedLibraryFiles);
assertEquals(a.dataDir, that.dataDir);
assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir);
@@ -439,132 +489,93 @@ public class PackageParserTest {
assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi);
}
- public static void setKnownFields(PackageParser.Package pkg) {
- pkg.baseRevisionCode = 100;
- pkg.baseHardwareAccelerated = true;
- pkg.mVersionCode = 100;
- pkg.mSharedUserLabel = 100;
- pkg.mPreferredOrder = 100;
- pkg.installLocation = 100;
- pkg.coreApp = true;
- pkg.mRequiredForAllUsers = true;
- pkg.use32bitAbi = true;
- pkg.packageName = "foo";
- pkg.splitNames = new String[] { "foo2" };
- pkg.volumeUuid = "foo3";
- pkg.codePath = "foo4";
- pkg.baseCodePath = "foo5";
- pkg.splitCodePaths = new String[] { "foo6" };
- pkg.splitRevisionCodes = new int[] { 100 };
- pkg.splitFlags = new int[] { 100 };
- pkg.splitPrivateFlags = new int[] { 100 };
- pkg.applicationInfo = new ApplicationInfo();
-
- pkg.permissions.add(new PackageParser.Permission(pkg, (String) null));
- pkg.permissionGroups.add(new PackageParser.PermissionGroup(pkg, ID_NULL, ID_NULL, ID_NULL));
-
- final PackageParser.ParseComponentArgs dummy = new PackageParser.ParseComponentArgs(
- pkg, new String[1], 0, 0, 0, 0, 0, 0, null, 0, 0, 0);
-
- pkg.activities.add(new PackageParser.Activity(dummy, new ActivityInfo()));
- pkg.receivers.add(new PackageParser.Activity(dummy, new ActivityInfo()));
- pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo()));
- pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
- pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
- pkg.requestedPermissions.add("foo7");
- pkg.implicitPermissions.add("foo25");
-
- pkg.protectedBroadcasts = new ArrayList<>();
- pkg.protectedBroadcasts.add("foo8");
-
- pkg.parentPackage = new PackageParser.Package("foo9");
-
- pkg.childPackages = new ArrayList<>();
- pkg.childPackages.add(new PackageParser.Package("bar"));
-
- pkg.staticSharedLibName = "foo23";
- pkg.staticSharedLibVersion = 100;
- pkg.usesStaticLibraries = new ArrayList<>();
- pkg.usesStaticLibraries.add("foo23");
- pkg.usesStaticLibrariesCertDigests = new String[1][];
- pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" };
- pkg.usesStaticLibrariesVersions = new long[] { 100 };
-
- pkg.libraryNames = new ArrayList<>();
- pkg.libraryNames.add("foo10");
-
- pkg.usesLibraries = new ArrayList<>();
- pkg.usesLibraries.add("foo11");
-
- pkg.usesOptionalLibraries = new ArrayList<>();
- pkg.usesOptionalLibraries.add("foo12");
-
- pkg.usesLibraryFiles = new String[] { "foo13"};
-
- pkg.usesLibraryInfos = new ArrayList<>();
- pkg.usesLibraryInfos.add(
- new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null));
-
- pkg.mOriginalPackages = new ArrayList<>();
- pkg.mOriginalPackages.add("foo14");
-
- pkg.mRealPackage = "foo15";
-
- pkg.mAdoptPermissions = new ArrayList<>();
- pkg.mAdoptPermissions.add("foo16");
-
- pkg.mAppMetaData = new Bundle();
- pkg.mVersionName = "foo17";
- pkg.mSharedUserId = "foo18";
- pkg.mSigningDetails =
- new PackageParser.SigningDetails(
- new Signature[] { new Signature(new byte[16]) },
- 2,
- new ArraySet<>(),
- null);
- pkg.mExtras = new Bundle();
- pkg.mRestrictedAccountType = "foo19";
- pkg.mRequiredAccountType = "foo20";
- pkg.mOverlayTarget = "foo21";
- pkg.mOverlayPriority = 100;
- pkg.mUpgradeKeySets = new ArraySet<>();
- pkg.mKeySetMapping = new ArrayMap<>();
- pkg.cpuAbiOverride = "foo22";
- pkg.restrictUpdateHash = new byte[16];
-
- pkg.preferredActivityFilters = new ArrayList<>();
- pkg.preferredActivityFilters.add(new PackageParser.ActivityIntentInfo(
- new PackageParser.Activity(dummy, new ActivityInfo())));
-
- pkg.configPreferences = new ArrayList<>();
- pkg.configPreferences.add(new ConfigurationInfo());
-
- pkg.reqFeatures = new ArrayList<>();
- pkg.reqFeatures.add(new FeatureInfo());
-
- pkg.featureGroups = new ArrayList<>();
- pkg.featureGroups.add(new FeatureGroupInfo());
-
- pkg.mCompileSdkVersionCodename = "foo23";
- pkg.mCompileSdkVersion = 100;
- pkg.mVersionCodeMajor = 100;
-
- pkg.mOverlayCategory = "foo24";
- pkg.mOverlayIsStatic = true;
- pkg.mOverlayTargetName = "foo26";
-
- pkg.baseHardwareAccelerated = true;
- pkg.coreApp = true;
- pkg.mRequiredForAllUsers = true;
- pkg.visibleToInstantApps = true;
- pkg.use32bitAbi = true;
- pkg.mForceQueryable = true;
- pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27"));
- pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28")));
+ public static void setKnownFields(ParsingPackage pkg) {
+ Bundle bundle = new Bundle();
+ bundle.putString("key", "value");
+
+ ParsedPermission permission = new ParsedPermission();
+ permission.parsedPermissionGroup = new ParsedPermissionGroup();
+
+ pkg.setBaseRevisionCode(100)
+ .setBaseHardwareAccelerated(true)
+ .setSharedUserLabel(100)
+ .setPreferredOrder(100)
+ .setInstallLocation(100)
+ .setRequiredForAllUsers(true)
+ .asSplit(
+ new String[]{"foo2"},
+ new String[]{"foo6"},
+ new int[]{100},
+ null
+ )
+ .setUse32BitAbi(true)
+ .setVolumeUuid("foo3")
+ .setCodePath("foo4")
+ .addPermission(permission)
+ .addPermissionGroup(new ParsedPermissionGroup())
+ .addActivity(new ParsedActivity())
+ .addReceiver(new ParsedActivity())
+ .addProvider(new ParsedProvider())
+ .addService(new ParsedService())
+ .addInstrumentation(new ParsedInstrumentation())
+ .addRequestedPermission("foo7")
+ .addImplicitPermission("foo25")
+ .addProtectedBroadcast("foo8")
+ .setStaticSharedLibName("foo23")
+ .setStaticSharedLibVersion(100)
+ .addUsesStaticLibrary("foo23")
+ .addUsesStaticLibraryCertDigests(new String[]{"digest"})
+ .addUsesStaticLibraryVersion(100)
+ .addLibraryName("foo10")
+ .addUsesLibrary("foo11")
+ .addUsesOptionalLibrary("foo12")
+ .addOriginalPackage("foo14")
+ .setRealPackage("foo15")
+ .addAdoptPermission("foo16")
+ .setAppMetaData(bundle)
+ .setVersionName("foo17")
+ .setSharedUserId("foo18")
+ .setSigningDetails(
+ new PackageParser.SigningDetails(
+ new Signature[]{new Signature(new byte[16])},
+ 2,
+ new ArraySet<>(),
+ null)
+ )
+ .setRestrictedAccountType("foo19")
+ .setRequiredAccountType("foo20")
+ .setOverlayTarget("foo21")
+ .setOverlayPriority(100)
+ .setUpgradeKeySets(new ArraySet<>())
+ .addPreferredActivityFilter(
+ new ComponentParseUtils.ParsedActivityIntentInfo("foo", "className"))
+ .addConfigPreference(new ConfigurationInfo())
+ .addReqFeature(new FeatureInfo())
+ .addFeatureGroup(new FeatureGroupInfo())
+ .setCompileSdkVersionCodename("foo23")
+ .setCompileSdkVersion(100)
+ .setOverlayCategory("foo24")
+ .setOverlayIsStatic(true)
+ .setOverlayTargetName("foo26")
+ .setVisibleToInstantApps(true)
+ .setSplitHasCode(0, true)
+ .hideAsParsed()
+ .setBaseCodePath("foo5")
+ .setVersionCode(100)
+ .setCpuAbiOverride("foo22")
+ .setRestrictUpdateHash(new byte[16])
+ .setVersionCodeMajor(100)
+ .setCoreApp(true)
+ .hideAsFinal()
+ .mutate()
+ .setUsesLibraryInfos(Arrays.asList(
+ new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null)
+ ))
+ .setUsesLibraryFiles(new String[]{"foo13"});
}
- private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
- Field[] fields = PackageParser.Package.class.getDeclaredFields();
+ private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception {
+ Field[] fields = ParsedPackage.class.getDeclaredFields();
Set<String> nonSerializedFields = new HashSet<>();
nonSerializedFields.add("mExtras");
@@ -601,7 +612,7 @@ public class PackageParserTest {
} else if (fieldType == boolean.class) {
// boolean fields: Check that they're set to true.
boolean value = (boolean) f.get(pkg);
- assertEquals("Bad value for field: " + f, true, value);
+ assertTrue("Bad value for field: " + f, value);
} else {
// All other fields: Check that they're set.
Object o = f.get(pkg);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 8d476f6e9318..5baeedefef05 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -16,12 +16,11 @@
package com.android.server.pm;
-import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
+import android.content.pm.parsing.AndroidPackage;
import android.util.SparseArray;
import java.io.File;
-import java.util.List;
class PackageSettingBuilder {
private String mName;
@@ -35,17 +34,15 @@ class PackageSettingBuilder {
private long mPVersionCode;
private int mPkgFlags;
private int mPrivateFlags;
- private String mParentPackageName;
- private List<String> mChildPackageNames;
private int mSharedUserId;
private String[] mUsesStaticLibraries;
private long[] mUsesStaticLibrariesVersions;
private String mVolumeUuid;
private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
- private PackageParser.Package mPkg;
+ private AndroidPackage mPkg;
private int mAppId;
- public PackageSettingBuilder setPackage(PackageParser.Package pkg) {
+ public PackageSettingBuilder setPackage(AndroidPackage pkg) {
this.mPkg = pkg;
return this;
}
@@ -111,16 +108,6 @@ class PackageSettingBuilder {
return this;
}
- public PackageSettingBuilder setParentPackageName(String parentPackageName) {
- this.mParentPackageName = parentPackageName;
- return this;
- }
-
- public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
- this.mChildPackageNames = childPackageNames;
- return this;
- }
-
public PackageSettingBuilder setSharedUserId(int sharedUserId) {
this.mSharedUserId = sharedUserId;
return this;
@@ -154,9 +141,8 @@ class PackageSettingBuilder {
final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
new File(mCodePath), new File(mResourcePath),
mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
- mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
- mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
- mUsesStaticLibrariesVersions);
+ mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId,
+ mUsesStaticLibraries, mUsesStaticLibrariesVersions);
packageSetting.pkg = mPkg;
packageSetting.appId = mAppId;
packageSetting.volumeUuid = this.mVolumeUuid;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index d3a77d3e80f1..04e769d7dcfb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -16,8 +16,8 @@
package com.android.server.pm;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -467,8 +467,7 @@ public class PackageSignaturesTest {
File appPath = new File("/data/app/app");
PackageSetting result = new PackageSetting("test.app", null, appPath, appPath,
"/data/app/app", null, null, null,
- 1, 940097092, 0, null,
- null, 0 /*userId*/, null, null);
+ 1, 940097092, 0, 0 /*userId*/, null, null);
return result;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index 41489dc42a6a..a0efc8a03719 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsedPackage;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
@@ -74,7 +75,7 @@ public class ParallelPackageParserTest {
}
@Override
- protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+ protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
// Do not actually parse the package for testing
return null;
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 4b7dd36a382a..30108c67d920 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -18,14 +18,17 @@ package com.android.server.pm;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.os.Build;
import android.platform.test.annotations.Presubmit;
import com.android.server.compat.PlatformCompat;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -40,41 +43,45 @@ import org.mockito.junit.MockitoJUnitRunner;
public class SELinuxMMACTest {
private static final String PACKAGE_NAME = "my.package";
- private static final int OPT_IN_VERSION = android.os.Build.VERSION_CODES.R;
+ private static final int OPT_IN_VERSION = Build.VERSION_CODES.R;
@Mock
PlatformCompat mMockCompatibility;
- PackageParser.Package mPkg;
-
- @Before
- public void setUp() {
- mPkg = new PackageParser.Package(PACKAGE_NAME);
- mPkg.applicationInfo.targetSdkVersion = 28;
- }
-
@Test
public void getSeInfoOptInToLatest() {
- when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES,
- mPkg.applicationInfo)).thenReturn(true);
- assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility),
+ AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
+ when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+ argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+ .thenReturn(true);
+ assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
is("default:targetSdkVersion=" + OPT_IN_VERSION));
}
@Test
public void getSeInfoNoOptIn() {
- when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES,
- mPkg.applicationInfo)).thenReturn(false);
- assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility),
+ AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
+ when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+ argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+ .thenReturn(false);
+ assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
is("default:targetSdkVersion=28"));
}
@Test
public void getSeInfoNoOptInButAlreadyR() {
- mPkg.applicationInfo.targetSdkVersion = OPT_IN_VERSION;
- when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES,
- mPkg.applicationInfo)).thenReturn(false);
- assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility),
+ AndroidPackage pkg = makePackage(OPT_IN_VERSION);
+ when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+ argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+ .thenReturn(false);
+ assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
is("default:targetSdkVersion=" + OPT_IN_VERSION));
}
+
+ private AndroidPackage makePackage(int targetSdkVersion) {
+ return PackageImpl.forParsing(PACKAGE_NAME)
+ .setTargetSdkVersion(targetSdkVersion)
+ .hideAsParsed()
+ .hideAsFinal();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 34a3f860496a..11f154be688b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -16,12 +16,13 @@
package com.android.server.pm;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
import android.os.UserHandle;
class ScanRequestBuilder {
- private final PackageParser.Package mPkg;
- private PackageParser.Package mOldPkg;
+ private final ParsedPackage mPkg;
+ private AndroidPackage mOldPkg;
private SharedUserSetting mSharedUserSetting;
private PackageSetting mPkgSetting;
private PackageSetting mDisabledPkgSetting;
@@ -32,11 +33,11 @@ class ScanRequestBuilder {
private UserHandle mUser;
private boolean mIsPlatformPackage;
- ScanRequestBuilder(PackageParser.Package pkg) {
+ ScanRequestBuilder(ParsedPackage pkg) {
this.mPkg = pkg;
}
- public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+ public ScanRequestBuilder setOldPkg(AndroidPackage oldPkg) {
this.mOldPkg = oldPkg;
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 74ef034082a0..583cf5827367 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -35,13 +35,18 @@ import static org.junit.Assert.assertNotSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.Manifest;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageParser;
import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.res.TypedArray;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManagerInternal;
@@ -60,6 +65,7 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
+import java.util.UUID;
@RunWith(MockitoJUnitRunner.class)
@Presubmit
@@ -68,6 +74,9 @@ public class ScanTests {
private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
+ private static final UUID UUID_ONE = UUID.randomUUID();
+ private static final UUID UUID_TWO = UUID.randomUUID();
+
@Mock
PackageAbiHelper mMockPackageAbiHelper;
@Mock
@@ -92,25 +101,25 @@ public class ScanTests {
@Before
public void setupDefaultAbiBehavior() throws Exception {
when(mMockPackageAbiHelper.derivePackageAbi(
- any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
+ any(ParsedPackage.class), nullable(String.class), anyBoolean()))
.thenReturn(new Pair<>(
new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
new PackageAbiHelper.NativeLibraryPaths(
"derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
when(mMockPackageAbiHelper.getNativeLibraryPaths(
- any(PackageParser.Package.class), any(File.class)))
+ any(ParsedPackage.class), any(File.class)))
.thenReturn(new PackageAbiHelper.NativeLibraryPaths(
"getRootDir", true, "getNativeDir", "getNativeDir2"
));
when(mMockPackageAbiHelper.getBundledAppAbis(
- any(PackageParser.Package.class)))
+ any(ParsedPackage.class)))
.thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
}
@Test
public void newInstallSimpleAllNominal() throws Exception {
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.build();
@@ -128,7 +137,7 @@ public class ScanTests {
when(mMockUserManager.getUserIds()).thenReturn(userIds);
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setRealPkgName(null)
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
@@ -143,7 +152,7 @@ public class ScanTests {
@Test
public void installRealPackageName() throws Exception {
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setRealPkgName("com.package.real")
.build();
@@ -154,7 +163,7 @@ public class ScanTests {
final PackageManagerService.ScanRequest scanRequestNoRealPkg =
createBasicScanRequestBuilder(
createBasicPackage(DUMMY_PACKAGE_NAME)
- .setRealPackageName("com.package.real").build())
+ .setRealPackage("com.package.real"))
.build();
final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
@@ -170,7 +179,7 @@ public class ScanTests {
.setSecondaryCpuAbiString("secondaryCpuAbi")
.build();
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.setPkgSetting(pkgSetting)
.build();
@@ -202,7 +211,7 @@ public class ScanTests {
.build();
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.build();
@@ -214,17 +223,18 @@ public class ScanTests {
@Test
public void installStaticSharedLibrary() throws Exception {
- final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
- .setStaticSharedLib("static.lib", 123L)
- .setManifestPackageName("static.lib.pkg")
+ final ParsedPackage pkg = createBasicPackage("static.lib.pkg")
+ .setStaticSharedLibName("static.lib")
+ .setStaticSharedLibVersion(123L)
+ .hideAsParsed()
+ .setPackageName("static.lib.pkg.123")
.setVersionCodeMajor(1)
.setVersionCode(234)
.setBaseCodePath("/some/path.apk")
- .addSplitCodePath("/some/other/path.apk")
- .build();
+ .setSplitCodePaths(new String[] {"/some/other/path.apk"});
- final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
- pkg).setUser(UserHandle.of(0)).build();
+ final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg)
+ .setUser(UserHandle.of(0)).build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
@@ -245,15 +255,14 @@ public class ScanTests {
@Test
public void installDynamicLibraries() throws Exception {
- final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
- .setManifestPackageName("dynamic.lib.pkg")
+ final ParsedPackage pkg = createBasicPackage("dynamic.lib.pkg")
.addLibraryName("liba")
.addLibraryName("libb")
+ .hideAsParsed()
.setVersionCodeMajor(1)
.setVersionCode(234)
.setBaseCodePath("/some/path.apk")
- .addSplitCodePath("/some/other/path.apk")
- .build();
+ .setSplitCodePaths(new String[] {"/some/other/path.apk"});
final PackageManagerService.ScanRequest scanRequest =
new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
@@ -295,15 +304,15 @@ public class ScanTests {
.setVolumeUuid("someUuid")
.build();
- final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
- .setApplicationInfoVolumeUuid("someNewUuid")
- .build();
+ final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .hideAsParsed()
+ .setApplicationVolumeUuid(UUID_TWO.toString());
final PackageManagerService.ScanResult scanResult = executeScan(
new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
- assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+ assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString()));
}
@Test
@@ -311,10 +320,10 @@ public class ScanTests {
final PackageSetting pkgSetting =
createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
- final PackageParser.Package basicPackage =
+ final ParsedPackage basicPackage =
createBasicPackage(DUMMY_PACKAGE_NAME)
- .setCpuAbiOVerride("testOverride")
- .build();
+ .hideAsParsed()
+ .setCpuAbiOverride("testOverride");
final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
@@ -331,9 +340,9 @@ public class ScanTests {
final PackageSetting originalPkgSetting =
createBasicPackageSettingBuilder("original.package").build();
- final PackageParser.Package basicPackage =
+ final ParsedPackage basicPackage =
createBasicPackage(DUMMY_PACKAGE_NAME)
- .build();
+ .hideAsParsed();
final PackageManagerService.ScanResult result =
@@ -341,7 +350,7 @@ public class ScanTests {
.setOriginalPkgSetting(originalPkgSetting)
.build());
- assertThat(result.request.pkg.packageName, is("original.package"));
+ assertThat(result.request.parsedPackage.getPackageName(), is("original.package"));
}
@Test
@@ -354,7 +363,7 @@ public class ScanTests {
.build();
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_AS_FULL_APP)
.build();
@@ -375,7 +384,7 @@ public class ScanTests {
.build();
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_AS_INSTANT_APP)
.build();
@@ -394,7 +403,7 @@ public class ScanTests {
.build();
final PackageManagerService.ScanRequest scanRequest =
- createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.setDisabledPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_NEW_INSTALL)
@@ -402,15 +411,14 @@ public class ScanTests {
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
- assertThat(scanResult.request.pkg.applicationInfo.flags,
+ assertThat(scanResult.request.parsedPackage.getFlags(),
hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
}
@Test
public void factoryTestFlagSet() throws Exception {
- final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
- .addPermissionRequest(Manifest.permission.FACTORY_TEST)
- .build();
+ final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .addRequestedPermission(Manifest.permission.FACTORY_TEST);
final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
createBasicScanRequestBuilder(basicPackage).build(),
@@ -418,15 +426,15 @@ public class ScanTests {
true /*isUnderFactoryTest*/,
System.currentTimeMillis());
- assertThat(scanResult.request.pkg.applicationInfo.flags,
+ assertThat(scanResult.request.parsedPackage.getFlags(),
hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
}
@Test
public void scanSystemApp_isOrphanedTrue() throws Exception {
- final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
- .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
- .build();
+ final ParsedPackage pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .hideAsParsed()
+ .setSystem(true);
final PackageManagerService.ScanRequest scanRequest =
createBasicScanRequestBuilder(pkg)
@@ -481,22 +489,29 @@ public class ScanTests {
.setResourcePath(createResourcePath(packageName));
}
- private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
- return new ScanRequestBuilder(pkg)
+ private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) {
+ return new ScanRequestBuilder(pkg.hideAsParsed())
.setUser(UserHandle.of(0));
}
+ private static ScanRequestBuilder createBasicScanRequestBuilder(ParsedPackage pkg) {
+ return new ScanRequestBuilder(pkg)
+ .setUser(UserHandle.of(0));
+ }
- private static PackageBuilder createBasicPackage(String packageName) {
- return new PackageBuilder(packageName)
+ private static ParsingPackage createBasicPackage(String packageName) {
+ // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
+ return new PackageImpl(packageName, null, mock(TypedArray.class), false)
.setCodePath("/data/tmp/randompath")
.setApplicationInfoCodePath(createCodePath(packageName))
.setApplicationInfoResourcePath(createResourcePath(packageName))
- .setApplicationInfoVolumeUuid("volumeUuid")
+ .setApplicationVolumeUuid(UUID_ONE.toString())
.setBaseCodePath("/data/tmp/randompath/base.apk")
- .addUsesStaticLibrary("some.static.library", 234L)
- .addUsesStaticLibrary("some.other.static.library", 456L)
- .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+ .addUsesStaticLibrary("some.static.library")
+ .addUsesStaticLibraryVersion(234L)
+ .addUsesStaticLibrary("some.other.static.library")
+ .addUsesStaticLibraryVersion(456L)
+ .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
.setVersionCodeMajor(1)
.setVersionCode(2345);
}
@@ -508,20 +523,19 @@ public class ScanTests {
final PackageSetting pkgSetting = scanResult.pkgSetting;
assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
- final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+ final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
+ pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
assertBasicApplicationInfo(scanResult, applicationInfo);
-
}
private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
String packageName, boolean isInstant, PackageSetting pkgSetting) {
- assertThat(pkgSetting.pkg.packageName, is(packageName));
+ assertThat(pkgSetting.pkg.getPackageName(), is(packageName));
assertThat(pkgSetting.getInstantApp(0), is(isInstant));
assertThat(pkgSetting.usesStaticLibraries,
arrayContaining("some.static.library", "some.other.static.library"));
assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
- assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
- assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
+ assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
@@ -529,34 +543,39 @@ public class ScanTests {
private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
ApplicationInfo applicationInfo) {
- assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+ assertThat(applicationInfo.processName,
+ is(scanResult.request.parsedPackage.getPackageName()));
final int uid = applicationInfo.uid;
assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
- scanResult.request.pkg.packageName).getAbsolutePath();
+ scanResult.request.parsedPackage.getPackageName()).getAbsolutePath();
assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
}
private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
- final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+ PackageSetting pkgSetting = scanResult.pkgSetting;
+ final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
+ pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
- assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
+ assertThat(pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
}
private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
- final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+ PackageSetting pkgSetting = scanResult.pkgSetting;
+ final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
+ pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
- assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
+ assertThat(pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
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 790f2b47cdd5..683278b699c0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -37,8 +37,9 @@ import static org.junit.Assert.fail;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
import android.os.Looper;
import android.os.SystemProperties;
import android.os.UserManager;
@@ -250,10 +251,14 @@ public class UserSystemPackageInstallerTest {
final Set<String> userWhitelist = new ArraySet<>();
userWhitelist.add(packageName1);
- final PackageParser.Package pkg1 = new PackageParser.Package(packageName1);
- final PackageParser.Package pkg2 = new PackageParser.Package(packageName2);
- final PackageParser.Package pkg3 = new PackageParser.Package(packageName3);
- final PackageParser.Package pkg4 = new PackageParser.Package(packageName4);
+ final AndroidPackage pkg1 = PackageImpl.forParsing(packageName1)
+ .hideAsParsed().hideAsFinal();
+ final AndroidPackage pkg2 = PackageImpl.forParsing(packageName2)
+ .hideAsParsed().hideAsFinal();
+ final AndroidPackage pkg3 = PackageImpl.forParsing(packageName3)
+ .hideAsParsed().hideAsFinal();
+ final AndroidPackage pkg4 = PackageImpl.forParsing(packageName4)
+ .hideAsParsed().hideAsFinal();
// No implicit whitelist, so only install pkg1.
boolean implicit = false;
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 3a55c2290157..66a4946ecc20 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
@@ -22,8 +22,11 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.content.pm.ApplicationInfo;
import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
@@ -51,17 +54,18 @@ public class DexoptUtilsTest {
DelegateLastClassLoader.class.getName();
private static class TestData {
- ApplicationInfo info;
+ AndroidPackage pkg;
boolean[] pathsWithCode;
}
private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits,
- boolean addSplitDependencies) {
- ApplicationInfo ai = new ApplicationInfo();
+ boolean addSplitDependencies, boolean isolatedSplitLoading) {
String codeDir = "/data/app/mock.android.com";
- ai.setBaseCodePath(codeDir + "/base.dex");
- ai.classLoaderName = baseClassLoader;
- ai.privateFlags = ai.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
+ ParsingPackage parsingPackage = PackageImpl.forParsing("mock.android.com")
+ .setClassLoaderName(baseClassLoader);
+
+ parsingPackage.setIsolatedSplitLoading(isolatedSplitLoading);
+
boolean[] pathsWithCode;
if (!addSplits) {
pathsWithCode = new boolean[] {true};
@@ -70,7 +74,7 @@ public class DexoptUtilsTest {
Arrays.fill(pathsWithCode, true);
pathsWithCode[7] = false; // config split
- ai.setSplitCodePaths(new String[]{
+ String[] splitCodePaths = new String[]{
codeDir + "/base-1.dex",
codeDir + "/base-2.dex",
codeDir + "/base-3.dex",
@@ -78,32 +82,51 @@ public class DexoptUtilsTest {
codeDir + "/base-5.dex",
codeDir + "/base-6.dex",
codeDir + "/config-split-7.dex",
- codeDir + "/feature-no-deps.dex"});
-
- ai.splitClassLoaderNames = new String[]{
- DELEGATE_LAST_CLASS_LOADER_NAME,
- DELEGATE_LAST_CLASS_LOADER_NAME,
- PATH_CLASS_LOADER_NAME,
- DEX_CLASS_LOADER_NAME,
- PATH_CLASS_LOADER_NAME,
- null, // A null class loader name should default to PathClassLoader.
- null, // The config split gets a null class loader.
- null}; // The feature split with no dependency and no specified class loader.
+ codeDir + "/feature-no-deps.dex"
+ };
+
+ String[] splitNames = new String[splitCodePaths.length];
+ int[] splitRevisionCodes = new int[splitCodePaths.length];
+ SparseArray<int[]> splitDependencies = null;
+
if (addSplitDependencies) {
- ai.splitDependencies = new SparseArray<>(ai.splitClassLoaderNames.length + 1);
- ai.splitDependencies.put(0, new int[] {-1}); // base has no dependency
- ai.splitDependencies.put(1, new int[] {2}); // split 1 depends on 2
- ai.splitDependencies.put(2, new int[] {4}); // split 2 depends on 4
- ai.splitDependencies.put(3, new int[] {4}); // split 3 depends on 4
- ai.splitDependencies.put(4, new int[] {0}); // split 4 depends on base
- ai.splitDependencies.put(5, new int[] {0}); // split 5 depends on base
- ai.splitDependencies.put(6, new int[] {5}); // split 6 depends on 5
+ splitDependencies = new SparseArray<>(splitCodePaths.length);
+ splitDependencies.put(0, new int[] {-1}); // base has no dependency
+ splitDependencies.put(1, new int[] {2}); // split 1 depends on 2
+ splitDependencies.put(2, new int[] {4}); // split 2 depends on 4
+ splitDependencies.put(3, new int[] {4}); // split 3 depends on 4
+ splitDependencies.put(4, new int[] {0}); // split 4 depends on base
+ splitDependencies.put(5, new int[] {0}); // split 5 depends on base
+ splitDependencies.put(6, new int[] {5}); // split 6 depends on 5
// Do not add the config split to the dependency list.
// Do not add the feature split with no dependency to the dependency list.
}
+
+ parsingPackage
+ .asSplit(
+ splitNames,
+ splitCodePaths,
+ splitRevisionCodes,
+ splitDependencies
+ )
+ .setSplitClassLoaderName(0, DELEGATE_LAST_CLASS_LOADER_NAME)
+ .setSplitClassLoaderName(1, DELEGATE_LAST_CLASS_LOADER_NAME)
+ .setSplitClassLoaderName(2, PATH_CLASS_LOADER_NAME)
+ .setSplitClassLoaderName(3, DEX_CLASS_LOADER_NAME)
+ .setSplitClassLoaderName(4, PATH_CLASS_LOADER_NAME)
+ // A null class loader name should default to PathClassLoader
+ .setSplitClassLoaderName(5, null)
+ // The config split gets a null class loader
+ .setSplitClassLoaderName(6, null)
+ // The feature split with no dependency and no specified class loader.
+ .setSplitClassLoaderName(7, null);
}
+
+ ParsedPackage parsedPackage = parsingPackage.hideAsParsed()
+ .setBaseCodePath(codeDir + "/base.dex");
+
TestData data = new TestData();
- data.info = ai;
+ data.pkg = parsedPackage.hideAsFinal();
data.pathsWithCode = pathsWithCode;
return data;
}
@@ -118,11 +141,11 @@ public class DexoptUtilsTest {
@Test
public void testSplitChain() {
- TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
+ TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, true);
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -139,11 +162,11 @@ public class DexoptUtilsTest {
@Test
public void testSplitChainNoSplitDependencies() {
- TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
+ TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false, true);
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -167,11 +190,9 @@ public class DexoptUtilsTest {
@Test
public void testSplitChainNoIsolationNoSharedLibrary() {
- TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
- data.info.privateFlags = data.info.privateFlags
- & (~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING);
+ TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, false);
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, null, data.pathsWithCode);
+ data.pkg, null, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals("PCL[]", contexts[0]);
@@ -192,9 +213,9 @@ public class DexoptUtilsTest {
@Test
public void testSplitChainNoSharedLibraries() {
TestData data = createMockApplicationInfo(
- DELEGATE_LAST_CLASS_LOADER_NAME, true, true);
+ DELEGATE_LAST_CLASS_LOADER_NAME, true, true, true);
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, null, data.pathsWithCode);
+ data.pkg, null, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals("DLC[]", contexts[0]);
@@ -211,11 +232,11 @@ public class DexoptUtilsTest {
@Test
public void testSplitChainWithNullPrimaryClassLoader() {
// A null classLoaderName should mean PathClassLoader.
- TestData data = createMockApplicationInfo(null, true, true);
+ TestData data = createMockApplicationInfo(null, true, true, true);
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -233,11 +254,11 @@ public class DexoptUtilsTest {
@Test
public void tesNoSplits() {
- TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
+ TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true);
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(1, contexts.length);
assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -245,11 +266,11 @@ public class DexoptUtilsTest {
@Test
public void tesNoSplitsNullClassLoaderName() {
- TestData data = createMockApplicationInfo(null, false, false);
+ TestData data = createMockApplicationInfo(null, false, false, true);
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(1, contexts.length);
assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -258,11 +279,11 @@ public class DexoptUtilsTest {
@Test
public void tesNoSplitDelegateLast() {
TestData data = createMockApplicationInfo(
- DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
+ DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true);
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(1, contexts.length);
assertEquals("DLC[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -270,9 +291,9 @@ public class DexoptUtilsTest {
@Test
public void tesNoSplitsNoSharedLibraries() {
- TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
+ TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true);
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, null, data.pathsWithCode);
+ data.pkg, null, data.pathsWithCode);
assertEquals(1, contexts.length);
assertEquals("PCL[]", contexts[0]);
@@ -281,9 +302,9 @@ public class DexoptUtilsTest {
@Test
public void tesNoSplitDelegateLastNoSharedLibraries() {
TestData data = createMockApplicationInfo(
- DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
+ DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true);
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, null, data.pathsWithCode);
+ data.pkg, null, data.pathsWithCode);
assertEquals(1, contexts.length);
assertEquals("DLC[]", contexts[0]);
@@ -291,13 +312,13 @@ public class DexoptUtilsTest {
@Test
public void testContextWithNoCode() {
- TestData data = createMockApplicationInfo(null, true, false);
+ TestData data = createMockApplicationInfo(null, true, false, true);
Arrays.fill(data.pathsWithCode, false);
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals(null, contexts[0]);
@@ -312,12 +333,12 @@ public class DexoptUtilsTest {
@Test
public void testContextBaseNoCode() {
- TestData data = createMockApplicationInfo(null, true, true);
+ TestData data = createMockApplicationInfo(null, true, true, true);
data.pathsWithCode[0] = false;
List<SharedLibraryInfo> sharedLibrary =
createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
- data.info, sharedLibrary, data.pathsWithCode);
+ data.pkg, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals(null, contexts[0]);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
new file mode 100644
index 000000000000..27d02e194540
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.parsing
+
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageParser
+import android.content.pm.parsing.AndroidPackage
+import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
+import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Verifies that missing/adding [PackageManager] flags adds/remove the appropriate fields from the
+ * [PackageInfo] or [ApplicationInfo] results.
+ *
+ * This test has to be updated manually whenever the info generation behavior changes, since
+ * there's no single place where flag -> field is defined besides this test.
+ */
+@RunWith(Parameterized::class)
+class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() {
+
+ companion object {
+
+ data class Param<T> constructor(
+ val flag: Int,
+ val logTag: String,
+ val oldPkgFunction: (pkg: PackageParser.Package, flags: Int) -> T?,
+ val newPkgFunction: (pkg: AndroidPackage, flags: Int) -> T?,
+ val fieldFunction: (T) -> List<Any?>
+ ) {
+ companion object {
+ fun pkgInfo(flag: Int, fieldFunction: (PackageInfo) -> List<Any?>) = Param(
+ flag, PackageInfo::class.java.simpleName,
+ ::oldPackageInfo, ::newPackageInfo, fieldFunction
+ )
+
+ fun appInfo(flag: Int, fieldFunction: (ApplicationInfo) -> List<Any?>) = Param(
+ flag, ApplicationInfo::class.java.simpleName,
+ ::oldAppInfo, ::newAppInfo, fieldFunction
+ )
+ }
+
+ override fun toString(): String {
+ val hex = Integer.toHexString(flag)
+ val fromRight = Integer.toBinaryString(flag).reversed().indexOf('1')
+ return "$logTag $hex | 1 shl $fromRight"
+ }
+ }
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters() = arrayOf(
+ pkgInfo(PackageManager.GET_ACTIVITIES) { listOf(it.activities) },
+ pkgInfo(PackageManager.GET_GIDS) { listOf(it.gids) },
+ pkgInfo(PackageManager.GET_INSTRUMENTATION) { listOf(it.instrumentation) },
+ pkgInfo(PackageManager.GET_META_DATA) { listOf(it.applicationInfo.metaData) },
+ pkgInfo(PackageManager.GET_PROVIDERS) { listOf(it.providers) },
+ pkgInfo(PackageManager.GET_RECEIVERS) { listOf(it.receivers) },
+ pkgInfo(PackageManager.GET_SERVICES) { listOf(it.services) },
+ pkgInfo(PackageManager.GET_SIGNATURES) { listOf(it.signatures) },
+ pkgInfo(PackageManager.GET_SIGNING_CERTIFICATES) { listOf(it.signingInfo) },
+ pkgInfo(PackageManager.GET_SHARED_LIBRARY_FILES) {
+ it.applicationInfo.run { listOf(sharedLibraryFiles, sharedLibraryFiles) }
+ },
+ pkgInfo(PackageManager.GET_CONFIGURATIONS) {
+ listOf(it.configPreferences, it.reqFeatures, it.featureGroups)
+ },
+ pkgInfo(PackageManager.GET_PERMISSIONS) {
+ listOf(it.permissions, it.requestedPermissions, it.requestedPermissionsFlags)
+ },
+
+ appInfo(PackageManager.GET_META_DATA) { listOf(it.metaData) },
+ appInfo(PackageManager.GET_SHARED_LIBRARY_FILES) {
+ listOf(it.sharedLibraryFiles, it.sharedLibraryFiles)
+ }
+ )
+ }
+
+ @Parameterized.Parameter(0)
+ lateinit var param: Param<Any>
+
+ @Test
+ fun fieldPresence() {
+ oldPackages.asSequence().zip(newPackages.asSequence())
+ .forEach { (old, new) ->
+ val oldWithFlag = param.oldPkgFunction(old, param.flag)
+ val newWithFlag = param.newPkgFunction(new, param.flag)
+ val oldFieldList = oldWithFlag?.let(param.fieldFunction).orEmpty()
+ val newFieldList = newWithFlag?.let(param.fieldFunction).orEmpty()
+
+ oldFieldList.zip(newFieldList).forEach {
+ assertWithMessage(new.packageName).that(it.second).apply {
+ // Assert same null-ness as old logic
+ if (it.first == null) {
+ isNull()
+ } else {
+ isNotNull()
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ fun fieldAbsence() {
+ newPackages.forEach {
+ val newWithoutFlag = param.newPkgFunction(it, 0)
+ val newFieldListWithoutFlag = newWithoutFlag?.let(param.fieldFunction).orEmpty()
+ assertThat(newFieldListWithoutFlag.filterNotNull()).isEmpty()
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
new file mode 100644
index 000000000000..925af7fba82a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.parsing
+
+import android.content.pm.PackageManager
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+
+/**
+ * Collects APKs from the device and verifies that the new parsing behavior outputs
+ * the same exposed Info object as the old parsing logic.
+ */
+class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
+
+ @Test
+ fun applicationInfoEquality() {
+ val flags = PackageManager.GET_META_DATA or PackageManager.GET_SHARED_LIBRARY_FILES
+ val oldAppInfo = oldPackages.asSequence().map { oldAppInfo(it, flags) }
+ val newAppInfo = newPackages.asSequence().map { newAppInfo(it, flags) }
+ oldAppInfo.zip(newAppInfo).forEach {
+ val firstName = it.first?.packageName
+ val secondName = it.second?.packageName
+ val packageName = if (firstName == secondName) {
+ "$firstName"
+ } else {
+ "$firstName | $secondName"
+ }
+ assertWithMessage(packageName).that(it.first?.dumpToString())
+ .isEqualTo(it.second?.dumpToString())
+ }
+ }
+
+ @Test
+ fun packageInfoEquality() {
+ val flags = PackageManager.GET_ACTIVITIES or
+ PackageManager.GET_CONFIGURATIONS or
+ PackageManager.GET_GIDS or
+ PackageManager.GET_INSTRUMENTATION or
+ PackageManager.GET_META_DATA or
+ PackageManager.GET_PERMISSIONS or
+ PackageManager.GET_PROVIDERS or
+ PackageManager.GET_RECEIVERS or
+ PackageManager.GET_SERVICES or
+ PackageManager.GET_SHARED_LIBRARY_FILES or
+ PackageManager.GET_SIGNATURES or
+ PackageManager.GET_SIGNING_CERTIFICATES
+ val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) }
+ val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) }
+
+ oldPackageInfo.zip(newPackageInfo).forEach {
+ val firstName = it.first?.packageName
+ val secondName = it.second?.packageName
+ val packageName = if (firstName == secondName) {
+ "$firstName"
+ } else {
+ "$firstName | $secondName"
+ }
+ assertWithMessage(packageName).that(it.first?.dumpToString())
+ .isEqualTo(it.second?.dumpToString())
+ }
+ }
+}
+
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
new file mode 100644
index 000000000000..afd6e1851cde
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.parsing
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.ConfigurationInfo
+import android.content.pm.FeatureInfo
+import android.content.pm.InstrumentationInfo
+import android.content.pm.PackageInfo
+import android.content.pm.PackageParser
+import android.content.pm.PackageUserState
+import android.content.pm.PermissionInfo
+import android.content.pm.ProviderInfo
+import android.content.pm.parsing.AndroidPackage
+import android.content.pm.parsing.PackageImpl
+import android.content.pm.parsing.PackageInfoUtils
+import android.os.Debug
+import android.os.Environment
+import android.util.SparseArray
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.pm.PackageManagerService
+import org.junit.BeforeClass
+import org.mockito.Mockito
+import java.io.File
+
+open class AndroidPackageParsingTestBase {
+
+ companion object {
+
+ /**
+ * By default, don't parse all APKs on device, only the framework one.
+ * Toggle this manually if working on package parsing.
+ */
+ private const val VERIFY_ALL_APKS = false
+
+ /** For auditing memory usage differences */
+ private const val DUMP_HPROF_TO_EXTERNAL = false
+
+ val context: Context = InstrumentationRegistry.getInstrumentation().getContext()
+ protected val packageParser = PackageParser().apply {
+ setOnlyCoreApps(false)
+ setDisplayMetrics(context.resources.displayMetrics)
+ setCallback { true }
+ }
+
+ /**
+ * It would be difficult to mock all possibilities, so just use the APKs on device.
+ * Unfortunately, this means the device must be bootable to verify potentially
+ * boot-breaking behavior.
+ */
+ private val apks = mutableListOf(File(Environment.getRootDirectory(), "framework"))
+ .apply {
+ @Suppress("ConstantConditionIf")
+ if (VERIFY_ALL_APKS) {
+ this += (PackageManagerService.SYSTEM_PARTITIONS)
+ .flatMap {
+ listOfNotNull(it.privAppFolder, it.appFolder, it.overlayFolder)
+ }
+ }
+ }
+ .flatMap {
+ it.walkTopDown()
+ .filter { file -> file.name.endsWith(".apk") }
+ .toList()
+ }
+
+ private val dummyState = Mockito.mock(PackageUserState::class.java).apply {
+ installed = true
+ Mockito.`when`(isAvailable(Mockito.anyInt())).thenReturn(true)
+ }
+
+ lateinit var oldPackages: List<PackageParser.Package>
+
+ lateinit var newPackages: List<AndroidPackage>
+
+ @Suppress("ConstantConditionIf")
+ @JvmStatic
+ @BeforeClass
+ fun setUpPackages() {
+ this.oldPackages = apks.map {
+ packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+ }
+
+ this.newPackages = apks.map {
+ packageParser.parseParsedPackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+ }
+
+ if (DUMP_HPROF_TO_EXTERNAL) {
+ System.gc()
+ Environment.getExternalStorageDirectory()
+ .resolve("${AndroidPackageParsingTestBase::class.java.simpleName}.hprof")
+ .absolutePath
+ .run(Debug::dumpHprofData)
+ }
+ }
+
+ fun oldAppInfo(pkg: PackageParser.Package, flags: Int = 0): ApplicationInfo? {
+ return PackageParser.generateApplicationInfo(pkg, flags, dummyState, 0)
+ }
+
+ fun newAppInfo(pkg: AndroidPackage, flags: Int = 0): ApplicationInfo? {
+ return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyState, 0)
+ }
+
+ fun oldPackageInfo(pkg: PackageParser.Package, flags: Int = 0): PackageInfo? {
+ return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState)
+ }
+
+ fun newPackageInfo(pkg: AndroidPackage, flags: Int = 0): PackageInfo? {
+ return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState, 0)
+ }
+ }
+
+ // The following methods dump an exact set of fields from the object to compare, because
+ // 1. comprehensive equals/toStrings do not exist on all of the Info objects, and
+ // 2. the test must only verify fields that [PackageParser.Package] can actually fill, as
+ // no new functionality will be added to it.
+
+ // The following methods prepend "this." because @hide APIs can cause an IDE to auto-import
+ // the R.attr constant instead of referencing the field in an attempt to fix the error.
+
+ /**
+ * Known exclusions:
+ * - [ApplicationInfo.credentialProtectedDataDir]
+ * - [ApplicationInfo.dataDir]
+ * - [ApplicationInfo.deviceProtectedDataDir]
+ * - [ApplicationInfo.processName]
+ * - [ApplicationInfo.publicSourceDir]
+ * - [ApplicationInfo.scanPublicSourceDir]
+ * - [ApplicationInfo.scanSourceDir]
+ * - [ApplicationInfo.sourceDir]
+ * These attributes used to be assigned post-package-parsing as part of another component,
+ * but are now adjusted directly inside [PackageImpl].
+ */
+ protected fun ApplicationInfo.dumpToString() = """
+ appComponentFactory=${this.appComponentFactory}
+ backupAgentName=${this.backupAgentName}
+ banner=${this.banner}
+ category=${this.category}
+ classLoaderName=${this.classLoaderName}
+ className=${this.className}
+ compatibleWidthLimitDp=${this.compatibleWidthLimitDp}
+ compileSdkVersion=${this.compileSdkVersion}
+ compileSdkVersionCodename=${this.compileSdkVersionCodename}
+ descriptionRes=${this.descriptionRes}
+ enabled=${this.enabled}
+ enabledSetting=${this.enabledSetting}
+ flags=${Integer.toBinaryString(this.flags)}
+ fullBackupContent=${this.fullBackupContent}
+ hiddenUntilInstalled=${this.hiddenUntilInstalled}
+ icon=${this.icon}
+ iconRes=${this.iconRes}
+ installLocation=${this.installLocation}
+ largestWidthLimitDp=${this.largestWidthLimitDp}
+ logo=${this.logo}
+ longVersionCode=${this.longVersionCode}
+ manageSpaceActivityName=${this.manageSpaceActivityName}
+ maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio}
+ metaData=${this.metaData}
+ minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio}
+ minSdkVersion=${this.minSdkVersion}
+ name=${this.name}
+ nativeLibraryDir=${this.nativeLibraryDir}
+ nativeLibraryRootDir=${this.nativeLibraryRootDir}
+ nativeLibraryRootRequiresIsa=${this.nativeLibraryRootRequiresIsa}
+ networkSecurityConfigRes=${this.networkSecurityConfigRes}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
+ permission=${this.permission}
+ primaryCpuAbi=${this.primaryCpuAbi}
+ privateFlags=${Integer.toBinaryString(this.privateFlags)}
+ requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
+ resourceDirs=${this.resourceDirs?.contentToString()}
+ roundIconRes=${this.roundIconRes}
+ secondaryCpuAbi=${this.secondaryCpuAbi}
+ secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+ seInfo=${this.seInfo}
+ seInfoUser=${this.seInfoUser}
+ sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()}
+ sharedLibraryInfos=${this.sharedLibraryInfos}
+ showUserIcon=${this.showUserIcon}
+ splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()}
+ splitDependencies=${this.splitDependencies}
+ splitNames=${this.splitNames?.contentToString()}
+ splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
+ splitSourceDirs=${this.splitSourceDirs?.contentToString()}
+ storageUuid=${this.storageUuid}
+ targetSandboxVersion=${this.targetSandboxVersion}
+ targetSdkVersion=${this.targetSdkVersion}
+ taskAffinity=${this.taskAffinity}
+ theme=${this.theme}
+ uid=${this.uid}
+ uiOptions=${this.uiOptions}
+ versionCode=${this.versionCode}
+ volumeUuid=${this.volumeUuid}
+ zygotePreloadName=${this.zygotePreloadName}
+ """.trimIndent()
+
+ protected fun FeatureInfo.dumpToString() = """
+ flags=${Integer.toBinaryString(this.flags)}
+ name=${this.name}
+ reqGlEsVersion=${this.reqGlEsVersion}
+ version=${this.version}
+ """.trimIndent()
+
+ protected fun InstrumentationInfo.dumpToString() = """
+ credentialProtectedDataDir=${this.credentialProtectedDataDir}
+ dataDir=${this.dataDir}
+ deviceProtectedDataDir=${this.deviceProtectedDataDir}
+ functionalTest=${this.functionalTest}
+ handleProfiling=${this.handleProfiling}
+ nativeLibraryDir=${this.nativeLibraryDir}
+ primaryCpuAbi=${this.primaryCpuAbi}
+ publicSourceDir=${this.publicSourceDir}
+ secondaryCpuAbi=${this.secondaryCpuAbi}
+ secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+ sourceDir=${this.sourceDir}
+ splitDependencies=${this.splitDependencies.sequence().map { it.first to it.second?.contentToString() }.joinToString()}
+ splitNames=${this.splitNames?.contentToString()}
+ splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
+ splitSourceDirs=${this.splitSourceDirs?.contentToString()}
+ targetPackage=${this.targetPackage}
+ targetProcesses=${this.targetProcesses}
+ """.trimIndent()
+
+ protected fun ActivityInfo.dumpToString() = """
+ colorMode=${this.colorMode}
+ configChanges=${this.configChanges}
+ documentLaunchMode=${this.documentLaunchMode}
+ flags=${Integer.toBinaryString(this.flags)}
+ launchMode=${this.launchMode}
+ launchToken=${this.launchToken}
+ lockTaskLaunchMode=${this.lockTaskLaunchMode}
+ maxAspectRatio=${this.maxAspectRatio}
+ maxRecents=${this.maxRecents}
+ minAspectRatio=${this.minAspectRatio}
+ parentActivityName=${this.parentActivityName}
+ permission=${this.permission}
+ persistableMode=${this.persistableMode}
+ privateFlags=${Integer.toBinaryString(this.privateFlags)}
+ requestedVrComponent=${this.requestedVrComponent}
+ resizeMode=${this.resizeMode}
+ rotationAnimation=${this.rotationAnimation}
+ screenOrientation=${this.screenOrientation}
+ softInputMode=${this.softInputMode}
+ targetActivity=${this.targetActivity}
+ taskAffinity=${this.taskAffinity}
+ theme=${this.theme}
+ uiOptions=${this.uiOptions}
+ windowLayout=${this.windowLayout?.dumpToString()}
+ """.trimIndent()
+
+ protected fun ActivityInfo.WindowLayout.dumpToString() = """
+ gravity=${this.gravity}
+ height=${this.height}
+ heightFraction=${this.heightFraction}
+ minHeight=${this.minHeight}
+ minWidth=${this.minWidth}
+ width=${this.width}
+ widthFraction=${this.widthFraction}
+ """.trimIndent()
+
+ protected fun PermissionInfo.dumpToString() = """
+ backgroundPermission=${this.backgroundPermission}
+ descriptionRes=${this.descriptionRes}
+ flags=${Integer.toBinaryString(this.flags)}
+ group=${this.group}
+ nonLocalizedDescription=${this.nonLocalizedDescription}
+ protectionLevel=${this.protectionLevel}
+ requestRes=${this.requestRes}
+ """.trimIndent()
+
+ protected fun ProviderInfo.dumpToString() = """
+ authority=${this.authority}
+ flags=${Integer.toBinaryString(this.flags)}
+ forceUriPermissions=${this.forceUriPermissions}
+ grantUriPermissions=${this.grantUriPermissions}
+ initOrder=${this.initOrder}
+ isSyncable=${this.isSyncable}
+ multiprocess=${this.multiprocess}
+ pathPermissions=${this.pathPermissions?.joinToString { "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" }}
+ readPermission=${this.readPermission}
+ uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
+ writePermission=${this.writePermission}
+ """.trimIndent()
+
+ protected fun ConfigurationInfo.dumpToString() = """
+ reqGlEsVersion=${this.reqGlEsVersion}
+ reqInputFeatures=${this.reqInputFeatures}
+ reqKeyboardType=${this.reqKeyboardType}
+ reqNavigation=${this.reqNavigation}
+ reqTouchScreen=${this.reqTouchScreen}
+ """.trimIndent()
+
+ protected fun PackageInfo.dumpToString() = """
+ activities=${this.activities?.joinToString { it.dumpToString() }}
+ applicationInfo=${this.applicationInfo.dumpToString()}
+ baseRevisionCode=${this.baseRevisionCode}
+ compileSdkVersion=${this.compileSdkVersion}
+ compileSdkVersionCodename=${this.compileSdkVersionCodename}
+ configPreferences=${this.configPreferences?.joinToString { it.dumpToString() }}
+ coreApp=${this.coreApp}
+ featureGroups=${this.featureGroups?.joinToString { it.features?.joinToString { featureInfo -> featureInfo.dumpToString() }.orEmpty() }}
+ firstInstallTime=${this.firstInstallTime}
+ gids=${gids?.contentToString()}
+ installLocation=${this.installLocation}
+ instrumentation=${instrumentation?.joinToString { it.dumpToString() }}
+ isApex=${this.isApex}
+ isStub=${this.isStub}
+ lastUpdateTime=${this.lastUpdateTime}
+ mOverlayIsStatic=${this.mOverlayIsStatic}
+ overlayCategory=${this.overlayCategory}
+ overlayPriority=${this.overlayPriority}
+ overlayTarget=${this.overlayTarget}
+ packageName=${this.packageName}
+ permissions=${this.permissions?.joinToString { it.dumpToString() }}
+ providers=${this.providers?.joinToString { it.dumpToString() }}
+ receivers=${this.receivers?.joinToString { it.dumpToString() }}
+ reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
+ requestedPermissions=${this.requestedPermissions?.contentToString()}
+ requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()}
+ requiredAccountType=${this.requiredAccountType}
+ requiredForAllUsers=${this.requiredForAllUsers}
+ restrictedAccountType=${this.restrictedAccountType}
+ services=${this.services?.contentToString()}
+ sharedUserId=${this.sharedUserId}
+ sharedUserLabel=${this.sharedUserLabel}
+ signatures=${this.signatures?.joinToString { it.toCharsString() }}
+ signingInfo=${this.signingInfo?.signingCertificateHistory?.joinToString { it.toCharsString() }.orEmpty()}
+ splitNames=${this.splitNames?.contentToString()}
+ splitRevisionCodes=${this.splitRevisionCodes?.contentToString()}
+ targetOverlayableName=${this.targetOverlayableName}
+ versionCode=${this.versionCode}
+ versionCodeMajor=${this.versionCodeMajor}
+ versionName=${this.versionName}
+ """.trimIndent()
+
+ @Suppress("unused")
+ private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> {
+ var index = 0
+ return generateSequence {
+ index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) }
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
index 7a0a28dfbd16..52e7d8197842 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
@@ -42,11 +42,12 @@ import java.time.Duration;
@RunWith(AndroidJUnit4.class)
public class SimpleTimeDetectorStrategyTest {
- private static final Scenario SCENARIO_1 = new Scenario.Builder()
- .setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0)
- .setInitialDeviceRealtimeMillis(123456789L)
- .setActualTimeUtc(2018, 1, 1, 12, 0, 0)
- .build();
+ private static final TimestampedValue<Long> ARBITRARY_CLOCK_INITIALIZATION_INFO =
+ new TimestampedValue<>(
+ 123456789L /* realtimeClockMillis */,
+ createUtcTime(1977, 1, 1, 12, 0, 0));
+
+ private static final long ARBITRARY_TEST_TIME_MILLIS = createUtcTime(2018, 1, 1, 12, 0, 0);
private static final int ARBITRARY_PHONE_ID = 123456;
@@ -61,116 +62,211 @@ public class SimpleTimeDetectorStrategyTest {
@Test
public void testSuggestPhoneTime_autoTimeEnabled() {
- Scenario scenario = SCENARIO_1;
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(true);
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+ int phoneId = ARBITRARY_PHONE_ID;
+ long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
PhoneTimeSuggestion timeSuggestion =
- scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
- final int clockIncrement = 1000;
- long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
+ mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ int clockIncrement = 1000;
+ long expectedSystemClockMillis = testTimeMillis + clockIncrement;
mScript.simulateTimePassing(clockIncrement)
.simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- expectSystemClockMillis, true /* expectNetworkBroadcast */);
+ expectedSystemClockMillis, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion);
}
@Test
public void testSuggestPhoneTime_emptySuggestionIgnored() {
- Scenario scenario = SCENARIO_1;
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(true);
-
- PhoneTimeSuggestion timeSuggestion = createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, null);
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+ int phoneId = ARBITRARY_PHONE_ID;
+ PhoneTimeSuggestion timeSuggestion =
+ mScript.generatePhoneTimeSuggestion(phoneId, null);
mScript.simulatePhoneTimeSuggestion(timeSuggestion)
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, null);
}
@Test
public void testSuggestPhoneTime_systemClockThreshold() {
- Scenario scenario = SCENARIO_1;
- final int systemClockUpdateThresholdMillis = 1000;
- mScript.pokeFakeClocks(scenario)
+ int systemClockUpdateThresholdMillis = 1000;
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeThresholds(systemClockUpdateThresholdMillis)
- .pokeTimeDetectionEnabled(true);
-
- PhoneTimeSuggestion timeSuggestion1 =
- scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
- TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
+ .pokeAutoTimeDetectionEnabled(true);
final int clockIncrement = 100;
- // Increment the the device clocks to simulate the passage of time.
- mScript.simulateTimePassing(clockIncrement);
-
- long expectSystemClockMillis1 =
- TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+ int phoneId = ARBITRARY_PHONE_ID;
// Send the first time signal. It should be used.
- mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
- .verifySystemClockWasSetAndResetCallTracking(
- expectSystemClockMillis1, true /* expectNetworkBroadcast */);
+ {
+ long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ PhoneTimeSuggestion timeSuggestion1 =
+ mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
+
+ // Increment the the device clocks to simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+
+ long expectedSystemClockMillis1 =
+ TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis1, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ }
// Now send another time signal, but one that is too similar to the last one and should be
- // ignored.
- int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
- TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
- mScript.peekElapsedRealtimeMillis(),
- mScript.peekSystemClockMillis() + underThresholdMillis);
- PhoneTimeSuggestion timeSuggestion2 =
- createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
- mScript.simulateTimePassing(clockIncrement)
- .simulatePhoneTimeSuggestion(timeSuggestion2)
- .verifySystemClockWasNotSetAndResetCallTracking();
+ // stored, but not used to set the system clock.
+ {
+ int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
+ PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion(
+ phoneId, mScript.peekSystemClockMillis() + underThresholdMillis);
+ mScript.simulateTimePassing(clockIncrement)
+ .simulatePhoneTimeSuggestion(timeSuggestion2)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion2);
+ }
// Now send another time signal, but one that is on the threshold and so should be used.
- TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
- mScript.peekElapsedRealtimeMillis(),
- mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
+ {
+ PhoneTimeSuggestion timeSuggestion3 = mScript.generatePhoneTimeSuggestion(
+ phoneId,
+ mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
+ mScript.simulateTimePassing(clockIncrement);
+
+ long expectedSystemClockMillis3 =
+ TimeDetectorStrategy.getTimeAt(timeSuggestion3.getUtcTime(),
+ mScript.peekElapsedRealtimeMillis());
+
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis3, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion3);
+ }
+ }
+
+ @Test
+ public void testSuggestPhoneTime_multiplePhoneIdsAndBucketing() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ // There are 2 phones in this test. Phone 2 has a different idea of the current time.
+ // phone1Id < phone2Id (which is important because the strategy uses the lowest ID when
+ // multiple phone suggestions are available.
+ int phone1Id = ARBITRARY_PHONE_ID;
+ int phone2Id = ARBITRARY_PHONE_ID + 1;
+ long phone1TimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ long phone2TimeMillis = phone1TimeMillis + 60000;
+
+ final int clockIncrement = 999;
+
+ // Make a suggestion with phone2Id.
+ {
+ PhoneTimeSuggestion phone2TimeSuggestion =
+ mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
+ mScript.simulateTimePassing(clockIncrement);
+
+ long expectedSystemClockMillis = phone2TimeMillis + clockIncrement;
+
+ mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phone1Id, null)
+ .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion);
+ }
- PhoneTimeSuggestion timeSuggestion3 =
- createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
mScript.simulateTimePassing(clockIncrement);
- long expectSystemClockMillis3 =
- TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
+ // Now make a different suggestion with phone1Id.
+ {
+ PhoneTimeSuggestion phone1TimeSuggestion =
+ mScript.generatePhoneTimeSuggestion(phone1Id, phone1TimeMillis);
+ mScript.simulateTimePassing(clockIncrement);
- mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
- .verifySystemClockWasSetAndResetCallTracking(
- expectSystemClockMillis3, true /* expectNetworkBroadcast */);
+ long expectedSystemClockMillis = phone1TimeMillis + clockIncrement;
+
+ mScript.simulatePhoneTimeSuggestion(phone1TimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phone1Id, phone1TimeSuggestion);
+
+ }
+
+ mScript.simulateTimePassing(clockIncrement);
+
+ // Make another suggestion with phone2Id. It should be stored but not used because the
+ // phone1Id suggestion will still "win".
+ {
+ PhoneTimeSuggestion phone2TimeSuggestion =
+ mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
+ mScript.simulateTimePassing(clockIncrement);
+
+ mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion);
+ }
+
+ // Let enough time pass that phone1Id's suggestion should now be too old.
+ mScript.simulateTimePassing(SimpleTimeDetectorStrategy.PHONE_BUCKET_SIZE_MILLIS);
+
+ // Make another suggestion with phone2Id. It should be used because the phoneId1
+ // is in an older "bucket".
+ {
+ PhoneTimeSuggestion phone2TimeSuggestion =
+ mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
+ mScript.simulateTimePassing(clockIncrement);
+
+ long expectedSystemClockMillis = phone2TimeMillis + clockIncrement;
+
+ mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion);
+ }
}
@Test
public void testSuggestPhoneTime_autoTimeDisabled() {
- Scenario scenario = SCENARIO_1;
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(false);
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(false);
+ int phoneId = ARBITRARY_PHONE_ID;
PhoneTimeSuggestion timeSuggestion =
- scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
- mScript.simulatePhoneTimeSuggestion(timeSuggestion)
- .verifySystemClockWasNotSetAndResetCallTracking();
+ mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS);
+ mScript.simulateTimePassing(1000)
+ .simulatePhoneTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion);
}
@Test
public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() {
- Scenario scenario = SCENARIO_1;
final int systemClockUpdateThreshold = 2000;
- mScript.pokeFakeClocks(scenario)
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeThresholds(systemClockUpdateThreshold)
- .pokeTimeDetectionEnabled(true);
+ .pokeAutoTimeDetectionEnabled(true);
+
+ long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ int phoneId = ARBITRARY_PHONE_ID;
+
PhoneTimeSuggestion timeSuggestion1 =
- scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
- // Initialize the strategy / device with a time set from NITZ.
+ // Initialize the strategy / device with a time set from a phone suggestion.
mScript.simulateTimePassing(100);
long expectedSystemClockMillis1 =
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
- expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
+ expectedSystemClockMillis1, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
// The UTC time increment should be larger than the system clock update threshold so we
// know it shouldn't be ignored for other reasons.
@@ -182,9 +278,10 @@ public class SimpleTimeDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
PhoneTimeSuggestion timeSuggestion2 =
- createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+ createPhoneTimeSuggestion(phoneId, utcTime2);
mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
// Now supply a new signal that has an obviously bogus reference time : substantially in the
// future.
@@ -193,9 +290,10 @@ public class SimpleTimeDetectorStrategyTest {
TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
referenceTimeInFutureMillis, validUtcTimeMillis);
PhoneTimeSuggestion timeSuggestion3 =
- createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
+ createPhoneTimeSuggestion(phoneId, utcTime3);
mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
// Just to prove validUtcTimeMillis is valid.
long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
@@ -204,23 +302,25 @@ public class SimpleTimeDetectorStrategyTest {
long expectedSystemClockMillis4 =
TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
PhoneTimeSuggestion timeSuggestion4 =
- createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
+ createPhoneTimeSuggestion(phoneId, utcTime4);
mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
.verifySystemClockWasSetAndResetCallTracking(
- expectedSystemClockMillis4, true /* expectNetworkBroadcast */);
+ expectedSystemClockMillis4, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion4);
}
@Test
public void testSuggestPhoneTime_timeDetectionToggled() {
- Scenario scenario = SCENARIO_1;
final int clockIncrementMillis = 100;
final int systemClockUpdateThreshold = 2000;
- mScript.pokeFakeClocks(scenario)
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeThresholds(systemClockUpdateThreshold)
- .pokeTimeDetectionEnabled(false);
+ .pokeAutoTimeDetectionEnabled(false);
+ int phoneId = ARBITRARY_PHONE_ID;
+ long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
PhoneTimeSuggestion timeSuggestion1 =
- scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Simulate time passing.
@@ -229,7 +329,8 @@ public class SimpleTimeDetectorStrategyTest {
// Simulate the time signal being received. It should not be used because auto time
// detection is off but it should be recorded.
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
@@ -240,64 +341,95 @@ public class SimpleTimeDetectorStrategyTest {
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
.verifySystemClockWasSetAndResetCallTracking(
- expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
+ expectedSystemClockMillis1, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
// Turn off auto time detection.
mScript.simulateAutoTimeDetectionToggle()
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
// Receive another valid time signal.
// It should be on the threshold and accounting for the clock increments.
- TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
- mScript.peekElapsedRealtimeMillis(),
- mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
- PhoneTimeSuggestion timeSuggestion2 =
- createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion(
+ phoneId, mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
- long expectedSystemClockMillis2 =
- TimeDetectorStrategy.getTimeAt(utcTime2, mScript.peekElapsedRealtimeMillis());
+ long expectedSystemClockMillis2 = TimeDetectorStrategy.getTimeAt(
+ timeSuggestion2.getUtcTime(), mScript.peekElapsedRealtimeMillis());
// The new time, though valid, should not be set in the system clock because auto time is
// disabled.
mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion2);
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
.verifySystemClockWasSetAndResetCallTracking(
- expectedSystemClockMillis2, true /* expectNetworkBroadcast */);
+ expectedSystemClockMillis2, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, timeSuggestion2);
+ }
+
+ @Test
+ public void testSuggestPhoneTime_maxSuggestionAge() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ int phoneId = ARBITRARY_PHONE_ID;
+ long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ PhoneTimeSuggestion phoneSuggestion =
+ mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ int clockIncrementMillis = 1000;
+
+ mScript.simulateTimePassing(clockIncrementMillis)
+ .simulatePhoneTimeSuggestion(phoneSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ testTimeMillis + clockIncrementMillis, true /* expectedNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, phoneSuggestion);
+
+ // Look inside and check what the strategy considers the current best phone suggestion.
+ assertEquals(phoneSuggestion, mScript.peekBestPhoneSuggestion());
+
+ // Simulate time passing, long enough that phoneSuggestion is now too old.
+ mScript.simulateTimePassing(SimpleTimeDetectorStrategy.PHONE_MAX_AGE_MILLIS);
+
+ // Look inside and check what the strategy considers the current best phone suggestion. It
+ // should still be the, it's just no longer used.
+ assertNull(mScript.peekBestPhoneSuggestion());
+ mScript.assertLatestPhoneSuggestion(phoneId, phoneSuggestion);
}
@Test
public void testSuggestManualTime_autoTimeDisabled() {
- Scenario scenario = SCENARIO_1;
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(false);
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(false);
- ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+ long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ ManualTimeSuggestion timeSuggestion = mScript.generateManualTimeSuggestion(testTimeMillis);
final int clockIncrement = 1000;
- long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
+ long expectedSystemClockMillis = testTimeMillis + clockIncrement;
mScript.simulateTimePassing(clockIncrement)
.simulateManualTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- expectSystemClockMillis, false /* expectNetworkBroadcast */);
+ expectedSystemClockMillis, false /* expectNetworkBroadcast */);
}
@Test
public void testSuggestManualTime_retainsAutoSignal() {
- Scenario scenario = SCENARIO_1;
-
// Configure the start state.
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(true);
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ int phoneId = ARBITRARY_PHONE_ID;
// Simulate a phone suggestion.
+ long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
PhoneTimeSuggestion phoneTimeSuggestion =
- scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue();
final int clockIncrement = 1000;
@@ -307,7 +439,8 @@ public class SimpleTimeDetectorStrategyTest {
mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+ expectedAutoClockMillis, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
// Simulate the passage of time.
mScript.simulateTimePassing(clockIncrement);
@@ -315,20 +448,22 @@ public class SimpleTimeDetectorStrategyTest {
// Switch to manual.
mScript.simulateAutoTimeDetectionToggle()
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
// Simulate the passage of time.
mScript.simulateTimePassing(clockIncrement);
expectedAutoClockMillis += clockIncrement;
-
// Simulate a manual suggestion 1 day different from the auto suggestion.
- long manualTimeMillis = SCENARIO_1.getActualTimeMillis() + ONE_DAY_MILLIS;
+ long manualTimeMillis = testTimeMillis + ONE_DAY_MILLIS;
long expectedManualClockMillis = manualTimeMillis;
- ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(manualTimeMillis);
+ ManualTimeSuggestion manualTimeSuggestion =
+ mScript.generateManualTimeSuggestion(manualTimeMillis);
mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- expectedManualClockMillis, false /* expectNetworkBroadcast */);
+ expectedManualClockMillis, false /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
// Simulate the passage of time.
mScript.simulateTimePassing(clockIncrement);
@@ -338,11 +473,13 @@ public class SimpleTimeDetectorStrategyTest {
mScript.simulateAutoTimeDetectionToggle();
mScript.verifySystemClockWasSetAndResetCallTracking(
- expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+ expectedAutoClockMillis, true /* expectNetworkBroadcast */)
+ .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
// Switch back to manual - nothing should happen to the clock.
mScript.simulateAutoTimeDetectionToggle()
- .verifySystemClockWasNotSetAndResetCallTracking();
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
}
/**
@@ -350,11 +487,11 @@ public class SimpleTimeDetectorStrategyTest {
*/
@Test
public void testSuggestManualTime_autoTimeEnabled() {
- Scenario scenario = SCENARIO_1;
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(true);
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
- ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+ ManualTimeSuggestion timeSuggestion =
+ mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
final int clockIncrement = 1000;
mScript.simulateTimePassing(clockIncrement)
@@ -367,7 +504,7 @@ public class SimpleTimeDetectorStrategyTest {
* like the real thing should, it also asserts preconditions.
*/
private static class FakeCallback implements TimeDetectorStrategy.Callback {
- private boolean mTimeDetectionEnabled;
+ private boolean mAutoTimeDetectionEnabled;
private boolean mWakeLockAcquired;
private long mElapsedRealtimeMillis;
private long mSystemClockMillis;
@@ -384,7 +521,7 @@ public class SimpleTimeDetectorStrategyTest {
@Override
public boolean isAutoTimeDetectionEnabled() {
- return mTimeDetectionEnabled;
+ return mAutoTimeDetectionEnabled;
}
@Override
@@ -397,7 +534,6 @@ public class SimpleTimeDetectorStrategyTest {
@Override
public long elapsedRealtimeMillis() {
- assertWakeLockAcquired();
return mElapsedRealtimeMillis;
}
@@ -428,57 +564,57 @@ public class SimpleTimeDetectorStrategyTest {
// Methods below are for managing the fake's behavior.
- public void pokeSystemClockUpdateThreshold(int thresholdMillis) {
+ void pokeSystemClockUpdateThreshold(int thresholdMillis) {
mSystemClockUpdateThresholdMillis = thresholdMillis;
}
- public void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
+ void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
mElapsedRealtimeMillis = elapsedRealtimeMillis;
}
- public void pokeSystemClockMillis(long systemClockMillis) {
+ void pokeSystemClockMillis(long systemClockMillis) {
mSystemClockMillis = systemClockMillis;
}
- public void pokeAutoTimeDetectionEnabled(boolean enabled) {
- mTimeDetectionEnabled = enabled;
+ void pokeAutoTimeDetectionEnabled(boolean enabled) {
+ mAutoTimeDetectionEnabled = enabled;
}
- public long peekElapsedRealtimeMillis() {
+ long peekElapsedRealtimeMillis() {
return mElapsedRealtimeMillis;
}
- public long peekSystemClockMillis() {
+ long peekSystemClockMillis() {
return mSystemClockMillis;
}
- public void simulateTimePassing(int incrementMillis) {
+ void simulateTimePassing(long incrementMillis) {
mElapsedRealtimeMillis += incrementMillis;
mSystemClockMillis += incrementMillis;
}
- public void simulateAutoTimeZoneDetectionToggle() {
- mTimeDetectionEnabled = !mTimeDetectionEnabled;
+ void simulateAutoTimeZoneDetectionToggle() {
+ mAutoTimeDetectionEnabled = !mAutoTimeDetectionEnabled;
}
- public void verifySystemClockNotSet() {
+ void verifySystemClockNotSet() {
assertFalse(mSystemClockWasSet);
}
- public void verifySystemClockWasSet(long expectSystemClockMillis) {
+ void verifySystemClockWasSet(long expectedSystemClockMillis) {
assertTrue(mSystemClockWasSet);
- assertEquals(expectSystemClockMillis, mSystemClockMillis);
+ assertEquals(expectedSystemClockMillis, mSystemClockMillis);
}
- public void verifyIntentWasBroadcast() {
+ void verifyIntentWasBroadcast() {
assertTrue(mBroadcastSent != null);
}
- public void verifyIntentWasNotBroadcast() {
+ void verifyIntentWasNotBroadcast() {
assertNull(mBroadcastSent);
}
- public void resetCallTracking() {
+ void resetCallTracking() {
mSystemClockWasSet = false;
mBroadcastSent = null;
}
@@ -495,23 +631,23 @@ public class SimpleTimeDetectorStrategyTest {
private class Script {
private final FakeCallback mFakeCallback;
- private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy;
+ private final SimpleTimeDetectorStrategy mTimeDetectorStrategy;
Script() {
mFakeCallback = new FakeCallback();
- mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
- mSimpleTimeDetectorStrategy.initialize(mFakeCallback);
+ mTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
+ mTimeDetectorStrategy.initialize(mFakeCallback);
}
- Script pokeTimeDetectionEnabled(boolean enabled) {
+ Script pokeAutoTimeDetectionEnabled(boolean enabled) {
mFakeCallback.pokeAutoTimeDetectionEnabled(enabled);
return this;
}
- Script pokeFakeClocks(Scenario scenario) {
- mFakeCallback.pokeElapsedRealtimeMillis(scenario.getInitialRealTimeMillis());
- mFakeCallback.pokeSystemClockMillis(scenario.getInitialSystemClockMillis());
+ Script pokeFakeClocks(TimestampedValue<Long> timeInfo) {
+ mFakeCallback.pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis());
+ mFakeCallback.pokeSystemClockMillis(timeInfo.getValue());
return this;
}
@@ -529,23 +665,23 @@ public class SimpleTimeDetectorStrategyTest {
}
Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
- mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
+ mTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
return this;
}
Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) {
- mSimpleTimeDetectorStrategy.suggestManualTime(timeSuggestion);
+ mTimeDetectorStrategy.suggestManualTime(timeSuggestion);
return this;
}
Script simulateAutoTimeDetectionToggle() {
mFakeCallback.simulateAutoTimeZoneDetectionToggle();
- mSimpleTimeDetectorStrategy.handleAutoTimeDetectionChanged();
+ mTimeDetectorStrategy.handleAutoTimeDetectionChanged();
return this;
}
- Script simulateTimePassing(int clockIncrement) {
- mFakeCallback.simulateTimePassing(clockIncrement);
+ Script simulateTimePassing(long clockIncrementMillis) {
+ mFakeCallback.simulateTimePassing(clockIncrementMillis);
return this;
}
@@ -557,84 +693,51 @@ public class SimpleTimeDetectorStrategyTest {
}
Script verifySystemClockWasSetAndResetCallTracking(
- long expectSystemClockMillis, boolean expectNetworkBroadcast) {
- mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
+ long expectedSystemClockMillis, boolean expectNetworkBroadcast) {
+ mFakeCallback.verifySystemClockWasSet(expectedSystemClockMillis);
if (expectNetworkBroadcast) {
mFakeCallback.verifyIntentWasBroadcast();
}
mFakeCallback.resetCallTracking();
return this;
}
- }
- /**
- * A starting scenario used during tests. Describes a fictional "physical" reality.
- */
- private static class Scenario {
-
- private final long mInitialDeviceSystemClockMillis;
- private final long mInitialDeviceRealtimeMillis;
- private final long mActualTimeMillis;
-
- Scenario(long initialDeviceSystemClock, long elapsedRealtime, long timeMillis) {
- mInitialDeviceSystemClockMillis = initialDeviceSystemClock;
- mActualTimeMillis = timeMillis;
- mInitialDeviceRealtimeMillis = elapsedRealtime;
- }
-
- long getInitialRealTimeMillis() {
- return mInitialDeviceRealtimeMillis;
- }
-
- long getInitialSystemClockMillis() {
- return mInitialDeviceSystemClockMillis;
- }
-
- long getActualTimeMillis() {
- return mActualTimeMillis;
- }
-
- PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
- TimestampedValue<Long> time = new TimestampedValue<>(
- mInitialDeviceRealtimeMillis, mActualTimeMillis);
- return createPhoneTimeSuggestion(phoneId, time);
- }
-
- ManualTimeSuggestion createManualTimeSuggestionForActual() {
- TimestampedValue<Long> time = new TimestampedValue<>(
- mInitialDeviceRealtimeMillis, mActualTimeMillis);
- return new ManualTimeSuggestion(time);
+ /**
+ * White box test info: Asserts the latest suggestion for the phone ID is as expected.
+ */
+ Script assertLatestPhoneSuggestion(int phoneId, PhoneTimeSuggestion expected) {
+ assertEquals(expected, mTimeDetectorStrategy.getLatestPhoneSuggestion(phoneId));
+ return this;
}
- static class Builder {
-
- private long mInitialDeviceSystemClockMillis;
- private long mInitialDeviceRealtimeMillis;
- private long mActualTimeMillis;
-
- Builder setInitialDeviceSystemClockUtc(int year, int monthInYear, int day,
- int hourOfDay, int minute, int second) {
- mInitialDeviceSystemClockMillis = createUtcTime(year, monthInYear, day, hourOfDay,
- minute, second);
- return this;
- }
-
- Builder setInitialDeviceRealtimeMillis(long realtimeMillis) {
- mInitialDeviceRealtimeMillis = realtimeMillis;
- return this;
- }
-
- Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
- int minute, int second) {
- mActualTimeMillis =
- createUtcTime(year, monthInYear, day, hourOfDay, minute, second);
- return this;
- }
-
- Scenario build() {
- return new Scenario(mInitialDeviceSystemClockMillis, mInitialDeviceRealtimeMillis,
- mActualTimeMillis);
+ /**
+ * White box test info: Returns the phone suggestion that would be used, if any, given the
+ * current elapsed real time clock.
+ */
+ PhoneTimeSuggestion peekBestPhoneSuggestion() {
+ return mTimeDetectorStrategy.findBestPhoneSuggestionForTests();
+ }
+
+ /**
+ * Generates a ManualTimeSuggestion using the current elapsed realtime clock for the
+ * reference time.
+ */
+ ManualTimeSuggestion generateManualTimeSuggestion(long timeMillis) {
+ TimestampedValue<Long> utcTime =
+ new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis);
+ return new ManualTimeSuggestion(utcTime);
+ }
+
+ /**
+ * Generates a PhoneTimeSuggestion using the current elapsed realtime clock for the
+ * reference time.
+ */
+ PhoneTimeSuggestion generatePhoneTimeSuggestion(int phoneId, Long timeMillis) {
+ TimestampedValue<Long> time = null;
+ if (timeMillis != null) {
+ time = new TimestampedValue<>(peekElapsedRealtimeMillis(), timeMillis);
}
+ return createPhoneTimeSuggestion(phoneId, time);
}
}
@@ -645,12 +748,6 @@ public class SimpleTimeDetectorStrategyTest {
.build();
}
- private ManualTimeSuggestion createManualTimeSuggestion(long timeMillis) {
- TimestampedValue<Long> utcTime =
- new TimestampedValue<>(mScript.peekElapsedRealtimeMillis(), timeMillis);
- return new ManualTimeSuggestion(utcTime);
- }
-
private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
int second) {
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
index 270436d65614..cb49fefb8047 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
@@ -50,7 +50,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
-import java.util.Objects;
/**
* White-box unit tests for {@link TimeZoneDetectorStrategy}.
@@ -445,8 +444,7 @@ public class TimeZoneDetectorStrategyTest {
static class FakeTimeZoneDetectorStrategyCallback implements TimeZoneDetectorStrategy.Callback {
private boolean mAutoTimeZoneDetectionEnabled;
- private TestState<TimeZoneChange> mTimeZoneChanges = new TestState<>();
- private String mTimeZoneId;
+ private TestState<String> mTimeZoneId = new TestState<>();
@Override
public boolean isAutoTimeZoneDetectionEnabled() {
@@ -460,13 +458,12 @@ public class TimeZoneDetectorStrategyTest {
@Override
public String getDeviceTimeZone() {
- return mTimeZoneId;
+ return mTimeZoneId.getLatest();
}
@Override
- public void setDeviceTimeZone(String zoneId, boolean withNetworkBroadcast) {
- mTimeZoneId = zoneId;
- mTimeZoneChanges.set(new TimeZoneChange(zoneId, withNetworkBroadcast));
+ public void setDeviceTimeZone(String zoneId) {
+ mTimeZoneId.set(zoneId);
}
void initializeAutoTimeZoneDetection(boolean enabled) {
@@ -474,7 +471,7 @@ public class TimeZoneDetectorStrategyTest {
}
void initializeTimeZone(String zoneId) {
- mTimeZoneId = zoneId;
+ mTimeZoneId.init(zoneId);
}
void setAutoTimeZoneDetectionEnabled(boolean enabled) {
@@ -482,46 +479,17 @@ public class TimeZoneDetectorStrategyTest {
}
void assertTimeZoneNotSet() {
- mTimeZoneChanges.assertHasNotBeenSet();
+ mTimeZoneId.assertHasNotBeenSet();
}
- void assertTimeZoneSet(String timeZoneId, boolean withNetworkBroadcast) {
- mTimeZoneChanges.assertHasBeenSet();
- mTimeZoneChanges.assertChangeCount(1);
- TimeZoneChange expectedChange = new TimeZoneChange(timeZoneId, withNetworkBroadcast);
- mTimeZoneChanges.assertLatestEquals(expectedChange);
+ void assertTimeZoneSet(String timeZoneId) {
+ mTimeZoneId.assertHasBeenSet();
+ mTimeZoneId.assertChangeCount(1);
+ mTimeZoneId.assertLatestEquals(timeZoneId);
}
void commitAllChanges() {
- mTimeZoneChanges.commitLatest();
- }
- }
-
- private static class TimeZoneChange {
- private final String mTimeZoneId;
- private final boolean mWithNetworkBroadcast;
-
- private TimeZoneChange(String timeZoneId, boolean withNetworkBroadcast) {
- mTimeZoneId = timeZoneId;
- mWithNetworkBroadcast = withNetworkBroadcast;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- TimeZoneChange that = (TimeZoneChange) o;
- return mWithNetworkBroadcast == that.mWithNetworkBroadcast
- && mTimeZoneId.equals(that.mTimeZoneId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mTimeZoneId, mWithNetworkBroadcast);
+ mTimeZoneId.commitLatest();
}
}
@@ -614,21 +582,13 @@ public class TimeZoneDetectorStrategyTest {
}
Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion suggestion) {
- // Phone suggestions should cause a TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE
- // broadcast.
- boolean withNetworkBroadcast = true;
- mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(
- suggestion.getZoneId(), withNetworkBroadcast);
+ mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId());
mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
return this;
}
Script verifyTimeZoneSetAndReset(ManualTimeZoneSuggestion suggestion) {
- // Manual suggestions should not cause a TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE
- // broadcast.
- boolean withNetworkBroadcast = false;
- mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(
- suggestion.getZoneId(), withNetworkBroadcast);
+ mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId());
mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
return this;
}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 92198fa8cb0c..f608babd062c 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -20,6 +20,7 @@ android_test {
"androidx.test.rules", "hamcrest-library",
"mockito-target-inline-minus-junit4",
"platform-test-annotations",
+ "platformprotosnano",
"hamcrest-library",
"testables",
"truth-prebuilt",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java
new file mode 100644
index 000000000000..f685c68f4160
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.server.notification;
+
+import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.service.notification.nano.NotificationRemoteViewsProto;
+import android.test.MoreAsserts;
+import android.util.proto.ProtoOutputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+public class PulledStatsTest extends UiServiceTestCase {
+
+ @Test
+ public void testPulledStats_Empty() {
+ PulledStats stats = new PulledStats(0L);
+ assertEquals(0L, stats.endTimeMs());
+ }
+
+ @Test
+ public void testPulledStats_UnknownReport() {
+ PulledStats stats = new PulledStats(0L);
+ stats.addUndecoratedPackage("foo", 456);
+ stats.addUndecoratedPackage("bar", 123);
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ final ProtoOutputStream proto = new ProtoOutputStream(bytes);
+ stats.writeToProto(1023123, proto); // a very large number
+ proto.flush();
+
+ // expect empty output in response to an unrecognized request
+ assertEquals(0L, bytes.size());
+ }
+
+ @Test
+ public void testPulledStats_RemoteViewReportPackages() {
+ List<String> expectedPkgs = new ArrayList<>(2);
+ expectedPkgs.add("foo");
+ expectedPkgs.add("bar");
+
+ PulledStats stats = new PulledStats(0L);
+ for(String pkg: expectedPkgs) {
+ stats.addUndecoratedPackage(pkg, 111);
+ }
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ final ProtoOutputStream protoStream = new ProtoOutputStream(bytes);
+ stats.writeToProto(REPORT_REMOTE_VIEWS, protoStream);
+ protoStream.flush();
+
+ try {
+ NotificationRemoteViewsProto proto =
+ NotificationRemoteViewsProto.parseFrom(bytes.toByteArray());
+ List<String> actualPkgs = new ArrayList<>(2);
+ for(int i = 0 ; i < proto.packageRemoteViewInfo.length; i++) {
+ actualPkgs.add(proto.packageRemoteViewInfo[i].packageName);
+ }
+ assertEquals(2, actualPkgs.size());
+ assertTrue("missing packages", actualPkgs.containsAll(expectedPkgs));
+ assertTrue("unexpected packages", expectedPkgs.containsAll(actualPkgs));
+ } catch (InvalidProtocolBufferNanoException e) {
+ e.printStackTrace();
+ fail("writeToProto generated unparsable output");
+ }
+
+ }
+ @Test
+ public void testPulledStats_RemoteViewReportEndTime() {
+ List<String> expectedPkgs = new ArrayList<>(2);
+ expectedPkgs.add("foo");
+ expectedPkgs.add("bar");
+
+ PulledStats stats = new PulledStats(0L);
+ long t = 111;
+ for(String pkg: expectedPkgs) {
+ t += 1000;
+ stats.addUndecoratedPackage(pkg, t);
+ }
+ assertEquals(t, stats.endTimeMs());
+ }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index de2bba275171..592864185a3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -144,7 +144,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
// Put a finishing standard activity which will be reparented.
final ActivityStack stack = createFullscreenStackWithSimpleActivityAt(display);
- stack.topRunningActivityLocked().makeFinishingLocked();
+ stack.topRunningActivity().makeFinishingLocked();
clearInvocations(homeStack);
display.remove();
@@ -301,24 +301,18 @@ public class ActivityDisplayTests extends ActivityTestsBase {
doAnswer(invocation -> {
display.positionStackAtTop(stack3, false);
return true;
- }).when(mSupervisor).removeTaskByIdLocked(eq(task4.mTaskId), anyBoolean(), anyBoolean(),
- any());
+ }).when(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
// Removing stacks from the display while removing stacks.
doAnswer(invocation -> {
display.removeStack(stack2);
return true;
- }).when(mSupervisor).removeTaskByIdLocked(eq(task2.mTaskId), anyBoolean(), anyBoolean(),
- any());
+ }).when(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
runnable.run();
- verify(mSupervisor).removeTaskByIdLocked(eq(task4.mTaskId), anyBoolean(), anyBoolean(),
- any());
- verify(mSupervisor).removeTaskByIdLocked(eq(task3.mTaskId), anyBoolean(), anyBoolean(),
- any());
- verify(mSupervisor).removeTaskByIdLocked(eq(task2.mTaskId), anyBoolean(), anyBoolean(),
- any());
- verify(mSupervisor).removeTaskByIdLocked(eq(task1.mTaskId), anyBoolean(), anyBoolean(),
- any());
+ verify(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
+ verify(mSupervisor).removeTask(eq(task3), anyBoolean(), anyBoolean(), any());
+ verify(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
+ verify(mSupervisor).removeTask(eq(task1), anyBoolean(), anyBoolean(), any());
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 7166829e01da..7a449b37224a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -107,7 +107,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Before
public void setUp() throws Exception {
mStack = new StackBuilder(mRootActivityContainer).build();
- mTask = mStack.getChildAt(0);
+ mTask = mStack.getBottomMostTask();
mActivity = mTask.getTopNonFinishingActivity();
doReturn(false).when(mService).isBooting();
@@ -203,7 +203,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
// An activity can be launched on default display.
assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
// An activity cannot be launched on a non-existent display.
- assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
+ assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
}
@Test
@@ -640,7 +640,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
// stacks. Then when mActivity is finishing, its stack will be invisible (no running
// activities in the stack) that is the key condition to verify.
final ActivityStack stack2 = new StackBuilder(mRootActivityContainer).build();
- stack2.moveToBack("test", stack2.getChildAt(0));
+ stack2.moveToBack("test", stack2.getBottomMostTask());
assertTrue(mStack.isTopStackOnDisplay());
@@ -948,9 +948,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
// Empty the home stack.
final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
- for (Task t : homeStack.getAllTasks()) {
- homeStack.removeChild(t, "test");
- }
+ homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); });
mActivity.finishing = true;
doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
spyOn(mStack);
@@ -974,9 +972,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
// Empty the home stack.
final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
- for (Task t : homeStack.getAllTasks()) {
- homeStack.removeChild(t, "test");
- }
+ homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); });
mActivity.finishing = true;
spyOn(mStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 7806d40c3c0d..47f454e499af 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -286,12 +286,12 @@ public class ActivityStackTests extends ActivityTestsBase {
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Do not move display to back because there is still another stack.
- stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
+ stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask());
verify(stack2).positionChildAtBottom(any(), eq(false) /* includingParents */);
// Also move display to back because there is only one stack left.
display.removeStack(stack1);
- stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
+ stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask());
verify(stack2).positionChildAtBottom(any(), eq(true) /* includingParents */);
}
@@ -545,7 +545,7 @@ public class ActivityStackTests extends ActivityTestsBase {
public void testShouldBeVisible_Finishing() {
final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+ ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
topRunningHomeActivity = new ActivityBuilder(mService)
.setStack(homeStack)
@@ -563,7 +563,7 @@ public class ActivityStackTests extends ActivityTestsBase {
topRunningHomeActivity.finishing = true;
final ActivityRecord topRunningTranslucentActivity =
- translucentStack.topRunningActivityLocked();
+ translucentStack.topRunningActivity();
topRunningTranslucentActivity.finishing = true;
// Home stack should be visible even there are no running activities.
@@ -883,7 +883,7 @@ public class ActivityStackTests extends ActivityTestsBase {
// removed from the task. Since the overlay activity should be removed as well, the task
// should be empty.
assertFalse(mTask.hasChild());
- assertThat(mStack.getAllTasks()).isEmpty();
+ assertFalse(mStack.hasChild());
}
@Test
@@ -905,7 +905,7 @@ public class ActivityStackTests extends ActivityTestsBase {
mStack.handleAppDiedLocked(secondActivity.app);
assertFalse(mTask.hasChild());
- assertThat(mStack.getAllTasks()).isEmpty();
+ assertFalse(mStack.hasChild());
}
@Test
@@ -919,7 +919,7 @@ public class ActivityStackTests extends ActivityTestsBase {
mStack.handleAppDiedLocked(activity.app);
assertEquals(1, mTask.getChildCount());
- assertEquals(1, mStack.getAllTasks().size());
+ assertEquals(1, mStack.getChildCount());
}
@Test
@@ -933,7 +933,7 @@ public class ActivityStackTests extends ActivityTestsBase {
mStack.handleAppDiedLocked(activity.app);
assertFalse(mTask.hasChild());
- assertThat(mStack.getAllTasks()).isEmpty();
+ assertFalse(mStack.hasChild());
}
@Test
@@ -947,7 +947,7 @@ public class ActivityStackTests extends ActivityTestsBase {
mStack.handleAppDiedLocked(activity.app);
assertEquals(1, mTask.getChildCount());
- assertEquals(1, mStack.getAllTasks().size());
+ assertEquals(1, mStack.getChildCount());
}
@Test
@@ -961,7 +961,7 @@ public class ActivityStackTests extends ActivityTestsBase {
mStack.handleAppDiedLocked(activity.app);
assertFalse(mTask.hasChild());
- assertThat(mStack.getAllTasks()).isEmpty();
+ assertFalse(mStack.hasChild());
}
@Test
@@ -982,7 +982,7 @@ public class ActivityStackTests extends ActivityTestsBase {
final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- ActivityRecord activity = homeStack.topRunningActivityLocked();
+ ActivityRecord activity = homeStack.topRunningActivity();
if (activity == null) {
activity = new ActivityBuilder(mService)
.setStack(homeStack)
@@ -1020,7 +1020,7 @@ public class ActivityStackTests extends ActivityTestsBase {
}
private ActivityRecord finishTopActivity(ActivityStack stack) {
- final ActivityRecord activity = stack.topRunningActivityLocked();
+ final ActivityRecord activity = stack.topRunningActivity();
assertNotNull(activity);
activity.setState(STOPPED, "finishTopActivity");
activity.makeFinishingLocked();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index d5fdf9871f97..018c10a6dfba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -54,6 +54,7 @@ import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -519,7 +520,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
private void assertNoTasks(ActivityDisplay display) {
for (int i = display.getStackCount() - 1; i >= 0; --i) {
final ActivityStack stack = display.getStackAt(i);
- assertThat(stack.getAllTasks()).isEmpty();
+ assertFalse(stack.hasChild());
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index dae1052286f7..07b7cf482015 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -59,7 +59,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
@Test
public void testActivityFinish() {
final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
- final ActivityRecord activity = stack.getChildAt(0).getTopNonFinishingActivity();
+ final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
assertTrue("Activity must be finished", mService.finishActivity(activity.appToken,
0 /* resultCode */, null /* resultData */,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
@@ -75,7 +75,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
removeGlobalMinSizeRestriction();
final ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.topTask();
+ final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
Rect newBounds = new Rect(10, 10, 100, 100);
t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 0382bf829acf..6f1e6df52ad1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -31,7 +31,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.TRANSIT_UNSET;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -303,8 +302,8 @@ public class AppWindowTokenTests extends WindowTestsBase {
"closingWindow");
closingWindow.mAnimatingExit = true;
closingWindow.mRemoveOnExit = true;
- closingWindow.mActivityRecord.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
- true /* performLayout */, false /* isVoiceInteraction */);
+ closingWindow.mActivityRecord.commitVisibility(
+ false /* visible */, true /* performLayout */);
// We pretended that we were running an exit animation, but that should have been cleared up
// by changing visibility of ActivityRecord
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 716e777ab779..14c09eb99c80 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -244,7 +244,6 @@ public class DisplayContentTests extends WindowTestsBase {
// Add stack with activity.
final ActivityStack stack = createTaskStackOnDisplay(dc);
assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
- assertEquals(dc, stack.getParent().getParent());
assertEquals(dc, stack.getDisplayContent());
final Task task = createTaskInStack(stack, 0 /* userId */);
@@ -256,7 +255,6 @@ public class DisplayContentTests extends WindowTestsBase {
// Move stack to first display.
mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
- assertEquals(mDisplayContent, stack.getParent().getParent());
assertEquals(mDisplayContent, stack.getDisplayContent());
assertEquals(mDisplayContent, task.getDisplayContent());
assertEquals(mDisplayContent, activity.getDisplayContent());
@@ -744,7 +742,7 @@ public class DisplayContentTests extends WindowTestsBase {
final ActivityStack stack =
new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
.setDisplay(dc).build();
- final ActivityRecord activity = stack.topTask().getTopNonFinishingActivity();
+ final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
activity.setRequestedOrientation(newOrientation);
@@ -766,7 +764,7 @@ public class DisplayContentTests extends WindowTestsBase {
final ActivityStack stack =
new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
.setDisplay(dc).build();
- final ActivityRecord activity = stack.topTask().getTopNonFinishingActivity();
+ final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
activity.setRequestedOrientation(newOrientation);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index 6ced8160b426..0cc2626d9f89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -106,6 +106,7 @@ public class LockTaskControllerTest {
@Mock private ActivityStackSupervisor mSupervisor;
@Mock private RootActivityContainer mRootActivityContainer;
+ @Mock private RootWindowContainer mRootWindowContainer;
@Mock private IDevicePolicyManager mDevicePolicyManager;
@Mock private IStatusBarService mStatusBarService;
@Mock private WindowManagerService mWindowManager;
@@ -134,6 +135,7 @@ public class LockTaskControllerTest {
mSupervisor.mRecentTasks = mRecentTasks;
mSupervisor.mRootActivityContainer = mRootActivityContainer;
+ mRootActivityContainer.mRootWindowContainer = mRootWindowContainer;
mLockTaskController = new LockTaskController(mContext, mSupervisor,
new ImmediatelyExecuteHandler());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 9f97c488cf4d..b1cd93168c17 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1282,10 +1282,10 @@ public class RecentTasksTest extends ActivityTestsBase {
@Override
void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType,
- int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays,
+ int ignoreWindowingMode, RootActivityContainer root,
int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
mLastAllowed = allowed;
- super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays,
+ super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, root,
callingUid, allowed, crossUser, profileIds);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 4abab63cba81..8fbb16c80737 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -120,7 +120,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
final ActivityStack homeStack =
defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
defaultDisplay.positionStackAtTop(homeStack, false /* includingParents */);
- ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+ ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
topRunningHomeActivity = new ActivityBuilder(mService)
.setStack(homeStack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 59c7c021d71e..5417adec5e1e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -147,7 +147,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
}
private static void ensureStackPlacement(ActivityStack stack, ActivityRecord... activities) {
- final Task task = stack.getAllTasks().get(0);
+ final Task task = stack.getBottomMostTask();
final ArrayList<ActivityRecord> stackActivities = new ArrayList<>();
task.forAllActivities((Consumer<ActivityRecord>) stackActivities::add, false);
@@ -320,7 +320,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
.setOnTop(true)
.build();
- final Task task = primaryStack.topTask();
+ final Task task = primaryStack.getTopMostTask();
// Resize dock stack.
mService.resizeDockedStack(stackSize, taskSize, null, null, null);
@@ -340,7 +340,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final ActivityStack targetStack = new StackBuilder(mRootActivityContainer)
.setOnTop(false)
.build();
- final Task targetTask = targetStack.getChildAt(0);
+ final Task targetTask = targetStack.getBottomMostTask();
// Create Recents on top of the display.
final ActivityStack stack = new StackBuilder(mRootActivityContainer).setActivityType(
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 5c9ccae8b7d1..66f4d2a98dee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -82,8 +82,8 @@ public class RunningTasksTest extends ActivityTestsBase {
final int numFetchTasks = 5;
ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
- displays, -1 /* callingUid */, true /* allowed */, true /*crossUser */,
- PROFILE_IDS);
+ mRootActivityContainer, -1 /* callingUid */, true /* allowed */,
+ true /*crossUser */, PROFILE_IDS);
assertThat(tasks).hasSize(numFetchTasks);
for (int i = 0; i < numFetchTasks; i++) {
assertEquals(numTasks - i - 1, tasks.get(i).id);
@@ -93,8 +93,8 @@ public class RunningTasksTest extends ActivityTestsBase {
// and does not crash
tasks.clear();
mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
- displays, -1 /* callingUid */, true /* allowed */, true /* crossUser */,
- PROFILE_IDS);
+ mRootActivityContainer, -1 /* callingUid */, true /* allowed */,
+ true /* crossUser */, PROFILE_IDS);
assertThat(tasks).hasSize(numTasks);
for (int i = 0; i < numTasks; i++) {
assertEquals(numTasks - i - 1, tasks.get(i).id);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 212931b76b88..46f95ed16ec6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
@@ -27,7 +26,7 @@ import static android.view.Surface.ROTATION_90;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
@@ -36,7 +35,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -54,7 +52,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
-import java.util.concurrent.TimeUnit;
/**
* Tests for Size Compatibility mode.
@@ -72,7 +69,7 @@ public class SizeCompatTests extends ActivityTestsBase {
private void setUpApp(ActivityDisplay display) {
mStack = new StackBuilder(mRootActivityContainer).setDisplay(display).build();
- mTask = mStack.getChildAt(0);
+ mTask = mStack.getBottomMostTask();
mActivity = mTask.getTopNonFinishingActivity();
}
@@ -265,7 +262,8 @@ public class SizeCompatTests extends ActivityTestsBase {
setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
- assertTrue(mActivity.inSizeCompatMode());
+ // The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted.
+ assertFalse(mActivity.inSizeCompatMode());
final Rect originalBounds = new Rect(mActivity.getBounds());
final Rect originalAppBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds());
@@ -317,37 +315,35 @@ public class SizeCompatTests extends ActivityTestsBase {
@Test
public void testResetNonVisibleActivity() {
setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
final ActivityDisplay display = mStack.getDisplay();
- spyOn(display);
+ // Resize the display so the activity is in size compatibility mode.
+ resizeDisplay(display, 900, 1800);
- prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
mActivity.setState(STOPPED, "testSizeCompatMode");
mActivity.mVisibleRequested = false;
mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- // Make the parent bounds to be different so the activity is in size compatibility mode.
- mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200));
// Simulate the display changes orientation.
- when(display.getLastOverrideConfigurationChanges()).thenReturn(
- ActivityInfo.CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION
- | ActivityInfo.CONFIG_WINDOW_CONFIGURATION);
- mActivity.onConfigurationChanged(mTask.getConfiguration());
- when(display.getLastOverrideConfigurationChanges()).thenCallRealMethod();
- // The override configuration should not change so it is still in size compatibility mode.
+ final Configuration c = new Configuration();
+ display.getDisplayRotation().setRotation(ROTATION_90);
+ display.computeScreenConfiguration(c);
+ display.onRequestedOverrideConfigurationChanged(c);
+ // Size compatibility mode is able to handle orientation change so the process shouldn't be
+ // restarted and the override configuration won't be cleared.
+ verify(mActivity, never()).restartProcessIfVisible();
assertTrue(mActivity.inSizeCompatMode());
// Change display density
- final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
- displayContent.mBaseDisplayDensity = (int) (0.7f * displayContent.mBaseDisplayDensity);
- final Configuration c = new Configuration();
- displayContent.computeScreenConfiguration(c);
+ display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity);
+ display.computeScreenConfiguration(c);
mService.mAmInternal = mock(ActivityManagerInternal.class);
- mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
+ display.onRequestedOverrideConfigurationChanged(c);
// The override configuration should be reset and the activity's process will be killed.
assertFalse(mActivity.inSizeCompatMode());
verify(mActivity).restartProcessIfVisible();
- mLockRule.runWithScissors(mService.mH, () -> { }, TimeUnit.SECONDS.toMillis(3));
+ waitHandlerIdle(mService.mH);
verify(mService.mAmInternal).killProcess(
eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
}
@@ -362,7 +358,6 @@ public class SizeCompatTests extends ActivityTestsBase {
ActivityRecord activity = mActivity;
activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
- ensureActivityConfiguration();
assertFalse(mActivity.inSizeCompatMode());
final ArrayList<IBinder> compatTokens = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index d3b68e02cbf8..a172b656be0c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -287,6 +287,10 @@ public class SystemServicesTestRule implements TestRule {
// Mock root, some default display, and home stack.
spyOn(mWmService.mRoot);
final ActivityDisplay display = mAtmService.mRootActivityContainer.getDefaultDisplay();
+ // Set default display to be in fullscreen mode. Devices with PC feature may start their
+ // default display in freeform mode but some of tests in WmTests have implicit assumption on
+ // that the default display is in fullscreen mode.
+ display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(display);
spyOn(display.mDisplayContent);
final ActivityStack homeStack = display.getStack(
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 599edb1465d0..39e788530eae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -235,7 +235,7 @@ public class TaskRecordTests extends ActivityTestsBase {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- Task task = stack.getChildAt(0);
+ Task task = stack.getBottomMostTask();
task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
DisplayInfo info = new DisplayInfo();
display.mDisplay.getDisplayInfo(info);
@@ -276,7 +276,7 @@ public class TaskRecordTests extends ActivityTestsBase {
ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- Task task = stack.getChildAt(0);
+ Task task = stack.getBottomMostTask();
ActivityRecord root = task.getTopNonFinishingActivity();
assertEquals(fullScreenBounds, task.getBounds());
@@ -337,7 +337,7 @@ public class TaskRecordTests extends ActivityTestsBase {
display.getRequestedOverrideConfiguration());
ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- Task task = stack.getChildAt(0);
+ Task task = stack.getBottomMostTask();
ActivityRecord root = task.getTopNonFinishingActivity();
final WindowContainer parentWindowContainer =
@@ -803,7 +803,7 @@ public class TaskRecordTests extends ActivityTestsBase {
private Task getTestTask() {
final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
- return stack.getChildAt(0);
+ return stack.getBottomMostTask();
}
private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 6ebaf29d2977..7174e5c8bb48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -18,7 +18,6 @@ package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.TRANSIT_UNSET;
import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_APP_THEME;
import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL;
@@ -50,8 +49,8 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
public void testGetClosingApps_closing() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
- closingWindow.mActivityRecord.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
- true /* performLayout */, false /* isVoiceInteraction */);
+ closingWindow.mActivityRecord.commitVisibility(
+ false /* visible */, true /* performLayout */);
final ArraySet<ActivityRecord> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mActivityRecord);
final ArraySet<Task> closingTasks = new ArraySet<>();
@@ -66,10 +65,10 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
"closingWindow");
final WindowState openingWindow = createAppWindow(closingWindow.getTask(),
FIRST_APPLICATION_WINDOW, "openingWindow");
- closingWindow.mActivityRecord.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
- true /* performLayout */, false /* isVoiceInteraction */);
- openingWindow.mActivityRecord.commitVisibility(null, true /* visible */, TRANSIT_UNSET,
- true /* performLayout */, false /* isVoiceInteraction */);
+ closingWindow.mActivityRecord.commitVisibility(
+ false /* visible */, true /* performLayout */);
+ openingWindow.mActivityRecord.commitVisibility(
+ true /* visible */, true /* performLayout */);
final ArraySet<ActivityRecord> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mActivityRecord);
final ArraySet<Task> closingTasks = new ArraySet<>();
@@ -81,8 +80,8 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
public void testGetClosingApps_skipClosingAppsSnapshotTasks() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
- closingWindow.mActivityRecord.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
- true /* performLayout */, false /* isVoiceInteraction */);
+ closingWindow.mActivityRecord.commitVisibility(
+ false /* visible */, true /* performLayout */);
final ArraySet<ActivityRecord> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mActivityRecord);
final ArraySet<Task> closingTasks = new ArraySet<>();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 1996dd4f6545..ef9a73b794f7 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -229,8 +229,8 @@ public class UsageStatsDatabase {
}
try {
- IntervalStats stats = new IntervalStats();
for (int i = start; i < fileCount - 1; i++) {
+ final IntervalStats stats = new IntervalStats();
readLocked(files.valueAt(i), stats);
if (!checkinAction.checkin(stats)) {
return false;
@@ -848,10 +848,10 @@ public class UsageStatsDatabase {
}
}
- final IntervalStats stats = new IntervalStats();
final ArrayList<T> results = new ArrayList<>();
for (int i = startIndex; i <= endIndex; i++) {
final AtomicFile f = intervalStats.valueAt(i);
+ final IntervalStats stats = new IntervalStats();
if (DEBUG) {
Slog.d(TAG, "Reading stat file " + f.getBaseFile().getAbsolutePath());
@@ -1061,6 +1061,11 @@ public class UsageStatsDatabase {
}
}
+ /**
+ * Note: the data read from the given file will add to the IntervalStats object passed into this
+ * method. It is up to the caller to ensure that this is the desired behavior - if not, the
+ * caller should ensure that the data in the reused object is being cleared.
+ */
private void readLocked(AtomicFile file, IntervalStats statsOut)
throws IOException, RuntimeException {
if (mCurrentVersion <= 3) {
@@ -1072,6 +1077,10 @@ public class UsageStatsDatabase {
/**
* Returns {@code true} if any stats were omitted while reading, {@code false} otherwise.
+ * <p/>
+ * Note: the data read from the given file will add to the IntervalStats object passed into this
+ * method. It is up to the caller to ensure that this is the desired behavior - if not, the
+ * caller should ensure that the data in the reused object is being cleared.
*/
private static boolean readLocked(AtomicFile file, IntervalStats statsOut, int version,
PackagesTokenData packagesTokenData) throws IOException, RuntimeException {
@@ -1098,6 +1107,10 @@ public class UsageStatsDatabase {
/**
* Returns {@code true} if any stats were omitted while reading, {@code false} otherwise.
+ * <p/>
+ * Note: the data read from the given file will add to the IntervalStats object passed into this
+ * method. It is up to the caller to ensure that this is the desired behavior - if not, the
+ * caller should ensure that the data in the reused object is being cleared.
*/
private static boolean readLocked(InputStream in, IntervalStats statsOut, int version,
PackagesTokenData packagesTokenData) throws RuntimeException {
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index f89bbc7d179a..73faf9f5f9f4 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -463,9 +463,7 @@ public class Annotation {
DataFailCause.UNKNOWN,
DataFailCause.RADIO_NOT_AVAILABLE,
DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
- DataFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN,
DataFailCause.LOST_CONNECTION,
- DataFailCause.RESET_BY_FRAMEWORK
})
@Retention(RetentionPolicy.SOURCE)
public @interface DataFailureCause {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1b86c09ce86c..001888c6c117 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1052,9 +1052,6 @@ public class CarrierConfigManager {
*
* When {@code false}, the old behavior is used, where the toggle in accessibility settings is
* used to set the IMS stack's RTT enabled state.
- *
- * @deprecated -- this flag no longer does anything. Remove once the new behavior is verified.
- *
* @hide
*/
public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
@@ -2092,12 +2089,6 @@ public class CarrierConfigManager {
"allow_metered_network_for_cert_download_bool";
/**
- * Carrier specified WiFi networks.
- * @hide
- */
- public static final String KEY_CARRIER_WIFI_STRING_ARRAY = "carrier_wifi_string_array";
-
- /**
* Time delay (in ms) after which we show the notification to switch the preferred
* network.
* @hide
@@ -2326,7 +2317,7 @@ public class CarrierConfigManager {
* Reference: 3GPP TS 38.215
*
* 4 threshold integers must be within the boundaries [-20 dB, -3 dB], and the levels are:
- * "NONE: [-23, threshold1]"
+ * "NONE: [-20, threshold1]"
* "POOR: (threshold1, threshold2]"
* "MODERATE: (threshold2, threshold3]"
* "GOOD: (threshold3, threshold4]"
@@ -2360,15 +2351,26 @@ public class CarrierConfigManager {
/**
* Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
* SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
- * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
- * parameter whose value is smallest is used to indicate the signal bar.
+ * ratio (SSSINR) for the number of 5G NR signal bars and signal criteria reporting enabling.
+ *
+ * <p> If a measure is not set, signal criteria reporting from modem will not be triggered and
+ * not be used for calculating signal level. If multiple measures are set bit, the parameter
+ * whose value is smallest is used to indicate the signal level.
*
* SSRSRP = 1 << 0,
* SSRSRQ = 1 << 1,
* SSSINR = 1 << 2,
*
+ * The value of this key must be bitwise OR of {@link CellSignalStrengthNr#USE_SSRSRP},
+ * {@link CellSignalStrengthNr#USE_SSRSRQ}, {@link CellSignalStrengthNr#USE_SSSINR}.
+ *
+ * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+ * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
+ *
* Reference: 3GPP TS 38.215,
* 3GPP TS 38.133 10.1.16.1
+ *
+ * @hide
*/
public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT =
"parameters_use_for_5g_nr_signal_bar_int";
@@ -3035,7 +3037,6 @@ public class CarrierConfigManager {
/**
* Location information during (and after) an emergency call is only provided over control
* plane signaling from the network.
- * @hide
*/
public static final int SUPL_EMERGENCY_MODE_TYPE_CP_ONLY = 0;
@@ -3043,7 +3044,6 @@ public class CarrierConfigManager {
* Location information during (and after) an emergency call is provided over the data
* plane and serviced by the framework GNSS service, but if it fails, the carrier also
* supports control plane backup signaling.
- * @hide
*/
public static final int SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK = 1;
@@ -3051,7 +3051,6 @@ public class CarrierConfigManager {
* Location information during (and after) an emergency call is provided over the data plane
* and serviced by the framework GNSS service only. There is no backup signalling over the
* control plane if it fails.
- * @hide
*/
public static final int SUPL_EMERGENCY_MODE_TYPE_DP_ONLY = 2;
@@ -3158,11 +3157,21 @@ public class CarrierConfigManager {
* {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}.
* <p>
* The default value for this configuration is {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}.
- * @hide
*/
public static final String KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT = KEY_PREFIX
+ "es_supl_control_plane_support_int";
+ /**
+ * A list of roaming PLMNs where SUPL ES mode does not support a control-plane mechanism to
+ * get a user's location in the event that data plane SUPL fails or is otherwise
+ * unavailable.
+ * <p>
+ * A string array of PLMNs that do not support a control-plane mechanism for getting a
+ * user's location for SUPL ES.
+ */
+ public static final String KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY =
+ KEY_PREFIX + "es_supl_data_plane_only_roaming_plmn_string_array";
+
private static PersistableBundle getDefaults() {
PersistableBundle defaults = new PersistableBundle();
defaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
@@ -3179,63 +3188,11 @@ public class CarrierConfigManager {
defaults.putString(KEY_NFW_PROXY_APPS_STRING, "");
defaults.putInt(KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
SUPL_EMERGENCY_MODE_TYPE_CP_ONLY);
+ defaults.putStringArray(KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, null);
return defaults;
}
}
- /**
- * Wi-Fi configs used in Carrier Wi-Fi application.
- *
- * @hide
- */
- @SystemApi
- public static final class Wifi {
- /** Prefix of all Wifi.KEY_* constants. */
- public static final String KEY_PREFIX = "wifi.";
-
- /**
- * Whenever any information under wifi namespace is changed, the version should be
- * incremented by 1 so that the device is able to figure out the latest profiles based on
- * the version.
- */
- public static final String KEY_CARRIER_PROFILES_VERSION_INT =
- KEY_PREFIX + "carrier_profiles_version_int";
-
- /**
- * It contains the package name of connection manager that the carrier owns.
- *
- * <P>Once it is installed, the profiles installed by Carrier Wi-Fi Application
- * will be deleted.
- * Once it is uninstalled, Carrier Wi-Fi Application will re-install the latest profiles.
- */
- public static final String KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING =
- KEY_PREFIX + "carrier_connection_manager_package_string";
- /**
- * It is to have the list of wifi networks profiles which contain the information about
- * the wifi-networks to which carrier wants the device to connect.
- */
- public static final String KEY_NETWORK_PROFILES_STRING_ARRAY =
- KEY_PREFIX + "network_profiles_string_array";
-
- /**
- * It is to have the list of Passpoint profiles which contain the information about
- * the Passpoint networks to which carrier wants the device to connect.
- */
- public static final String KEY_PASSPOINT_PROFILES_STRING_ARRAY =
- KEY_PREFIX + "passpoint_profiles_string_array";
-
- private static PersistableBundle getDefaults() {
- PersistableBundle defaults = new PersistableBundle();
- defaults.putInt(KEY_CARRIER_PROFILES_VERSION_INT, -1);
- defaults.putString(KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING, null);
- defaults.putStringArray(KEY_NETWORK_PROFILES_STRING_ARRAY, null);
- defaults.putStringArray(KEY_PASSPOINT_PROFILES_STRING_ARRAY, null);
- return defaults;
- }
-
- private Wifi() {}
- }
-
/**
* An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) network.
* The default values come from 3GPP2 C.R1001 table 8.1-1.
@@ -3537,7 +3494,7 @@ public class CarrierConfigManager {
sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
- sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, true);
+ sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
@@ -3688,7 +3645,6 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_DIGITS_HELPER_TEXT_ON_STK_INPUT_SCREEN_BOOL, true);
- sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
sDefaults.putInt(KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1);
sDefaults.putBoolean(KEY_ALLOW_USSD_REQUESTS_VIA_TELEPHONY_MANAGER_BOOL, true);
@@ -3748,6 +3704,32 @@ public class CarrierConfigManager {
-95, /* SIGNAL_STRENGTH_GOOD */
-85 /* SIGNAL_STRENGTH_GREAT */
});
+ sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
+ // Boundaries: [-140 dB, -44 dB]
+ new int[] {
+ -125, /* SIGNAL_STRENGTH_POOR */
+ -115, /* SIGNAL_STRENGTH_MODERATE */
+ -105, /* SIGNAL_STRENGTH_GOOD */
+ -95, /* SIGNAL_STRENGTH_GREAT */
+ });
+ sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
+ // Boundaries: [-20 dB, -3 dB]
+ new int[] {
+ -14, /* SIGNAL_STRENGTH_POOR */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
+ -10, /* SIGNAL_STRENGTH_GOOD */
+ -8 /* SIGNAL_STRENGTH_GREAT */
+ });
+ sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
+ // Boundaries: [-23 dB, 40 dB]
+ new int[] {
+ -8, /* SIGNAL_STRENGTH_POOR */
+ 0, /* SIGNAL_STRENGTH_MODERATE */
+ 8, /* SIGNAL_STRENGTH_GOOD */
+ 16 /* SIGNAL_STRENGTH_GREAT */
+ });
+ sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
+ CellSignalStrengthNr.USE_SSRSRP);
sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
@@ -3791,7 +3773,6 @@ public class CarrierConfigManager {
/* Default value is 60 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000);
sDefaults.putAll(Gps.getDefaults());
- sDefaults.putAll(Wifi.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {
1 /* Roaming Indicator Off */
@@ -3876,6 +3857,34 @@ public class CarrierConfigManager {
@SystemApi
@TestApi
public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues) {
+ overrideConfig(subscriptionId, overrideValues, false);
+ }
+
+ /**
+ * Overrides the carrier config of the provided subscription ID with the provided values.
+ *
+ * Any further queries to carrier config from any process will return the overridden values
+ * after this method returns. The overrides are effective until the user passes in {@code null}
+ * for {@code overrideValues}. This removes all previous overrides and sets the carrier config
+ * back to production values.
+ *
+ * The overrides is stored persistently and will survive a reboot if {@code persistent} is true.
+ *
+ * May throw an {@link IllegalArgumentException} if {@code overrideValues} contains invalid
+ * values for the specified config keys.
+ *
+ * NOTE: This API is meant for testing purposes only.
+ *
+ * @param subscriptionId The subscription ID for which the override should be done.
+ * @param overrideValues Key-value pairs of the values that are to be overridden. If set to
+ * {@code null}, this will remove all previous overrides and set the
+ * carrier configuration back to production values.
+ * @param persistent Determines whether the override should be persistent.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues,
+ boolean persistent) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
if (loader == null) {
@@ -3883,7 +3892,7 @@ public class CarrierConfigManager {
+ " ICarrierConfigLoader is null");
return;
}
- loader.overrideConfig(subscriptionId, overrideValues);
+ loader.overrideConfig(subscriptionId, overrideValues, persistent);
} catch (RemoteException ex) {
Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": "
+ ex.toString());
diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java
index ce5e3f38e78b..d4d4e1374477 100644
--- a/telephony/java/android/telephony/CbGeoUtils.java
+++ b/telephony/java/android/telephony/CbGeoUtils.java
@@ -18,9 +18,10 @@ package android.telephony;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.os.Build;
import android.text.TextUtils;
+import com.android.internal.telephony.util.TelephonyUtils;
+
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -262,7 +263,7 @@ public class CbGeoUtils {
@Override
public String toString() {
String str = "Polygon: ";
- if (Build.IS_DEBUGGABLE) {
+ if (TelephonyUtils.IS_DEBUGGABLE) {
str += mVertices;
}
return str;
@@ -298,7 +299,7 @@ public class CbGeoUtils {
@Override
public String toString() {
String str = "Circle: ";
- if (Build.IS_DEBUGGABLE) {
+ if (TelephonyUtils.IS_DEBUGGABLE) {
str += mCenter + ", radius = " + mRadiusMeter;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index f9b7f6dbc193..f31fafe36508 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -16,11 +16,15 @@
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -36,13 +40,67 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
private static final String TAG = "CellSignalStrengthNr";
+ // Lifted from Default carrier configs and max range of SSRSRP
+ // Boundaries: [-140 dB, -44 dB]
+ private int[] mSsRsrpThresholds = new int[] {
+ -125, /* SIGNAL_STRENGTH_POOR */
+ -115, /* SIGNAL_STRENGTH_MODERATE */
+ -105, /* SIGNAL_STRENGTH_GOOD */
+ -95, /* SIGNAL_STRENGTH_GREAT */
+ };
+
+ // Lifted from Default carrier configs and max range of SSRSRQ
+ // Boundaries: [-20 dB, -3 dB]
+ private int[] mSsRsrqThresholds = new int[] {
+ -14, /* SIGNAL_STRENGTH_POOR */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
+ -10, /* SIGNAL_STRENGTH_GOOD */
+ -8 /* SIGNAL_STRENGTH_GREAT */
+ };
+
+ // Lifted from Default carrier configs and max range of SSSINR
+ // Boundaries: [-23 dB, 40 dB]
+ private int[] mSsSinrThresholds = new int[] {
+ -8, /* SIGNAL_STRENGTH_POOR */
+ 0, /* SIGNAL_STRENGTH_MODERATE */
+ 8, /* SIGNAL_STRENGTH_GOOD */
+ 16 /* SIGNAL_STRENGTH_GREAT */
+ };
+
+ /**
+ * Indicates SSRSRP is considered for {@link #getLevel()} and reporting from modem.
+ *
+ * @hide
+ */
+ public static final int USE_SSRSRP = 1 << 0;
+ /**
+ * Indicates SSRSRQ is considered for {@link #getLevel()} and reporting from modem.
+ *
+ * @hide
+ */
+ public static final int USE_SSRSRQ = 1 << 1;
/**
- * These threshold values are copied from LTE.
- * TODO: make it configurable via CarrierConfig.
+ * Indicates SSSINR is considered for {@link #getLevel()} and reporting from modem.
+ *
+ * @hide
*/
- private static final int SIGNAL_GREAT_THRESHOLD = -95;
- private static final int SIGNAL_GOOD_THRESHOLD = -105;
- private static final int SIGNAL_MODERATE_THRESHOLD = -115;
+ public static final int USE_SSSINR = 1 << 2;
+
+ /**
+ * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
+ * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
+ * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
+ * parameter whose value is smallest is used to indicate the signal bar.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "USE_" }, value = {
+ USE_SSRSRP,
+ USE_SSRSRQ,
+ USE_SSSINR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SignalLevelAndReportCriteriaSource {}
private int mCsiRsrp;
private int mCsiRsrq;
@@ -52,6 +110,21 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
private int mSsSinr;
private int mLevel;
+ /**
+ * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
+ * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
+ * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
+ * parameter whose value is smallest is used to indicate the signal bar.
+ *
+ * SSRSRP = 1 << 0,
+ * SSRSRQ = 1 << 1,
+ * SSSINR = 1 << 2,
+ *
+ * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+ * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
+ */
+ private int mParametersUseForLevel;
+
/** @hide */
public CellSignalStrengthNr() {
setDefaultValues();
@@ -182,6 +255,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
mSsRsrq = CellInfo.UNAVAILABLE;
mSsSinr = CellInfo.UNAVAILABLE;
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ mParametersUseForLevel = USE_SSRSRP;
}
/** {@inheritDoc} */
@@ -191,20 +265,83 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
return mLevel;
}
+ /**
+ * Checks if the given parameter type is considered to use for {@link #getLevel()}.
+ *
+ * Note: if multiple parameter types are considered, the smaller level for one of the
+ * parameters would be returned by {@link #getLevel()}
+ *
+ * @param parameterType bitwise OR of {@link #USE_SSRSRP}, {@link #USE_SSRSRQ},
+ * {@link #USE_SSSINR}
+ * @return {@code true} if the level is calculated based on the given parameter type;
+ * {@code false} otherwise.
+ *
+ */
+ private boolean isLevelForParameter(@SignalLevelAndReportCriteriaSource int parameterType) {
+ return (parameterType & mParametersUseForLevel) == parameterType;
+ }
+
/** @hide */
@Override
public void updateLevel(PersistableBundle cc, ServiceState ss) {
- if (mSsRsrp == CellInfo.UNAVAILABLE) {
- mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- } else if (mSsRsrp >= SIGNAL_GREAT_THRESHOLD) {
- mLevel = SIGNAL_STRENGTH_GREAT;
- } else if (mSsRsrp >= SIGNAL_GOOD_THRESHOLD) {
- mLevel = SIGNAL_STRENGTH_GOOD;
- } else if (mSsRsrp >= SIGNAL_MODERATE_THRESHOLD) {
- mLevel = SIGNAL_STRENGTH_MODERATE;
+ if (cc == null) {
+ mParametersUseForLevel = USE_SSRSRP;
+ } else {
+ mParametersUseForLevel = cc.getInt(
+ CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, USE_SSRSRP);
+ Rlog.i(TAG, "Using SSRSRP for Level.");
+ mSsRsrpThresholds = cc.getIntArray(
+ CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY);
+ Rlog.i(TAG, "Applying 5G NR SSRSRP Thresholds: " + Arrays.toString(mSsRsrpThresholds));
+ mSsRsrqThresholds = cc.getIntArray(
+ CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY);
+ Rlog.i(TAG, "Applying 5G NR SSRSRQ Thresholds: " + Arrays.toString(mSsRsrqThresholds));
+ mSsSinrThresholds = cc.getIntArray(
+ CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY);
+ Rlog.i(TAG, "Applying 5G NR SSSINR Thresholds: " + Arrays.toString(mSsSinrThresholds));
+ }
+ int ssRsrpLevel = SignalStrength.INVALID;
+ int ssRsrqLevel = SignalStrength.INVALID;
+ int ssSinrLevel = SignalStrength.INVALID;
+ if (isLevelForParameter(USE_SSRSRP)) {
+ ssRsrpLevel = updateLevelWithMeasure(mSsRsrp, mSsRsrpThresholds);
+ Rlog.i(TAG, "Updated 5G NR SSRSRP Level: " + ssRsrpLevel);
+ }
+ if (isLevelForParameter(USE_SSRSRQ)) {
+ ssRsrqLevel = updateLevelWithMeasure(mSsRsrq, mSsRsrqThresholds);
+ Rlog.i(TAG, "Updated 5G NR SSRSRQ Level: " + ssRsrqLevel);
+ }
+ if (isLevelForParameter(USE_SSSINR)) {
+ ssSinrLevel = updateLevelWithMeasure(mSsSinr, mSsSinrThresholds);
+ Rlog.i(TAG, "Updated 5G NR SSSINR Level: " + ssSinrLevel);
+ }
+ // Apply the smaller value among three levels of three measures.
+ mLevel = Math.min(Math.min(ssRsrpLevel, ssRsrqLevel), ssSinrLevel);
+ }
+
+ /**
+ * Update level with corresponding measure and thresholds.
+ *
+ * @param measure corresponding signal measure
+ * @param thresholds corresponding signal thresholds
+ * @return level of the signal strength
+ */
+ private int updateLevelWithMeasure(int measure, int[] thresholds) {
+ int level;
+ if (measure == CellInfo.UNAVAILABLE) {
+ level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ } else if (measure > thresholds[3]) {
+ level = SIGNAL_STRENGTH_GREAT;
+ } else if (measure > thresholds[2]) {
+ level = SIGNAL_STRENGTH_GOOD;
+ } else if (measure > thresholds[1]) {
+ level = SIGNAL_STRENGTH_MODERATE;
+ } else if (measure > thresholds[0]) {
+ level = SIGNAL_STRENGTH_POOR;
} else {
- mLevel = SIGNAL_STRENGTH_POOR;
+ level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
+ return level;
}
/**
@@ -247,6 +384,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
mSsRsrq = s.mSsRsrq;
mSsSinr = s.mSsSinr;
mLevel = s.mLevel;
+ mParametersUseForLevel = s.mParametersUseForLevel;
}
/** @hide */
@@ -290,6 +428,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
.append(" ssRsrq = " + mSsRsrq)
.append(" ssSinr = " + mSsSinr)
.append(" level = " + mLevel)
+ .append(" parametersUseForLevel = " + mParametersUseForLevel)
.append(" }")
.toString();
}
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 7bdf1f57f8b2..e1c4bef0dd65 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -950,14 +950,10 @@ public final class DataFailCause {
public static final int UNKNOWN = 0x10000;
/** Data fail due to radio not unavailable. */
public static final int RADIO_NOT_AVAILABLE = 0x10001; /* no retry */
- /** @hide */
+ /** Data fail due to unacceptable network parameter. */
public static final int UNACCEPTABLE_NETWORK_PARAMETER = 0x10002; /* no retry */
- /** @hide */
- public static final int CONNECTION_TO_DATACONNECTIONAC_BROKEN = 0x10003;
/** Data connection was lost. */
public static final int LOST_CONNECTION = 0x10004;
- /** @hide */
- public static final int RESET_BY_FRAMEWORK = 0x10005;
/**
* Data handover failed.
@@ -1361,10 +1357,7 @@ public final class DataFailCause {
sFailCauseMap.put(RADIO_NOT_AVAILABLE, "RADIO_NOT_AVAILABLE");
sFailCauseMap.put(UNACCEPTABLE_NETWORK_PARAMETER,
"UNACCEPTABLE_NETWORK_PARAMETER");
- sFailCauseMap.put(CONNECTION_TO_DATACONNECTIONAC_BROKEN,
- "CONNECTION_TO_DATACONNECTIONAC_BROKEN");
sFailCauseMap.put(LOST_CONNECTION, "LOST_CONNECTION");
- sFailCauseMap.put(RESET_BY_FRAMEWORK, "RESET_BY_FRAMEWORK");
}
private DataFailCause() {
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index fe273b267e98..95aa101b8b2c 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -34,6 +34,8 @@ import android.os.UserManager;
import android.util.Log;
import android.widget.Toast;
+import com.android.internal.telephony.util.TelephonyUtils;
+
import java.util.List;
/**
@@ -174,7 +176,7 @@ public final class LocationAccessPolicy {
}
Log.e(TAG, errorMsg);
try {
- if (Build.IS_DEBUGGABLE) {
+ if (TelephonyUtils.IS_DEBUGGABLE) {
Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show();
}
} catch (Throwable t) {
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
index 465b6aa79d40..0ceb103d0f27 100644
--- a/telephony/java/android/telephony/NetworkScanRequest.java
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -20,10 +20,10 @@ import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
/**
* Defines a request to peform a network scan.
@@ -221,9 +221,11 @@ public final class NetworkScanRequest implements Parcelable {
private NetworkScanRequest(Parcel in) {
mScanType = in.readInt();
- mSpecifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
- Object.class.getClassLoader(),
- RadioAccessSpecifier.class);
+ Parcelable[] tempSpecifiers = in.readParcelableArray(Object.class.getClassLoader());
+ mSpecifiers = new RadioAccessSpecifier[tempSpecifiers.length];
+ for (int i = 0; i < tempSpecifiers.length; i++) {
+ mSpecifiers[i] = (RadioAccessSpecifier) tempSpecifiers[i];
+ }
mSearchPeriodicity = in.readInt();
mMaxSearchTime = in.readInt();
mIncrementalResults = in.readBoolean();
diff --git a/telephony/java/android/telephony/PhoneNumberRange.java b/telephony/java/android/telephony/PhoneNumberRange.java
index e6f107e28c98..2b199d2df141 100644
--- a/telephony/java/android/telephony/PhoneNumberRange.java
+++ b/telephony/java/android/telephony/PhoneNumberRange.java
@@ -85,18 +85,18 @@ public final class PhoneNumberRange implements Parcelable {
}
private PhoneNumberRange(Parcel in) {
- mCountryCode = in.readStringNoHelper();
- mPrefix = in.readStringNoHelper();
- mLowerBound = in.readStringNoHelper();
- mUpperBound = in.readStringNoHelper();
+ mCountryCode = in.readString();
+ mPrefix = in.readString();
+ mLowerBound = in.readString();
+ mUpperBound = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeStringNoHelper(mCountryCode);
- dest.writeStringNoHelper(mPrefix);
- dest.writeStringNoHelper(mLowerBound);
- dest.writeStringNoHelper(mUpperBound);
+ dest.writeString(mCountryCode);
+ dest.writeString(mPrefix);
+ dest.writeString(mLowerBound);
+ dest.writeString(mUpperBound);
}
@Override
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
new file mode 100644
index 000000000000..f6f6d75c37c6
--- /dev/null
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Defines the threshold value of the signal strength.
+ * @hide
+ */
+public class SignalThresholdInfo implements Parcelable {
+ /**
+ * Received Signal Strength Indication.
+ * Range: -113 dBm and -51 dBm
+ * Used RAN: GERAN, CDMA2000
+ * Reference: 3GPP TS 27.007 section 8.5.
+ */
+ public static final int SIGNAL_RSSI = 1;
+
+ /**
+ * Received Signal Code Power.
+ * Range: -120 dBm to -25 dBm;
+ * Used RAN: UTRAN
+ * Reference: 3GPP TS 25.123, section 9.1.1.1
+ */
+ public static final int SIGNAL_RSCP = 2;
+
+ /**
+ * Reference Signal Received Power.
+ * Range: -140 dBm to -44 dBm;
+ * Used RAN: EUTRAN
+ * Reference: 3GPP TS 36.133 9.1.4
+ */
+ public static final int SIGNAL_RSRP = 3;
+
+ /**
+ * Reference Signal Received Quality
+ * Range: -20 dB to -3 dB;
+ * Used RAN: EUTRAN
+ * Reference: 3GPP TS 36.133 9.1.7
+ */
+ public static final int SIGNAL_RSRQ = 4;
+
+ /**
+ * Reference Signal Signal to Noise Ratio
+ * Range: -20 dB to 30 dB;
+ * Used RAN: EUTRAN
+ */
+ public static final int SIGNAL_RSSNR = 5;
+
+ /**
+ * 5G SS reference signal received power.
+ * Range: -140 dBm to -44 dBm.
+ * Used RAN: NGRAN
+ * Reference: 3GPP TS 38.215.
+ */
+ public static final int SIGNAL_SSRSRP = 6;
+
+ /**
+ * 5G SS reference signal received quality.
+ * Range: -20 dB to -3 dB.
+ * Used RAN: NGRAN
+ * Reference: 3GPP TS 38.215.
+ */
+ public static final int SIGNAL_SSRSRQ = 7;
+
+ /**
+ * 5G SS signal-to-noise and interference ratio.
+ * Range: -23 dB to 40 dB
+ * Used RAN: NGRAN
+ * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+ */
+ public static final int SIGNAL_SSSINR = 8;
+
+ /** @hide */
+ @IntDef(prefix = { "SIGNAL_" }, value = {
+ SIGNAL_RSSI,
+ SIGNAL_RSCP,
+ SIGNAL_RSRP,
+ SIGNAL_RSRQ,
+ SIGNAL_RSSNR,
+ SIGNAL_SSRSRP,
+ SIGNAL_SSRSRQ,
+ SIGNAL_SSSINR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SignalMeasurementType {}
+
+ @SignalMeasurementType
+ private int mSignalMeasurement;
+
+ /**
+ * A hysteresis time in milliseconds to prevent flapping.
+ * A value of 0 disables hysteresis
+ */
+ private int mHysteresisMs;
+
+ /**
+ * An interval in dB defining the required magnitude change between reports.
+ * hysteresisDb must be smaller than the smallest threshold delta.
+ * An interval value of 0 disables hysteresis.
+ */
+ private int mHysteresisDb;
+
+ /**
+ * List of threshold values.
+ * Range and unit must reference specific SignalMeasurementType
+ * The threshold values for which to apply criteria.
+ * A vector size of 0 disables the use of thresholds for reporting.
+ */
+ private int[] mThresholds = null;
+
+ /**
+ * {@code true} means modem must trigger the report based on the criteria;
+ * {@code false} means modem must not trigger the report based on the criteria.
+ */
+ private boolean mIsEnabled = true;
+
+ /**
+ * Indicates the hysteresisMs is disabled.
+ */
+ public static final int HYSTERESIS_MS_DISABLED = 0;
+
+ /**
+ * Indicates the hysteresisDb is disabled.
+ */
+ public static final int HYSTERESIS_DB_DISABLED = 0;
+
+ /**
+ * Constructor
+ *
+ * @param signalMeasurement Signal Measurement Type
+ * @param hysteresisMs hysteresisMs
+ * @param hysteresisDb hysteresisDb
+ * @param thresholds threshold value
+ * @param isEnabled isEnabled
+ */
+ public SignalThresholdInfo(@SignalMeasurementType int signalMeasurement,
+ int hysteresisMs, int hysteresisDb, @NonNull int [] thresholds, boolean isEnabled) {
+ mSignalMeasurement = signalMeasurement;
+ mHysteresisMs = hysteresisMs < 0 ? HYSTERESIS_MS_DISABLED : hysteresisMs;
+ mHysteresisDb = hysteresisDb < 0 ? HYSTERESIS_DB_DISABLED : hysteresisDb;
+ mThresholds = thresholds == null ? null : thresholds.clone();
+ mIsEnabled = isEnabled;
+ }
+
+ public @SignalMeasurementType int getSignalMeasurement() {
+ return mSignalMeasurement;
+ }
+
+ public int getHysteresisMs() {
+ return mHysteresisMs;
+ }
+
+ public int getHysteresisDb() {
+ return mHysteresisDb;
+ }
+
+ public boolean isEnabled() {
+ return mIsEnabled;
+ }
+
+ public int[] getThresholds() {
+ return mThresholds == null ? null : mThresholds.clone();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mSignalMeasurement);
+ out.writeInt(mHysteresisMs);
+ out.writeInt(mHysteresisDb);
+ out.writeIntArray(mThresholds);
+ out.writeBoolean(mIsEnabled);
+ }
+
+ private SignalThresholdInfo(Parcel in) {
+ mSignalMeasurement = in.readInt();
+ mHysteresisMs = in.readInt();
+ mHysteresisDb = in.readInt();
+ mThresholds = in.createIntArray();
+ mIsEnabled = in.readBoolean();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (!(o instanceof SignalThresholdInfo)) {
+ return false;
+ }
+
+ SignalThresholdInfo other = (SignalThresholdInfo) o;
+ return mSignalMeasurement == other.mSignalMeasurement
+ && mHysteresisMs == other.mHysteresisMs
+ && mHysteresisDb == other.mHysteresisDb
+ && Arrays.equals(mThresholds, other.mThresholds)
+ && mIsEnabled == other.mIsEnabled;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mSignalMeasurement, mHysteresisMs, mHysteresisDb, mThresholds, mIsEnabled);
+ }
+
+ public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR =
+ new Parcelable.Creator<SignalThresholdInfo>() {
+ @Override
+ public SignalThresholdInfo createFromParcel(Parcel in) {
+ return new SignalThresholdInfo(in);
+ }
+
+ @Override
+ public SignalThresholdInfo[] newArray(int size) {
+ return new SignalThresholdInfo[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return new StringBuilder("SignalThresholdInfo{")
+ .append("mSignalMeasurement=").append(mSignalMeasurement)
+ .append("mHysteresisMs=").append(mSignalMeasurement)
+ .append("mHysteresisDb=").append(mHysteresisDb)
+ .append("mThresholds=").append(Arrays.toString(mThresholds))
+ .append("mIsEnabled=").append(mIsEnabled)
+ .append("}").toString();
+ }
+}
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ebb517596b6c..b71bd85b0a34 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -30,7 +30,6 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Typeface;
-import android.os.Build;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.Parcelable;
@@ -38,6 +37,8 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
+import com.android.internal.telephony.util.TelephonyUtils;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -665,8 +666,8 @@ public class SubscriptionInfo implements Parcelable {
int id = source.readInt();
String iccId = source.readString();
int simSlotIndex = source.readInt();
- CharSequence displayName = source.readCharSequence();
- CharSequence carrierName = source.readCharSequence();
+ CharSequence displayName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ CharSequence carrierName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
int nameSource = source.readInt();
int iconTint = source.readInt();
String number = source.readString();
@@ -685,8 +686,8 @@ public class SubscriptionInfo implements Parcelable {
int carrierid = source.readInt();
int profileClass = source.readInt();
int subType = source.readInt();
- String[] ehplmns = source.readStringArray();
- String[] hplmns = source.readStringArray();
+ String[] ehplmns = source.createStringArray();
+ String[] hplmns = source.createStringArray();
String groupOwner = source.readString();
UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray(
UiccAccessRule.CREATOR);
@@ -711,8 +712,8 @@ public class SubscriptionInfo implements Parcelable {
dest.writeInt(mId);
dest.writeString(mIccId);
dest.writeInt(mSimSlotIndex);
- dest.writeCharSequence(mDisplayName);
- dest.writeCharSequence(mCarrierName);
+ TextUtils.writeToParcel(mDisplayName, dest, 0);
+ TextUtils.writeToParcel(mCarrierName, dest, 0);
dest.writeInt(mNameSource);
dest.writeInt(mIconTint);
dest.writeString(mNumber);
@@ -748,7 +749,7 @@ public class SubscriptionInfo implements Parcelable {
public static String givePrintableIccid(String iccId) {
String iccIdToPrint = null;
if (iccId != null) {
- if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) {
+ if (iccId.length() > 9 && !TelephonyUtils.IS_DEBUGGABLE) {
iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9));
} else {
iccIdToPrint = iccId;
@@ -764,7 +765,8 @@ public class SubscriptionInfo implements Parcelable {
return "{id=" + mId + " iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
+ " carrierId=" + mCarrierId + " displayName=" + mDisplayName
+ " carrierName=" + mCarrierName + " nameSource=" + mNameSource
- + " iconTint=" + mIconTint + " mNumber=" + Rlog.pii(Build.IS_DEBUGGABLE, mNumber)
+ + " iconTint=" + mIconTint
+ + " mNumber=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber)
+ " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
+ " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
+ " nativeAccessRules " + Arrays.toString(mNativeAccessRules)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index cf705f466e48..a82ae887224c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -48,7 +48,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.Process;
@@ -64,6 +63,7 @@ import android.util.Pair;
import com.android.internal.telephony.ISetOpportunisticDataCallback;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.util.HandlerExecutor;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e3981f6abf34..9f5acb3072cb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -430,14 +430,14 @@ public class TelephonyManager {
int modemCount = 1;
switch (getMultiSimConfiguration()) {
case UNKNOWN:
- ConnectivityManager cm = mContext == null ? null : (ConnectivityManager) mContext
- .getSystemService(Context.CONNECTIVITY_SERVICE);
+ modemCount = MODEM_COUNT_SINGLE_MODEM;
// check for voice and data support, 0 if not supported
- if (!isVoiceCapable() && !isSmsCapable() && cm != null
- && !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) {
- modemCount = MODEM_COUNT_NO_MODEM;
- } else {
- modemCount = MODEM_COUNT_SINGLE_MODEM;
+ if (!isVoiceCapable() && !isSmsCapable() && mContext != null) {
+ ConnectivityManager cm = (ConnectivityManager) mContext
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm != null && !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) {
+ modemCount = MODEM_COUNT_NO_MODEM;
+ }
}
break;
case DSDS:
@@ -716,31 +716,6 @@ public class TelephonyManager {
public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
/**
- * Broadcast intent action indicating that a precise call state
- * (cellular) on the device has changed.
- *
- * <p>
- * The {@link #EXTRA_RINGING_CALL_STATE} extra indicates the ringing call state.
- * The {@link #EXTRA_FOREGROUND_CALL_STATE} extra indicates the foreground call state.
- * The {@link #EXTRA_BACKGROUND_CALL_STATE} extra indicates the background call state.
- *
- * <p class="note">
- * Requires the READ_PRECISE_PHONE_STATE permission.
- *
- * @see #EXTRA_RINGING_CALL_STATE
- * @see #EXTRA_FOREGROUND_CALL_STATE
- * @see #EXTRA_BACKGROUND_CALL_STATE
- *
- * <p class="note">
- * Requires the READ_PRECISE_PHONE_STATE permission.
- * @deprecated use {@link PhoneStateListener#LISTEN_PRECISE_CALL_STATE} instead
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PRECISE_CALL_STATE_CHANGED =
- "android.intent.action.PRECISE_CALL_STATE";
-
- /**
* Broadcast intent action indicating that call disconnect cause has changed.
*
* <p>
@@ -762,78 +737,6 @@ public class TelephonyManager {
/**
* The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
* {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
- * containing the state of the current ringing call.
- *
- * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
- * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
- * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
- * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
- * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
- * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
- * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
- * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_RINGING_CALL_STATE = "ringing_state";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
- * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
- * containing the state of the current foreground call.
- *
- * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
- * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
- * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
- * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
- * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
- * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
- * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
- * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_FOREGROUND_CALL_STATE = "foreground_state";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
- * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
- * containing the state of the current background call.
- *
- * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
- * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
- * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
- * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
- * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
- * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
- * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
- * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_BACKGROUND_CALL_STATE = "background_state";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
- * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
* containing the disconnect cause.
*
* @see DisconnectCause
@@ -862,88 +765,6 @@ public class TelephonyManager {
public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause";
/**
- * Broadcast intent action indicating a data connection has changed,
- * providing precise information about the connection.
- *
- * <p>
- * The {@link #EXTRA_DATA_STATE} extra indicates the connection state.
- * The {@link #EXTRA_DATA_NETWORK_TYPE} extra indicates the connection network type.
- * The {@link #EXTRA_DATA_APN_TYPE} extra indicates the APN type.
- * The {@link #EXTRA_DATA_APN} extra indicates the APN.
- * The {@link #EXTRA_DATA_IFACE_PROPERTIES} extra indicates the connection interface.
- * The {@link #EXTRA_DATA_FAILURE_CAUSE} extra indicates the connection fail cause.
- *
- * <p class="note">
- * Requires the READ_PRECISE_PHONE_STATE permission.
- *
- * @see #EXTRA_DATA_STATE
- * @see #EXTRA_DATA_NETWORK_TYPE
- * @see #EXTRA_DATA_APN_TYPE
- * @see #EXTRA_DATA_APN
- * @see #EXTRA_DATA_IFACE
- * @see #EXTRA_DATA_FAILURE_CAUSE
- * @hide
- *
- * @deprecated If the app is running in the background, it won't be able to receive this
- * broadcast. Apps should use ConnectivityManager {@link #registerNetworkCallback(
- * android.net.NetworkRequest, ConnectivityManager.NetworkCallback)} to listen for network
- * changes.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @Deprecated
- @UnsupportedAppUsage
- public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED =
- "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an integer containing the state of the current data connection.
- *
- * @see TelephonyManager#DATA_UNKNOWN
- * @see TelephonyManager#DATA_DISCONNECTED
- * @see TelephonyManager#DATA_CONNECTING
- * @see TelephonyManager#DATA_CONNECTED
- * @see TelephonyManager#DATA_SUSPENDED
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_STATE = PhoneConstants.STATE_KEY;
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an integer containing the network type.
- *
- * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
- * @see TelephonyManager#NETWORK_TYPE_GPRS
- * @see TelephonyManager#NETWORK_TYPE_EDGE
- * @see TelephonyManager#NETWORK_TYPE_UMTS
- * @see TelephonyManager#NETWORK_TYPE_CDMA
- * @see TelephonyManager#NETWORK_TYPE_EVDO_0
- * @see TelephonyManager#NETWORK_TYPE_EVDO_A
- * @see TelephonyManager#NETWORK_TYPE_1xRTT
- * @see TelephonyManager#NETWORK_TYPE_HSDPA
- * @see TelephonyManager#NETWORK_TYPE_HSUPA
- * @see TelephonyManager#NETWORK_TYPE_HSPA
- * @see TelephonyManager#NETWORK_TYPE_IDEN
- * @see TelephonyManager#NETWORK_TYPE_EVDO_B
- * @see TelephonyManager#NETWORK_TYPE_LTE
- * @see TelephonyManager#NETWORK_TYPE_EHRPD
- * @see TelephonyManager#NETWORK_TYPE_HSPAP
- * @see TelephonyManager#NETWORK_TYPE_NR
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_NETWORK_TYPE = PhoneConstants.DATA_NETWORK_TYPE_KEY;
-
- /**
* The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
* for an String containing the data APN type.
*
@@ -980,18 +801,6 @@ public class TelephonyManager {
public static final String EXTRA_DATA_LINK_PROPERTIES_KEY = PhoneConstants.DATA_LINK_PROPERTIES_KEY;
/**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for the data connection fail cause.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY;
-
- /**
* Broadcast intent action for letting the default dialer to know to show voicemail
* notification.
*
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 30c209b28a4d..96a5a8151065 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -22,7 +22,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Annotation.ApnType;
@@ -31,6 +30,7 @@ import android.telephony.data.ApnSetting.AuthType;
import android.text.TextUtils;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -261,7 +261,7 @@ public final class DataProfile implements Parcelable {
@Override
public String toString() {
return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType
- + "/" + (Build.IS_USER ? "***/***/***" :
+ + "/" + (TelephonyUtils.IS_USER ? "***/***/***" :
(mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
+ mMaxConnectionsTime + "/" + mMaxConnections + "/"
+ mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/"
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 47c468121484..5adc99e11478 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -1173,18 +1173,8 @@ public class ImsCallSession {
public void callSessionMergeComplete(IImsCallSession newSession) {
if (mListener != null) {
if (newSession != null) {
- // Check if the active session is the same session that was
- // active before the merge request was sent.
- ImsCallSession validActiveSession = ImsCallSession.this;
- try {
- if (!Objects.equals(miSession.getCallId(), newSession.getCallId())) {
- // New session created after conference
- validActiveSession = new ImsCallSession(newSession);
- }
- } catch (RemoteException rex) {
- Log.e(TAG, "callSessionMergeComplete: exception for getCallId!");
- }
- mListener.callSessionMergeComplete(validActiveSession);
+ // New session created after conference
+ mListener.callSessionMergeComplete(new ImsCallSession(newSession));
} else {
// Session already exists. Hence no need to pass
mListener.callSessionMergeComplete(null);
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 4fc6a19d1f38..cfc803ca3639 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -17,7 +17,6 @@
package com.android.ims;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.RemoteException;
import android.telephony.Rlog;
@@ -26,6 +25,8 @@ import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsConfigCallback;
+import com.android.internal.telephony.util.HandlerExecutor;
+
import java.util.concurrent.Executor;
/**
diff --git a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
index ee09c1c9c62f..76ebc0f3ac2f 100644
--- a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
+++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
@@ -30,7 +30,7 @@ interface ICarrierConfigLoader {
PersistableBundle getConfigForSubIdWithFeature(int subId, String callingPackage,
String callingFeatureId);
- void overrideConfig(int subId, in PersistableBundle overrides);
+ void overrideConfig(int subId, in PersistableBundle overrides, boolean persistent);
void notifyConfigChangedForSubId(int subId);
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index 6ff27b1152c8..25f03c200610 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.telephony;
+import android.content.Intent;
import android.telephony.TelephonyManager;
import dalvik.annotation.compat.UnsupportedAppUsage;
@@ -25,37 +26,38 @@ import dalvik.annotation.compat.UnsupportedAppUsage;
public class IccCardConstants {
/* The extra data for broadcasting intent INTENT_ICC_STATE_CHANGE */
- public static final String INTENT_KEY_ICC_STATE = "ss";
+ public static final String INTENT_KEY_ICC_STATE = Intent.EXTRA_SIM_STATE;
/* UNKNOWN means the ICC state is unknown */
- public static final String INTENT_VALUE_ICC_UNKNOWN = "UNKNOWN";
+ public static final String INTENT_VALUE_ICC_UNKNOWN = Intent.SIM_STATE_UNKNOWN;
/* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
- public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
+ public static final String INTENT_VALUE_ICC_NOT_READY = Intent.SIM_STATE_NOT_READY;
/* ABSENT means ICC is missing */
- public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
+ public static final String INTENT_VALUE_ICC_ABSENT = Intent.SIM_STATE_ABSENT;
/* PRESENT means ICC is present */
- public static final String INTENT_VALUE_ICC_PRESENT = "PRESENT";
+ public static final String INTENT_VALUE_ICC_PRESENT = Intent.SIM_STATE_PRESENT;
/* CARD_IO_ERROR means for three consecutive times there was SIM IO error */
- static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = "CARD_IO_ERROR";
+ static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = Intent.SIM_STATE_CARD_IO_ERROR;
/* CARD_RESTRICTED means card is present but not usable due to carrier restrictions */
- static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = "CARD_RESTRICTED";
+ static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = Intent.SIM_STATE_CARD_RESTRICTED;
/* LOCKED means ICC is locked by pin or by network */
- public static final String INTENT_VALUE_ICC_LOCKED = "LOCKED";
+ public static final String INTENT_VALUE_ICC_LOCKED = Intent.SIM_STATE_LOCKED;
/* READY means ICC is ready to access */
- public static final String INTENT_VALUE_ICC_READY = "READY";
+ public static final String INTENT_VALUE_ICC_READY = Intent.SIM_STATE_READY;
/* IMSI means ICC IMSI is ready in property */
- public static final String INTENT_VALUE_ICC_IMSI = "IMSI";
+ public static final String INTENT_VALUE_ICC_IMSI = Intent.SIM_STATE_IMSI;
/* LOADED means all ICC records, including IMSI, are loaded */
- public static final String INTENT_VALUE_ICC_LOADED = "LOADED";
+ public static final String INTENT_VALUE_ICC_LOADED = Intent.SIM_STATE_LOADED;
/* The extra data for broadcasting intent INTENT_ICC_STATE_CHANGE */
- public static final String INTENT_KEY_LOCKED_REASON = "reason";
+ public static final String INTENT_KEY_LOCKED_REASON = Intent.EXTRA_SIM_LOCKED_REASON;
/* PIN means ICC is locked on PIN1 */
- public static final String INTENT_VALUE_LOCKED_ON_PIN = "PIN";
+ public static final String INTENT_VALUE_LOCKED_ON_PIN = Intent.SIM_LOCKED_ON_PIN;
/* PUK means ICC is locked on PUK1 */
- public static final String INTENT_VALUE_LOCKED_ON_PUK = "PUK";
+ public static final String INTENT_VALUE_LOCKED_ON_PUK = Intent.SIM_LOCKED_ON_PUK;
/* NETWORK means ICC is locked on NETWORK PERSONALIZATION */
- public static final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK";
+ public static final String INTENT_VALUE_LOCKED_NETWORK = Intent.SIM_LOCKED_NETWORK;
/* PERM_DISABLED means ICC is permanently disabled due to puk fails */
- public static final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
+ public static final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED =
+ Intent.SIM_ABSENT_ON_PERM_DISABLED;
/**
* This is combination of IccCardStatus.CardState and IccCardApplicationStatus.AppState
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index c19ae7b3916a..aad7f3e7bf2a 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -182,10 +182,6 @@ public class PhoneConstants {
public static final String SLOT_KEY = "slot";
- /** Fired when a subscriptions phone state changes. */
- public static final String ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED =
- "android.intent.action.SUBSCRIPTION_PHONE_STATE";
-
// FIXME: This is used to pass a subId via intents, we need to look at its usage, which is
// FIXME: extensive, and see if this should be an array of all active subId's or ...?
/**
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 22168c54510b..9cbcd7fc6b04 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -489,6 +489,8 @@ public interface RILConstants {
int RIL_REQUEST_EMERGENCY_DIAL = 205;
int RIL_REQUEST_GET_PHONE_CAPABILITY = 206;
int RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG = 207;
+ int RIL_REQUEST_ENABLE_UICC_APPLICATIONS = 208;
+ int RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT = 209;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
@@ -552,4 +554,5 @@ public interface RILConstants {
int RIL_UNSOL_ICC_SLOT_STATUS = 1100;
int RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG = 1101;
int RIL_UNSOL_EMERGENCY_NUMBER_LIST = 1102;
+ int RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED = 1103;
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 8b62872b77af..b2c3fc79025b 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -240,25 +240,6 @@ public class TelephonyIntents {
*/
public static final String ACTION_NETWORK_SET_TIME = "android.intent.action.NETWORK_SET_TIME";
-
- /**
- * Broadcast Action: The timezone was set by the carrier (typically by the NITZ string).
- * This is a sticky broadcast.
- * The intent will have the following extra values:</p>
- * <ul>
- * <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time
- * zone.</li>
- * </ul>
- *
- * <p class="note">
- * Requires the READ_PHONE_STATE permission.
- *
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
- */
- public static final String ACTION_NETWORK_SET_TIMEZONE
- = "android.intent.action.NETWORK_SET_TIMEZONE";
-
/**
* <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
* <p class="note">.
diff --git a/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java
new file mode 100644
index 000000000000..8a2545772b5b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ if (handler == null) {
+ throw new NullPointerException();
+ }
+ mHandler = handler;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+}
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index aa4174ad40f4..616b6b005f89 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,6 +30,7 @@ java_sdk_library {
libs: [
"framework-all",
"app-compat-annotations",
+ "unsupportedappusage",
],
api_packages: [
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index adcbb4287dd0..9bb9983f66a9 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
java_test_host {
- name: "ApkVerityTests",
+ name: "ApkVerityTest",
srcs: ["src/**/*.java"],
libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
test_suites: ["general-tests"],
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml
index 73779cbd1a87..51bcdea21f49 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/ApkVerityTest/AndroidTest.xml
@@ -36,6 +36,6 @@
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
- <option name="jar" value="ApkVerityTests.jar" />
+ <option name="jar" value="ApkVerityTest.jar" />
</test>
</configuration>
diff --git a/tests/ApkVerityTest/TEST_MAPPING b/tests/ApkVerityTest/TEST_MAPPING
new file mode 100644
index 000000000000..a6608399d83c
--- /dev/null
+++ b/tests/ApkVerityTest/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ // nextgen test only runs during postsubmit.
+ {
+ "name": "ApkVerityTest",
+ "keywords": ["nextgen"]
+ }
+ ],
+ "postsubmit": [
+ // TODO: move to presubmit once it's confirmed stable.
+ {
+ "name": "ApkVerityTest"
+ }
+ ]
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index ef8facec9752..b4cafe41662e 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -328,7 +328,8 @@ public class PackageWatchdogTest {
long differentVersionCode = 2L;
TestObserver observer = new TestObserver(OBSERVER_NAME_1) {
@Override
- public int onHealthCheckFailed(VersionedPackage versionedPackage) {
+ public int onHealthCheckFailed(VersionedPackage versionedPackage,
+ int failureReason) {
if (versionedPackage.getVersionCode() == VERSION_CODE) {
// Only rollback for specific versionCode
return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
@@ -1012,7 +1013,7 @@ public class PackageWatchdogTest {
mImpact = impact;
}
- public int onHealthCheckFailed(VersionedPackage versionedPackage) {
+ public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason) {
mHealthCheckFailedPackages.add(versionedPackage.getPackageName());
return mImpact;
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 3be7a4a0261d..7b289d8a7858 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -22,18 +22,14 @@ import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoFo
import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
-import android.annotation.Nullable;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.ParcelFileDescriptor;
import android.provider.DeviceConfig;
-import android.text.TextUtils;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -44,7 +40,6 @@ import com.android.cts.install.lib.TestApp;
import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
import com.android.cts.rollback.lib.RollbackUtils;
-import com.android.internal.R;
import libcore.io.IoUtils;
@@ -75,7 +70,6 @@ public class StagedRollbackTest {
private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS =
"watchdog_request_timeout_millis";
- private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName();
private static final TestApp NETWORK_STACK = new TestApp("NetworkStack",
getNetworkStackPackageName(), -1, false, findNetworkStackApk());
@@ -186,21 +180,15 @@ public class StagedRollbackTest {
}
/**
- * Stage install ModuleMetadata package to simulate a Mainline module update.
+ * Stage install an apk with rollback that will be later triggered by unattributable crash.
*/
@Test
public void testNativeWatchdogTriggersRollback_Phase1() throws Exception {
- resetModuleMetadataPackage();
- Context context = InstrumentationRegistry.getInstrumentation().getContext();
- PackageInfo metadataPackageInfo = context.getPackageManager().getPackageInfo(
- MODULE_META_DATA_PACKAGE, 0);
- String metadataApkPath = metadataPackageInfo.applicationInfo.sourceDir;
- assertThat(metadataApkPath).isNotNull();
- assertThat(metadataApkPath).isNotEqualTo("");
-
- runShellCommand("pm install "
- + "-r --enable-rollback --staged --wait "
- + metadataApkPath);
+ Uninstall.packages(TestApp.A);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+
+ Install.single(TestApp.A2).setEnableRollback().setStaged().commit();
}
/**
@@ -208,9 +196,10 @@ public class StagedRollbackTest {
*/
@Test
public void testNativeWatchdogTriggersRollback_Phase2() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- MODULE_META_DATA_PACKAGE)).isNotNull();
+ TestApp.A)).isNotNull();
}
/**
@@ -218,9 +207,10 @@ public class StagedRollbackTest {
*/
@Test
public void testNativeWatchdogTriggersRollback_Phase3() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- MODULE_META_DATA_PACKAGE)).isNotNull();
+ TestApp.A)).isNotNull();
}
@Test
@@ -351,26 +341,6 @@ public class StagedRollbackTest {
getNetworkStackPackageName())).isNull();
}
- @Nullable
- private static String getModuleMetadataPackageName() {
- String packageName = InstrumentationRegistry.getInstrumentation().getContext()
- .getResources().getString(R.string.config_defaultModuleMetadataProvider);
- if (TextUtils.isEmpty(packageName)) {
- return null;
- }
- return packageName;
- }
-
- private void resetModuleMetadataPackage() {
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- assertThat(MODULE_META_DATA_PACKAGE).isNotNull();
- rm.expireRollbackForPackage(MODULE_META_DATA_PACKAGE);
-
- assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- MODULE_META_DATA_PACKAGE)).isNull();
- }
-
private static void runShellCommand(String cmd) {
ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
.executeShellCommand(cmd);
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index b06607e41c07..0db1807c75d9 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -160,13 +160,19 @@ class MenuVisitor : public BaseVisitor {
void Visit(xml::Element* node) override {
if (node->namespace_uri.empty() && node->name == "item") {
for (const auto& attr : node->attributes) {
- if (attr.namespace_uri == xml::kSchemaAndroid) {
- if ((attr.name == "actionViewClass" || attr.name == "actionProviderClass") &&
- util::IsJavaClassName(attr.value)) {
- AddClass(node->line_number, attr.value, "android.content.Context");
- } else if (attr.name == "onClick") {
- AddMethod(node->line_number, attr.value, "android.view.MenuItem");
- }
+ // AppCompat-v7 defines its own versions of Android attributes if
+ // they're defined after SDK 7 (the below are from 11 and 14,
+ // respectively), so don't bother checking the XML namespace.
+ //
+ // Given the names of the containing XML files and the attribute
+ // names, it's unlikely that keeping these classes would be wrong.
+ if ((attr.name == "actionViewClass" || attr.name == "actionProviderClass") &&
+ util::IsJavaClassName(attr.value)) {
+ AddClass(node->line_number, attr.value, "android.content.Context");
+ }
+
+ if (attr.namespace_uri == xml::kSchemaAndroid && attr.name == "onClick") {
+ AddMethod(node->line_number, attr.value, "android.view.MenuItem");
}
}
}
diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp
index 87205973566b..b6e76021ccc1 100644
--- a/tools/aapt2/java/ProguardRules_test.cpp
+++ b/tools/aapt2/java/ProguardRules_test.cpp
@@ -326,6 +326,25 @@ TEST(ProguardRulesTest, MenuRulesAreEmitted) {
EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
}
+TEST(ProguardRulesTest, MenuRulesAreEmittedForActionClasses) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
+ <menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item android:id="@+id/my_item"
+ app:actionViewClass="com.foo.Bar"
+ app:actionProviderClass="com.foo.Baz" />
+ </menu>)");
+ menu->file.name = test::ParseNameOrDie("menu/foo");
+
+ proguard::KeepSet set;
+ ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));
+
+ std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
+ EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar"));
+ EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz"));
+}
+
TEST(ProguardRulesTest, TransitionPathMotionRulesAreEmitted) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
std::unique_ptr<xml::XmlResource> transition = test::BuildXmlDom(R"(
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index d45c4e7efb12..712b48edbc1b 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -189,6 +189,7 @@ static int write_java_methods(
}
fprintf(out, "\n");
+ fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str());
fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str());
// Add support for writing using Q schema if this is not the default module.
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index fccbcf7c101f..b52880e29e30 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -44,7 +44,6 @@ import android.net.wifi.WifiNetworkSuggestion;
import android.os.Messenger;
import android.os.ResultReceiver;
import android.os.WorkSource;
-import android.os.connectivity.WifiActivityEnergyInfo;
/**
* Interface that allows controlling and querying Wi-Fi connectivity.
@@ -55,8 +54,6 @@ interface IWifiManager
{
long getSupportedFeatures();
- WifiActivityEnergyInfo reportActivityInfo();
-
oneway void getWifiActivityEnergyInfoAsync(in IOnWifiActivityEnergyInfoListener listener);
ParceledListSlice getConfiguredNetworks(String packageName, String featureId);
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 449f95e8a161..66b0590511fc 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -22,7 +22,6 @@ import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.security.Credentials;
import android.text.TextUtils;
import android.util.Log;
@@ -93,10 +92,26 @@ public class WifiEnterpriseConfig implements Parcelable {
*/
public static final String ENGINE_DISABLE = "0";
+ /**
+ * Key prefix for CA certificates.
+ * Note: copied from {@link android.security.Credentials#CA_CERTIFICATE} since it is @hide.
+ */
+ private static final String CA_CERTIFICATE = "CACERT_";
+ /**
+ * Key prefix for user certificates.
+ * Note: copied from {@link android.security.Credentials#USER_CERTIFICATE} since it is @hide.
+ */
+ private static final String USER_CERTIFICATE = "USRCERT_";
+ /**
+ * Key prefix for user private and secret keys.
+ * Note: copied from {@link android.security.Credentials#USER_PRIVATE_KEY} since it is @hide.
+ */
+ private static final String USER_PRIVATE_KEY = "USRPKEY_";
+
/** @hide */
- public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
+ public static final String CA_CERT_PREFIX = KEYSTORE_URI + CA_CERTIFICATE;
/** @hide */
- public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE;
+ public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + USER_CERTIFICATE;
/** @hide */
public static final String CLIENT_CERT_KEY = "client_cert";
/** @hide */
@@ -659,7 +674,7 @@ public class WifiEnterpriseConfig implements Parcelable {
if (i > 0) {
sb.append(CA_CERT_ALIAS_DELIMITER);
}
- sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i]));
+ sb.append(encodeCaCertificateAlias(CA_CERTIFICATE + aliases[i]));
}
setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI);
}
@@ -693,8 +708,8 @@ public class WifiEnterpriseConfig implements Parcelable {
String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER);
for (int i = 0; i < aliases.length; i++) {
aliases[i] = decodeCaCertificateAlias(aliases[i]);
- if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) {
- aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length());
+ if (aliases[i].startsWith(CA_CERTIFICATE)) {
+ aliases[i] = aliases[i].substring(CA_CERTIFICATE.length());
}
}
return aliases.length != 0 ? aliases : null;
@@ -832,7 +847,7 @@ public class WifiEnterpriseConfig implements Parcelable {
@SystemApi
public void setClientCertificateAlias(@Nullable String alias) {
setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX);
- setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
+ setFieldValue(PRIVATE_KEY_ID_KEY, alias, USER_PRIVATE_KEY);
// Also, set engine parameters
if (TextUtils.isEmpty(alias)) {
setFieldValue(ENGINE_KEY, ENGINE_DISABLE);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 0108d5aa936c..50d62a0b627e 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1069,7 +1069,7 @@ public class WifiManager {
* @deprecated This API is non-functional and will have no impact.
*/
@Deprecated
- public static final int WIFI_MODE_FULL = WifiProtoEnums.WIFI_MODE_FULL; // 1
+ public static final int WIFI_MODE_FULL = 1;
/**
* In this Wi-Fi lock mode, Wi-Fi will be kept active,
@@ -1083,7 +1083,7 @@ public class WifiManager {
* @deprecated This API is non-functional and will have no impact.
*/
@Deprecated
- public static final int WIFI_MODE_SCAN_ONLY = WifiProtoEnums.WIFI_MODE_SCAN_ONLY; // 2
+ public static final int WIFI_MODE_SCAN_ONLY = 2;
/**
* In this Wi-Fi lock mode, Wi-Fi will not go to power save.
@@ -1102,7 +1102,7 @@ public class WifiManager {
* When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
* lock will have no impact.
*/
- public static final int WIFI_MODE_FULL_HIGH_PERF = WifiProtoEnums.WIFI_MODE_FULL_HIGH_PERF; // 3
+ public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
/**
* In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
@@ -1132,8 +1132,8 @@ public class WifiManager {
* lock will be effective when app is running in foreground and screen is on,
* while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
*/
- public static final int WIFI_MODE_FULL_LOW_LATENCY =
- WifiProtoEnums.WIFI_MODE_FULL_LOW_LATENCY; // 4
+ public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
+
/** Anything worse than or equal to this will show 0 bars. */
@UnsupportedAppUsage
@@ -2379,25 +2379,6 @@ public class WifiManager {
}
/**
- * Return the record of {@link WifiActivityEnergyInfo} object that
- * has the activity and energy info. This can be used to ascertain what
- * the controller has been up to, since the last sample.
- *
- * @return a record with {@link WifiActivityEnergyInfo} or null if
- * report is unavailable or unsupported
- * @hide
- */
- public WifiActivityEnergyInfo getControllerActivityEnergyInfo() {
- try {
- synchronized(this) {
- return mService.reportActivityInfo();
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
* set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
*
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
index 24aa23aec7ae..04d2e1a8b5dd 100644
--- a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -23,7 +23,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.MacAddress;
import android.net.MatchAllNetworkSpecifier;
-import android.net.NetworkAgent;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.os.Parcel;
@@ -120,7 +119,7 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
/**
* Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the
- * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}.
+ * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link android.net.NetworkAgent}.
*/
public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) {
// None of these should be null by construction.
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index b07d8edde3d4..61ab92c9416f 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -47,6 +47,7 @@ public final class ConfigRequest implements Parcelable {
*/
public static final int NAN_BAND_24GHZ = 0;
public static final int NAN_BAND_5GHZ = 1;
+ public static final int NAN_BAND_6GHZ = 2;
/**
* Magic values for Discovery Window (DW) interval configuration
@@ -60,6 +61,11 @@ public final class ConfigRequest implements Parcelable {
public final boolean mSupport5gBand;
/**
+ * Indicates whether 6G band support is requested.
+ */
+ public final boolean mSupport6gBand;
+
+ /**
* Specifies the desired master preference.
*/
public final int mMasterPreference;
@@ -81,9 +87,10 @@ public final class ConfigRequest implements Parcelable {
*/
public final int mDiscoveryWindowInterval[];
- private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
- int clusterHigh, int discoveryWindowInterval[]) {
+ private ConfigRequest(boolean support5gBand, boolean support6gBand, int masterPreference,
+ int clusterLow, int clusterHigh, int[] discoveryWindowInterval) {
mSupport5gBand = support5gBand;
+ mSupport6gBand = support6gBand;
mMasterPreference = masterPreference;
mClusterLow = clusterLow;
mClusterHigh = clusterHigh;
@@ -92,10 +99,12 @@ public final class ConfigRequest implements Parcelable {
@Override
public String toString() {
- return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
- + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
- + mClusterHigh + ", mDiscoveryWindowInterval="
- + Arrays.toString(mDiscoveryWindowInterval) + "]";
+ return "ConfigRequest [mSupport5gBand=" + mSupport5gBand
+ + ", mSupport6gBand=" + mSupport6gBand
+ + ", mMasterPreference=" + mMasterPreference
+ + ", mClusterLow=" + mClusterLow
+ + ", mClusterHigh=" + mClusterHigh
+ + ", mDiscoveryWindowInterval=" + Arrays.toString(mDiscoveryWindowInterval) + "]";
}
@Override
@@ -106,6 +115,7 @@ public final class ConfigRequest implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mSupport5gBand ? 1 : 0);
+ dest.writeInt(mSupport6gBand ? 1 : 0);
dest.writeInt(mMasterPreference);
dest.writeInt(mClusterLow);
dest.writeInt(mClusterHigh);
@@ -121,13 +131,14 @@ public final class ConfigRequest implements Parcelable {
@Override
public ConfigRequest createFromParcel(Parcel in) {
boolean support5gBand = in.readInt() != 0;
+ boolean support6gBand = in.readInt() != 0;
int masterPreference = in.readInt();
int clusterLow = in.readInt();
int clusterHigh = in.readInt();
int discoveryWindowInterval[] = in.createIntArray();
- return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
- discoveryWindowInterval);
+ return new ConfigRequest(support5gBand, support6gBand, masterPreference, clusterLow,
+ clusterHigh, discoveryWindowInterval);
}
};
@@ -143,7 +154,9 @@ public final class ConfigRequest implements Parcelable {
ConfigRequest lhs = (ConfigRequest) o;
- return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
+ return mSupport5gBand == lhs.mSupport5gBand
+ && mSupport6gBand == lhs.mSupport6gBand
+ && mMasterPreference == lhs.mMasterPreference
&& mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
&& Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval);
}
@@ -153,6 +166,7 @@ public final class ConfigRequest implements Parcelable {
int result = 17;
result = 31 * result + (mSupport5gBand ? 1 : 0);
+ result = 31 * result + (mSupport6gBand ? 1 : 0);
result = 31 * result + mMasterPreference;
result = 31 * result + mClusterLow;
result = 31 * result + mClusterHigh;
@@ -190,9 +204,9 @@ public final class ConfigRequest implements Parcelable {
throw new IllegalArgumentException(
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
- if (mDiscoveryWindowInterval.length != 2) {
+ if (mDiscoveryWindowInterval.length != 3) {
throw new IllegalArgumentException(
- "Invalid discovery window interval: must have 2 elements (2.4 & 5");
+ "Invalid discovery window interval: must have 3 elements (2.4 & 5 & 6");
}
if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT &&
(mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5]
@@ -206,7 +220,12 @@ public final class ConfigRequest implements Parcelable {
throw new IllegalArgumentException(
"Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]");
}
-
+ if (mDiscoveryWindowInterval[NAN_BAND_6GHZ] != DW_INTERVAL_NOT_INIT
+ && (mDiscoveryWindowInterval[NAN_BAND_6GHZ] < 0 // valid for 6GHz: [0-5]
+ || mDiscoveryWindowInterval[NAN_BAND_6GHZ] > 5)) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval for 6GHz: valid is UNSET or [0,5]");
+ }
}
/**
@@ -214,10 +233,12 @@ public final class ConfigRequest implements Parcelable {
*/
public static final class Builder {
private boolean mSupport5gBand = true;
+ private boolean mSupport6gBand = false;
private int mMasterPreference = 0;
private int mClusterLow = CLUSTER_ID_MIN;
private int mClusterHigh = CLUSTER_ID_MAX;
- private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT};
+ private int[] mDiscoveryWindowInterval = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT,
+ DW_INTERVAL_NOT_INIT};
/**
* Specify whether 5G band support is required in this request. Disabled by default.
@@ -233,6 +254,19 @@ public final class ConfigRequest implements Parcelable {
}
/**
+ * Specify whether 6G band support is required in this request. Disabled by default.
+ *
+ * @param support6gBand Support for 6G band is required.
+ *
+ * @return The builder to facilitate chaining
+ * {@code builder.setXXX(..).setXXX(..)}.
+ */
+ public Builder setSupport6gBand(boolean support6gBand) {
+ mSupport6gBand = support6gBand;
+ return this;
+ }
+
+ /**
* Specify the Master Preference requested. The permitted range is 0 (the default) to
* 255 with 1 and 255 excluded (reserved).
*
@@ -310,7 +344,8 @@ public final class ConfigRequest implements Parcelable {
* awake. The configuration enables trading off latency vs. power (higher interval means
* higher discovery latency but lower power).
*
- * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}.
+ * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ} or
+ * {@link #NAN_BAND_6GHZ}.
* @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For
* the 5GHz band a value of 0 indicates that the device will not be awake
* for any discovery windows.
@@ -319,13 +354,14 @@ public final class ConfigRequest implements Parcelable {
* {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}.
*/
public Builder setDiscoveryWindowInterval(int band, int interval) {
- if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) {
+ if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ && band != NAN_BAND_6GHZ) {
throw new IllegalArgumentException("Invalid band value");
}
if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5))
- || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) {
+ || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))
+ || (band == NAN_BAND_6GHZ && (interval < 0 || interval > 5))) {
throw new IllegalArgumentException(
- "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]");
+ "Invalid interval value: 2.4 GHz [1,5] or 5GHz/6GHz [0,5]");
}
mDiscoveryWindowInterval[band] = interval;
@@ -342,8 +378,8 @@ public final class ConfigRequest implements Parcelable {
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
- return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
- mDiscoveryWindowInterval);
+ return new ConfigRequest(mSupport5gBand, mSupport6gBand, mMasterPreference, mClusterLow,
+ mClusterHigh, mDiscoveryWindowInterval);
}
}
}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 367cfa069e74..524a53c03305 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -76,11 +76,14 @@ public class BaseWifiService extends IWifiManager.Stub {
throw new UnsupportedOperationException();
}
- @Override
+ /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */
+ @Deprecated
public WifiActivityEnergyInfo reportActivityInfo() {
throw new UnsupportedOperationException();
}
+ /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */
+ @Deprecated
public void requestActivityInfo(ResultReceiver result) {
throw new UnsupportedOperationException();
}
@@ -544,19 +547,6 @@ public class BaseWifiService extends IWifiManager.Stub {
throw new UnsupportedOperationException();
}
- /** @deprecated replaced by {@link #registerScanResultsCallback(IScanResultsCallback)} */
- @Deprecated
- public void registerScanResultsListener(
- IBinder binder, IScanResultsListener listener, int listenerIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- /** @deprecated replaced by {@link #unregisterScanResultsCallback(IScanResultsCallback)} */
- @Deprecated
- public void unregisterScanResultsListener(int listenerIdentifier) {
- throw new UnsupportedOperationException();
- }
-
@Override
public void registerScanResultsCallback(IScanResultsCallback callback) {
throw new UnsupportedOperationException();
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index ac3304073809..f92d38c982b8 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1708,18 +1708,6 @@ public class WifiManagerTest {
}
/**
- * Test behavior of {@link WifiManager#getControllerActivityEnergyInfo()}
- */
- @Test
- public void testGetControllerActivityEnergyInfo() throws Exception {
- WifiActivityEnergyInfo activityEnergyInfo =
- new WifiActivityEnergyInfo(5, 3, 3, 5, 5, 5);
- when(mWifiService.reportActivityInfo()).thenReturn(activityEnergyInfo);
-
- assertEquals(activityEnergyInfo, mWifiManager.getControllerActivityEnergyInfo());
- }
-
- /**
* Tests that passing a null Executor to {@link WifiManager#getWifiActivityEnergyInfoAsync}
* throws an exception.
*/
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 200c0e31cb22..65fbf5b099d4 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -578,12 +578,15 @@ public class WifiAwareManagerTest {
collector.checkThat("mMasterPreference", 0,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", true, equalTo(configRequest.mSupport5gBand));
- collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ collector.checkThat("mSupport6gBand", false, equalTo(configRequest.mSupport6gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 3,
equalTo(configRequest.mDiscoveryWindowInterval.length));
collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
collector.checkThat("mDiscoveryWindowInterval[5Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[6Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ]));
}
@Test
@@ -592,12 +595,16 @@ public class WifiAwareManagerTest {
final int clusterLow = 5;
final int masterPreference = 55;
final boolean supportBand5g = true;
+ final boolean supportBand6g = true;
final int dwWindow5GHz = 3;
+ final int dwWindow6GHz = 4;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setSupport6gBand(supportBand6g)
.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz)
.build();
collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh));
@@ -605,12 +612,15 @@ public class WifiAwareManagerTest {
collector.checkThat("mMasterPreference", masterPreference,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand));
- collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ collector.checkThat("mSupport6gBand", supportBand6g, equalTo(configRequest.mSupport6gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 3,
equalTo(configRequest.mDiscoveryWindowInterval.length));
collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
collector.checkThat("mDiscoveryWindowInterval[5GHz]", dwWindow5GHz,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[6GHz]", dwWindow6GHz,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ]));
}
@Test(expected = IllegalArgumentException.class)
@@ -689,14 +699,18 @@ public class WifiAwareManagerTest {
final int clusterLow = 25;
final int masterPreference = 177;
final boolean supportBand5g = true;
+ final boolean supportBand6g = false;
final int dwWindow24GHz = 1;
final int dwWindow5GHz = 5;
+ final int dwWindow6GHz = 4;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setSupport6gBand(supportBand6g)
.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz)
.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz)
.build();
Parcel parcelW = Parcel.obtain();