summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java71
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java50
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java11
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java671
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java182
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java32
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java1
-rw-r--r--core/api/current.txt2
-rw-r--r--core/api/module-lib-current.txt9
-rw-r--r--core/api/system-current.txt6
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/Notification.java1
-rw-r--r--core/java/android/app/OWNERS13
-rw-r--r--core/java/android/app/SystemServiceRegistry.java11
-rw-r--r--core/java/android/app/people/ConversationChannel.aidl (renamed from services/core/jni/stats/PowerStatsPuller.h)28
-rw-r--r--core/java/android/app/people/IPeopleManager.aidl8
-rw-r--r--core/java/android/apphibernation/AppHibernationManager.java42
-rw-r--r--core/java/android/apphibernation/IAppHibernationService.aidl6
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/pm/PackageManager.java1
-rw-r--r--core/java/android/content/pm/PackageParser.java49
-rw-r--r--core/java/android/content/res/FontResourcesParser.java19
-rw-r--r--core/java/android/net/ConnectivityManager.java91
-rw-r--r--core/java/android/net/IConnectivityManager.aidl1
-rw-r--r--core/java/android/net/INetworkStatsService.aidl4
-rw-r--r--core/java/android/net/MatchAllNetworkSpecifier.java11
-rw-r--r--core/java/android/net/NetworkAgentConfig.java4
-rw-r--r--core/java/android/net/UnderlyingNetworkInfo.aidl (renamed from core/java/android/net/VpnInfo.aidl)2
-rw-r--r--core/java/android/net/UnderlyingNetworkInfo.java110
-rw-r--r--core/java/android/net/VpnInfo.java86
-rw-r--r--core/java/android/net/vcn/IVcnManagementService.aidl4
-rw-r--r--core/java/android/net/vcn/VcnManager.java35
-rw-r--r--core/java/android/os/ServiceManager.java14
-rw-r--r--core/java/android/os/ServiceManagerNative.java4
-rw-r--r--core/java/android/os/incremental/IIncrementalService.aidl29
-rw-r--r--core/java/android/os/incremental/IncrementalFileStorages.java91
-rw-r--r--core/java/android/os/incremental/IncrementalManager.java26
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java39
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java61
-rw-r--r--core/java/android/service/voice/IVoiceInteractionSessionService.aidl2
-rw-r--r--core/java/android/service/voice/VoiceInteractionSessionService.java21
-rw-r--r--core/java/android/util/RotationUtils.java32
-rw-r--r--core/java/android/view/DisplayCutout.java302
-rw-r--r--core/java/android/view/SurfaceControl.java9
-rw-r--r--core/java/android/view/SyncRtSurfaceTransactionApplier.java9
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/jni/android_view_SurfaceControl.cpp3
-rw-r--r--core/res/AndroidManifest.xml20
-rw-r--r--core/res/res/values/attrs.xml6
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/tests/GameManagerTests/Android.bp29
-rw-r--r--core/tests/GameManagerTests/AndroidManifest.xml30
-rw-r--r--core/tests/GameManagerTests/AndroidTest.xml32
-rw-r--r--core/tests/GameManagerTests/src/android/graphics/GameManagerTests.java83
-rw-r--r--core/tests/coretests/res/font/samplexmldownloadedfont.xml3
-rw-r--r--core/tests/coretests/src/android/content/pm/SigningDetailsTest.java246
-rw-r--r--core/tests/coretests/src/android/content/res/FontResourcesParserTest.java1
-rw-r--r--core/tests/coretests/src/android/view/DisplayCutoutTest.java58
-rw-r--r--core/tests/mockingcoretests/src/android/view/OWNERS2
-rw-r--r--data/etc/com.android.launcher3.xml3
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--graphics/java/android/graphics/GameManager.java98
-rw-r--r--graphics/java/android/graphics/IGameManagerService.aidl25
-rw-r--r--graphics/java/android/graphics/Typeface.java21
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java33
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp9
-rw-r--r--libs/hwui/Layer.cpp5
-rw-r--r--libs/hwui/RecordingCanvas.cpp4
-rw-r--r--libs/hwui/SkiaCanvas.cpp36
-rw-r--r--libs/hwui/VectorDrawable.cpp4
-rw-r--r--libs/hwui/canvas/CanvasOps.h9
-rw-r--r--libs/hwui/hwui/ImageDecoder.cpp10
-rw-r--r--libs/hwui/jni/BitmapFactory.cpp5
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp10
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp4
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp2
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp2
-rw-r--r--libs/hwui/tests/microbench/CanvasOpBench.cpp1
-rw-r--r--libs/hwui/tests/unit/CanvasOpTests.cpp3
-rw-r--r--media/jni/Android.bp5
-rw-r--r--media/jni/android_media_tv_Tuner.cpp2
-rw-r--r--media/jni/tuner/DemuxClient.cpp16
-rw-r--r--media/jni/tuner/DvrClient.cpp7
-rw-r--r--media/jni/tuner/FilterClient.cpp166
-rw-r--r--media/jni/tuner/FilterClient.h12
-rw-r--r--media/jni/tuner/FrontendClient.cpp68
-rw-r--r--media/jni/tuner/FrontendClient.h4
-rw-r--r--media/jni/tuner/TunerClient.cpp3
-rw-r--r--media/native/midi/include/amidi/AMidi.h4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java6
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml5
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml1
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java18
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java7
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java130
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java79
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java13
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java32
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java28
-rw-r--r--services/core/java/com/android/server/Watchdog.java32
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java231
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2293
-rw-r--r--services/core/java/com/android/server/am/AppErrorDialog.java4
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java615
-rw-r--r--services/core/java/com/android/server/am/AppExitInfoTracker.java123
-rw-r--r--services/core/java/com/android/server/am/AppNotRespondingDialog.java4
-rw-r--r--services/core/java/com/android/server/am/AppProfiler.java993
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java10
-rw-r--r--services/core/java/com/android/server/am/CacheOomRanker.java14
-rw-r--r--services/core/java/com/android/server/am/ConnectionRecord.java2
-rw-r--r--services/core/java/com/android/server/am/ContentProviderConnection.java8
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java16
-rw-r--r--services/core/java/com/android/server/am/ContentProviderRecord.java2
-rw-r--r--services/core/java/com/android/server/am/FgsStartTempAllowList.java4
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java87
-rw-r--r--services/core/java/com/android/server/am/PackageList.java155
-rw-r--r--services/core/java/com/android/server/am/PendingTempAllowlists.java (renamed from services/core/java/com/android/server/am/PendingTempWhitelists.java)32
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java920
-rw-r--r--services/core/java/com/android/server/am/ProcessProfileRecord.java651
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java362
-rw-r--r--services/core/java/com/android/server/am/StrictModeViolationDialog.java4
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java10
-rw-r--r--services/core/java/com/android/server/am/UserController.java5
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationService.java153
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java61
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java13
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java7
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java14
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java13
-rw-r--r--services/core/java/com/android/server/graphics/GameManagerService.java215
-rw-r--r--services/core/java/com/android/server/graphics/Settings.java193
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java6
-rw-r--r--services/core/java/com/android/server/location/contexthub/OWNERS1
-rw-r--r--services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java40
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsFactory.java19
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java41
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java125
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java5
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java20
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java23
-rw-r--r--services/core/java/com/android/server/powerstats/PowerStatsService.java26
-rw-r--r--services/core/java/com/android/server/powerstats/StatsPullAtomCallbackImpl.java152
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java83
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java34
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java12
-rw-r--r--services/core/java/com/android/server/wm/Session.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java40
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java105
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java33
-rw-r--r--services/core/jni/Android.bp4
-rw-r--r--services/core/jni/com_android_server_powerstats_PowerStatsService.cpp3
-rw-r--r--services/core/jni/com_android_server_stats_pull_StatsPullAtomService.cpp71
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/core/jni/stats/OWNERS9
-rw-r--r--services/core/jni/stats/PowerStatsPuller.cpp160
-rw-r--r--services/core/jni/stats/SubsystemSleepStatePuller.cpp357
-rw-r--r--services/core/jni/stats/SubsystemSleepStatePuller.h37
-rw-r--r--services/incremental/BinderIncrementalService.cpp45
-rw-r--r--services/incremental/BinderIncrementalService.h16
-rw-r--r--services/incremental/IncrementalService.cpp108
-rw-r--r--services/incremental/IncrementalService.h26
-rw-r--r--services/incremental/ServiceWrappers.cpp17
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp264
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/people/java/com/android/server/people/PeopleService.java8
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java64
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java16
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java208
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java71
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceSettingsTests.java129
-rw-r--r--services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceTests.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java (renamed from services/tests/servicestests/src/com/android/server/job/JobCountTrackerTest.java)66
-rw-r--r--services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java (renamed from services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java)53
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java79
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java36
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsDatabase.java6
-rw-r--r--telephony/java/android/telephony/ims/ImsUtListener.java7
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java38
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java31
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsUtImplBase.java27
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt3
-rw-r--r--tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt50
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java7
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java52
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsBaseTest.java10
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java53
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java57
-rw-r--r--tests/vcn/java/android/net/vcn/VcnManagerTest.java29
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java45
246 files changed, 9206 insertions, 5399 deletions
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index ed55f0056ea0..3bbc945c8b87 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -64,7 +64,7 @@ public class AppSearchManagerService extends SystemService {
public void onStart() {
publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mImplInstanceManager = new ImplInstanceManager(getContext());
+ mImplInstanceManager = ImplInstanceManager.getInstance(getContext());
}
private class Stub extends IAppSearchManager.Stub {
@@ -102,7 +102,8 @@ public class AppSearchManagerService extends SystemService {
}
schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
}
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.setSchema(
packageName,
databaseName,
@@ -133,7 +134,8 @@ public class AppSearchManagerService extends SystemService {
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
List<AppSearchSchema> schemas = impl.getSchema(packageName, databaseName);
List<Bundle> schemaBundles = new ArrayList<>(schemas.size());
for (int i = 0; i < schemas.size(); i++) {
@@ -166,7 +168,8 @@ public class AppSearchManagerService extends SystemService {
verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
for (int i = 0; i < documentBundles.size(); i++) {
GenericDocument document = new GenericDocument(documentBundles.get(i));
try {
@@ -207,12 +210,18 @@ public class AppSearchManagerService extends SystemService {
verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
- GenericDocument document = impl.getDocument(packageName, databaseName,
- namespace, uri, typePropertyPaths);
+ GenericDocument document =
+ impl.getDocument(
+ packageName,
+ databaseName,
+ namespace,
+ uri,
+ typePropertyPaths);
resultBuilder.setSuccess(uri, document.getBundle());
} catch (Throwable t) {
resultBuilder.setResult(uri, throwableToFailedResult(t));
@@ -245,7 +254,8 @@ public class AppSearchManagerService extends SystemService {
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
SearchResultPage searchResultPage =
impl.query(
packageName,
@@ -278,12 +288,14 @@ public class AppSearchManagerService extends SystemService {
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
- SearchResultPage searchResultPage = impl.globalQuery(
- queryExpression,
- new SearchSpec(searchSpecBundle),
- packageName,
- callingUid);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ SearchResultPage searchResultPage =
+ impl.globalQuery(
+ queryExpression,
+ new SearchSpec(searchSpecBundle),
+ packageName,
+ callingUid);
invokeCallbackOnResult(
callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
@@ -306,7 +318,8 @@ public class AppSearchManagerService extends SystemService {
// TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
// opened it
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
invokeCallbackOnResult(
callback,
@@ -324,7 +337,8 @@ public class AppSearchManagerService extends SystemService {
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.invalidateNextPageToken(nextPageToken);
} catch (Throwable t) {
Log.e(TAG, "Unable to invalidate the query page token", t);
@@ -350,15 +364,11 @@ public class AppSearchManagerService extends SystemService {
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
- impl.reportUsage(
- packageName,
- databaseName,
- namespace,
- uri,
- usageTimeMillis);
- invokeCallbackOnResult(callback,
- AppSearchResult.newSuccessfulResult(/*result=*/ null));
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ impl.reportUsage(packageName, databaseName, namespace, uri, usageTimeMillis);
+ invokeCallbackOnResult(
+ callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
} finally {
@@ -385,7 +395,8 @@ public class AppSearchManagerService extends SystemService {
verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
@@ -421,7 +432,8 @@ public class AppSearchManagerService extends SystemService {
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.removeByQuery(
packageName,
databaseName,
@@ -441,7 +453,8 @@ public class AppSearchManagerService extends SystemService {
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.persistToDisk();
} catch (Throwable t) {
Log.e(TAG, "Unable to persist the data to disk", t);
@@ -457,7 +470,7 @@ public class AppSearchManagerService extends SystemService {
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- mImplInstanceManager.getInstance(callingUserId);
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index fe3c2e1d1604..97b1a8cd6d50 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -41,14 +41,33 @@ import java.io.File;
public final class ImplInstanceManager {
private static final String APP_SEARCH_DIR = "appSearch";
- private static final SparseArray<AppSearchImpl> sInstances = new SparseArray<>();
+ private static ImplInstanceManager sImplInstanceManager;
- private final Context mContext;
+ private final SparseArray<AppSearchImpl> mInstances = new SparseArray<>();
private final String mGlobalQuerierPackage;
- public ImplInstanceManager(@NonNull Context context) {
- mContext = context;
- mGlobalQuerierPackage = getGlobalAppSearchDataQuerierPackageName(mContext);
+ private ImplInstanceManager(@NonNull String globalQuerierPackage) {
+ mGlobalQuerierPackage = globalQuerierPackage;
+ }
+
+ /**
+ * Gets an instance of ImplInstanceManager to be used.
+ *
+ * <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
+ * existing instance will be returned.
+ */
+ @NonNull
+ public static ImplInstanceManager getInstance(@NonNull Context context) {
+ if (sImplInstanceManager == null) {
+ synchronized (ImplInstanceManager.class) {
+ if (sImplInstanceManager == null) {
+ sImplInstanceManager =
+ new ImplInstanceManager(
+ getGlobalAppSearchDataQuerierPackageName(context));
+ }
+ }
+ }
+ return sImplInstanceManager;
}
/**
@@ -57,30 +76,30 @@ public final class ImplInstanceManager {
* <p>If no AppSearchImpl instance exists for this user, Icing will be initialized and one will
* be created.
*
+ * @param context The context
* @param userId The multi-user userId of the device user calling AppSearch
* @return An initialized {@link AppSearchImpl} for this user
*/
@NonNull
- public AppSearchImpl getInstance(@UserIdInt int userId)
+ public AppSearchImpl getAppSearchImpl(@NonNull Context context, @UserIdInt int userId)
throws AppSearchException {
- AppSearchImpl instance = sInstances.get(userId);
+ AppSearchImpl instance = mInstances.get(userId);
if (instance == null) {
synchronized (ImplInstanceManager.class) {
- instance = sInstances.get(userId);
+ instance = mInstances.get(userId);
if (instance == null) {
- instance = createImpl(userId);
- sInstances.put(userId, instance);
+ instance = createImpl(context, userId);
+ mInstances.put(userId, instance);
}
}
}
return instance;
}
- private AppSearchImpl createImpl(@UserIdInt int userId)
+ private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
throws AppSearchException {
- File appSearchDir = getAppSearchDir(mContext, userId);
- return AppSearchImpl.create(
- appSearchDir, mContext, userId, mGlobalQuerierPackage);
+ File appSearchDir = getAppSearchDir(context, userId);
+ return AppSearchImpl.create(appSearchDir, context, userId, mGlobalQuerierPackage);
}
private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
@@ -96,7 +115,8 @@ public final class ImplInstanceManager {
*
* @param context Context of the system service.
*/
- private static String getGlobalAppSearchDataQuerierPackageName(Context context) {
+ @NonNull
+ private static String getGlobalAppSearchDataQuerierPackageName(@NonNull Context context) {
String globalAppSearchDataQuerierPackage =
context.getString(R.string.config_globalAppSearchDataQuerierPackage);
try {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index d4ee9bb813c9..f6a1b8af9e49 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -151,7 +151,8 @@ public class AlarmManagerService extends SystemService {
static final boolean DEBUG_BG_LIMIT = localLOGV || false;
static final boolean DEBUG_STANDBY = localLOGV || false;
static final boolean RECORD_ALARMS_IN_HISTORY = true;
- static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
+ // TODO(b/178484639) : Turn off once alarms and reminders work is complete.
+ static final boolean RECORD_DEVICE_IDLE_ALARMS = true;
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
static final int TICK_HISTORY_DEPTH = 10;
@@ -1731,8 +1732,8 @@ public class AlarmManagerService extends SystemService {
if (RECORD_DEVICE_IDLE_ALARMS) {
IdleDispatchEntry ent = new IdleDispatchEntry();
ent.uid = a.uid;
- ent.pkg = a.operation.getCreatorPackage();
- ent.tag = a.operation.getTag("");
+ ent.pkg = a.sourcePackage;
+ ent.tag = a.statsTag;
ent.op = "START IDLE";
ent.elapsedRealtime = mInjector.getElapsedRealtime();
ent.argRealtime = a.getWhenElapsed();
@@ -3151,8 +3152,8 @@ public class AlarmManagerService extends SystemService {
if (RECORD_DEVICE_IDLE_ALARMS) {
IdleDispatchEntry ent = new IdleDispatchEntry();
ent.uid = alarm.uid;
- ent.pkg = alarm.operation.getCreatorPackage();
- ent.tag = alarm.operation.getTag("");
+ ent.pkg = alarm.sourcePackage;
+ ent.tag = alarm.statsTag;
ent.op = "END IDLE";
ent.elapsedRealtime = mInjector.getElapsedRealtime();
ent.argRealtime = alarm.getWhenElapsed();
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 7cad4ab0183d..e05f0b062dbe 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -16,6 +16,8 @@
package com.android.server.job;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
@@ -26,8 +28,11 @@ import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.provider.DeviceConfig;
+import android.util.ArraySet;
import android.util.IndentingPrintWriter;
+import android.util.Pair;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -36,16 +41,17 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.StatLogger;
import com.android.server.JobSchedulerBackgroundThread;
-import com.android.server.job.JobSchedulerService.MaxJobCountsPerMemoryTrimLevel;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.StateController;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Iterator;
import java.util.List;
/**
- * This class decides, given the various configuration and the system status, how many more jobs
- * can start.
+ * This class decides, given the various configuration and the system status, which jobs can start
+ * and which {@link JobServiceContext} to run each job on.
*/
class JobConcurrencyManager {
private static final String TAG = JobSchedulerService.TAG;
@@ -56,9 +62,22 @@ class JobConcurrencyManager {
CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms";
private static final long DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS = 30_000;
+ static final int WORK_TYPE_NONE = 0;
+ static final int WORK_TYPE_TOP = 1 << 0;
+ static final int WORK_TYPE_BG = 1 << 1;
+ private static final int NUM_WORK_TYPES = 2;
+
+ @IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
+ WORK_TYPE_NONE,
+ WORK_TYPE_TOP,
+ WORK_TYPE_BG
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WorkType {
+ }
+
private final Object mLock;
private final JobSchedulerService mService;
- private final JobSchedulerService.Constants mConstants;
private final Context mContext;
private final Handler mHandler;
@@ -72,6 +91,53 @@ class JobConcurrencyManager {
private static final int MAX_JOB_CONTEXTS_COUNT = JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
+ private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_ON =
+ new WorkConfigLimitsPerMemoryTrimLevel(
+ new WorkTypeConfig("screen_on_normal", 8,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 2)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 6))),
+ new WorkTypeConfig("screen_on_moderate", 8,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 4))),
+ new WorkTypeConfig("screen_on_low", 5,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 1))),
+ new WorkTypeConfig("screen_on_critical", 5,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 1)))
+ );
+ private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
+ new WorkConfigLimitsPerMemoryTrimLevel(
+ new WorkTypeConfig("screen_off_normal", 10,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 6))),
+ new WorkTypeConfig("screen_off_moderate", 10,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 4))),
+ new WorkTypeConfig("screen_off_low", 5,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 1))),
+ new WorkTypeConfig("screen_off_critical", 5,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, 1)))
+ );
+
/**
* This array essentially stores the state of mActiveServices array.
* The ith index stores the job present on the ith JobServiceContext.
@@ -84,10 +150,11 @@ class JobConcurrencyManager {
int[] mRecycledPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
- /** Max job counts according to the current system state. */
- private JobSchedulerService.MaxJobCounts mMaxJobCounts;
+ int[] mRecycledWorkTypeForContext = new int[MAX_JOB_CONTEXTS_COUNT];
+
+ private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
- private final JobCountTracker mJobCountTracker = new JobCountTracker();
+ private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
/** Wait for this long after screen off before adjusting the job concurrency. */
private long mScreenOffAdjustmentDelayMs = DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS;
@@ -114,7 +181,6 @@ class JobConcurrencyManager {
JobConcurrencyManager(JobSchedulerService service) {
mService = service;
mLock = mService.mLock;
- mConstants = service.mConstants;
mContext = service.getContext();
mHandler = JobSchedulerBackgroundThread.getHandler();
@@ -209,12 +275,6 @@ class JobConcurrencyManager {
}
}
- private boolean isFgJob(JobStatus job) {
- // (It's super confusing PRIORITY_BOUND_FOREGROUND_SERVICE isn't FG here)
- return job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP
- || job.shouldTreatAsExpeditedJob();
- }
-
@GuardedBy("mLock")
private void refreshSystemStateLocked() {
final long nowUptime = JobSchedulerService.sUptimeMillisClock.millis();
@@ -237,28 +297,29 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
- private void updateMaxCountsLocked() {
+ private void updateCounterConfigLocked() {
refreshSystemStateLocked();
- final MaxJobCountsPerMemoryTrimLevel jobCounts = mEffectiveInteractiveState
- ? mConstants.MAX_JOB_COUNTS_SCREEN_ON
- : mConstants.MAX_JOB_COUNTS_SCREEN_OFF;
-
+ final WorkConfigLimitsPerMemoryTrimLevel workConfigs = mEffectiveInteractiveState
+ ? CONFIG_LIMITS_SCREEN_ON : CONFIG_LIMITS_SCREEN_OFF;
+ WorkTypeConfig workTypeConfig;
switch (mLastMemoryTrimLevel) {
case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
- mMaxJobCounts = jobCounts.moderate;
+ workTypeConfig = workConfigs.moderate;
break;
case ProcessStats.ADJ_MEM_FACTOR_LOW:
- mMaxJobCounts = jobCounts.low;
+ workTypeConfig = workConfigs.low;
break;
case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
- mMaxJobCounts = jobCounts.critical;
+ workTypeConfig = workConfigs.critical;
break;
default:
- mMaxJobCounts = jobCounts.normal;
+ workTypeConfig = workConfigs.normal;
break;
}
+
+ mWorkCountTracker.setConfig(workTypeConfig);
}
/**
@@ -282,31 +343,26 @@ class JobConcurrencyManager {
Slog.d(TAG, printPendingQueueLocked());
}
- final JobPackageTracker tracker = mService.mJobPackageTracker;
final List<JobStatus> pendingJobs = mService.mPendingJobs;
final List<JobServiceContext> activeServices = mService.mActiveServices;
- final List<StateController> controllers = mService.mControllers;
-
- updateMaxCountsLocked();
// To avoid GC churn, we recycle the arrays.
JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
boolean[] slotChanged = mRecycledSlotChanged;
int[] preferredUidForContext = mRecycledPreferredUidForContext;
+ int[] workTypeForContext = mRecycledWorkTypeForContext;
+ updateCounterConfigLocked();
+ // Reset everything since we'll re-evaluate the current state.
+ mWorkCountTracker.resetCounts();
- // Initialize the work variables and also count running jobs.
- mJobCountTracker.reset(
- mMaxJobCounts.getMaxTotal(),
- mMaxJobCounts.getMaxBg(),
- mMaxJobCounts.getMinBg());
-
- for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
final JobServiceContext js = mService.mActiveServices.get(i);
final JobStatus status = js.getRunningJobLocked();
if ((contextIdToJobMap[i] = status) != null) {
- mJobCountTracker.incrementRunningJobCount(isFgJob(status));
+ mWorkCountTracker.incrementRunningJobCount(js.getRunningJobWorkType());
+ workTypeForContext[i] = js.getRunningJobWorkType();
}
slotChanged[i] = false;
@@ -317,41 +373,25 @@ class JobConcurrencyManager {
}
// Next, update the job priorities, and also count the pending FG / BG jobs.
- for (int i = 0; i < pendingJobs.size(); i++) {
- final JobStatus pending = pendingJobs.get(i);
+ updateNonRunningPriorities(pendingJobs, true);
- // If job is already running, go to next job.
- int jobRunningContext = findJobContextIdFromMap(pending, contextIdToJobMap);
- if (jobRunningContext != -1) {
- continue;
- }
-
- final int priority = mService.evaluateJobPriorityLocked(pending);
- pending.lastEvaluatedPriority = priority;
-
- mJobCountTracker.incrementPendingJobCount(isFgJob(pending));
- }
-
- mJobCountTracker.onCountDone();
+ mWorkCountTracker.onCountDone();
for (int i = 0; i < pendingJobs.size(); i++) {
final JobStatus nextPending = pendingJobs.get(i);
- // Unfortunately we need to repeat this relatively expensive check.
- int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);
- if (jobRunningContext != -1) {
+ if (mRunningJobs.contains(nextPending)) {
continue;
}
// TODO(171305774): make sure HPJs aren't pre-empted and add dedicated contexts for them
- final boolean isPendingFg = isFgJob(nextPending);
-
// Find an available slot for nextPending. The context should be available OR
// it should have lowest priority among all running jobs
// (sharing the same Uid as nextPending)
int minPriorityForPreemption = Integer.MAX_VALUE;
int selectedContextId = -1;
+ int workType = mWorkCountTracker.canJobStart(getJobWorkTypes(nextPending));
boolean startingJob = false;
for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) {
JobStatus job = contextIdToJobMap[j];
@@ -360,7 +400,7 @@ class JobConcurrencyManager {
final boolean preferredUidOkay = (preferredUid == nextPending.getUid())
|| (preferredUid == JobServiceContext.NO_PREFERRED_UID);
- if (preferredUidOkay && mJobCountTracker.canJobStart(isPendingFg)) {
+ if (preferredUidOkay && workType != WORK_TYPE_NONE) {
// This slot is free, and we haven't yet hit the limit on
// concurrent jobs... we can just throw the job in to here.
selectedContextId = j;
@@ -396,19 +436,19 @@ class JobConcurrencyManager {
}
if (startingJob) {
// Increase the counters when we're going to start a job.
- mJobCountTracker.onStartingNewJob(isPendingFg);
+ workTypeForContext[selectedContextId] = workType;
+ mWorkCountTracker.stageJob(workType);
}
}
if (DEBUG) {
Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
}
- mJobCountTracker.logStatus();
-
- tracker.noteConcurrency(mJobCountTracker.getTotalRunningJobCountToNote(),
- mJobCountTracker.getFgRunningJobCountToNote());
+ if (DEBUG) {
+ Slog.d(TAG, "assignJobsToContexts: " + mWorkCountTracker.toString());
+ }
- for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
boolean preservePreferredUid = false;
if (slotChanged[i]) {
JobStatus js = activeServices.get(i).getRunningJobLocked();
@@ -426,30 +466,58 @@ class JobConcurrencyManager {
Slog.d(TAG, "About to run job on context "
+ i + ", job: " + pendingJob);
}
- for (int ic=0; ic<controllers.size(); ic++) {
- controllers.get(ic).prepareForExecutionLocked(pendingJob);
- }
- if (!activeServices.get(i).executeRunnableJob(pendingJob)) {
- Slog.d(TAG, "Error executing " + pendingJob);
- }
- if (pendingJobs.remove(pendingJob)) {
- tracker.noteNonpending(pendingJob);
- }
+ startJobLocked(activeServices.get(i), pendingJob, workTypeForContext[i]);
}
}
if (!preservePreferredUid) {
activeServices.get(i).clearPreferredUid();
}
}
+ mWorkCountTracker.resetStagingCount();
+ noteConcurrency();
}
- private static int findJobContextIdFromMap(JobStatus jobStatus, JobStatus[] map) {
- for (int i=0; i<map.length; i++) {
- if (map[i] != null && map[i].matches(jobStatus.getUid(), jobStatus.getJobId())) {
- return i;
+ private void noteConcurrency() {
+ mService.mJobPackageTracker.noteConcurrency(mRunningJobs.size(),
+ // TODO: log per type instead of only TOP
+ mWorkCountTracker.getRunningJobCount(WORK_TYPE_TOP));
+ }
+
+ private void updateNonRunningPriorities(@NonNull final List<JobStatus> pendingJobs,
+ boolean updateCounter) {
+ for (int i = 0; i < pendingJobs.size(); i++) {
+ final JobStatus pending = pendingJobs.get(i);
+
+ // If job is already running, go to next job.
+ if (mRunningJobs.contains(pending)) {
+ continue;
+ }
+
+ pending.lastEvaluatedPriority = mService.evaluateJobPriorityLocked(pending);
+
+ if (updateCounter) {
+ mWorkCountTracker.incrementPendingJobCount(getJobWorkTypes(pending));
}
}
- return -1;
+ }
+
+ private void startJobLocked(@NonNull JobServiceContext worker, @NonNull JobStatus jobStatus,
+ @WorkType final int workType) {
+ final List<StateController> controllers = mService.mControllers;
+ for (int ic = 0; ic < controllers.size(); ic++) {
+ controllers.get(ic).prepareForExecutionLocked(jobStatus);
+ }
+ if (!worker.executeRunnableJob(jobStatus, workType)) {
+ Slog.e(TAG, "Error executing " + jobStatus);
+ mWorkCountTracker.onStagedJobFailed(workType);
+ } else {
+ mRunningJobs.add(jobStatus);
+ mWorkCountTracker.onJobStarted(workType);
+ }
+ final List<JobStatus> pendingJobs = mService.mPendingJobs;
+ if (pendingJobs.remove(jobStatus)) {
+ mService.mJobPackageTracker.noteNonpending(jobStatus);
+ }
}
@GuardedBy("mLock")
@@ -484,6 +552,16 @@ class JobConcurrencyManager {
mScreenOffAdjustmentDelayMs = properties.getLong(
KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS, DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS);
+
+ CONFIG_LIMITS_SCREEN_ON.normal.update(properties);
+ CONFIG_LIMITS_SCREEN_ON.moderate.update(properties);
+ CONFIG_LIMITS_SCREEN_ON.low.update(properties);
+ CONFIG_LIMITS_SCREEN_ON.critical.update(properties);
+
+ CONFIG_LIMITS_SCREEN_OFF.normal.update(properties);
+ CONFIG_LIMITS_SCREEN_OFF.moderate.update(properties);
+ CONFIG_LIMITS_SCREEN_OFF.low.update(properties);
+ CONFIG_LIMITS_SCREEN_OFF.critical.update(properties);
}
public void dumpLocked(IndentingPrintWriter pw, long now, long nowRealtime) {
@@ -494,6 +572,14 @@ class JobConcurrencyManager {
pw.print("Configuration:");
pw.increaseIndent();
pw.print(KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS, mScreenOffAdjustmentDelayMs).println();
+ CONFIG_LIMITS_SCREEN_ON.normal.dump(pw);
+ CONFIG_LIMITS_SCREEN_ON.moderate.dump(pw);
+ CONFIG_LIMITS_SCREEN_ON.low.dump(pw);
+ CONFIG_LIMITS_SCREEN_ON.critical.dump(pw);
+ CONFIG_LIMITS_SCREEN_OFF.normal.dump(pw);
+ CONFIG_LIMITS_SCREEN_OFF.moderate.dump(pw);
+ CONFIG_LIMITS_SCREEN_OFF.low.dump(pw);
+ CONFIG_LIMITS_SCREEN_OFF.critical.dump(pw);
pw.decreaseIndent();
pw.print("Screen state: current ");
@@ -514,7 +600,7 @@ class JobConcurrencyManager {
pw.println("Current max jobs:");
pw.println(" ");
- pw.println(mJobCountTracker);
+ pw.println(mWorkCountTracker);
pw.println();
@@ -540,8 +626,6 @@ class JobConcurrencyManager {
proto.write(JobConcurrencyManagerProto.TIME_SINCE_LAST_SCREEN_OFF_MS,
nowRealtime - mLastScreenOffRealtime);
- mJobCountTracker.dumpProto(proto, JobConcurrencyManagerProto.JOB_COUNT_TRACKER);
-
proto.write(JobConcurrencyManagerProto.MEMORY_TRIM_LEVEL, mLastMemoryTrimLevel);
mStatLogger.dumpProto(proto, JobConcurrencyManagerProto.STATS);
@@ -549,199 +633,312 @@ class JobConcurrencyManager {
proto.end(token);
}
- /**
- * This class decides, taking into account {@link #mMaxJobCounts} and how mny jos are running /
- * pending, how many more job can start.
- *
- * Extracted for testing and logging.
- */
+ int getJobWorkTypes(@NonNull JobStatus js) {
+ int classification = 0;
+ // TODO(171305774): create dedicated work type for EJ and FGS
+ if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP
+ || js.shouldTreatAsExpeditedJob()) {
+ classification |= WORK_TYPE_TOP;
+ } else {
+ classification |= WORK_TYPE_BG;
+ }
+ return classification;
+ }
+
@VisibleForTesting
- static class JobCountTracker {
- private int mConfigNumMaxTotalJobs;
- private int mConfigNumMaxBgJobs;
- private int mConfigNumMinBgJobs;
+ static class WorkTypeConfig {
+ private static final String KEY_PREFIX_MAX_TOTAL =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
+ private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
+ private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
+ private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
+ private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
+ private final String mConfigIdentifier;
+
+ private int mMaxTotal;
+ private final SparseIntArray mMinReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
+ private final SparseIntArray mMaxAllowedSlots = new SparseIntArray(NUM_WORK_TYPES);
+ private final int mDefaultMaxTotal;
+ private final SparseIntArray mDefaultMinReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
+ private final SparseIntArray mDefaultMaxAllowedSlots = new SparseIntArray(NUM_WORK_TYPES);
+
+ WorkTypeConfig(@NonNull String configIdentifier, int defaultMaxTotal,
+ List<Pair<Integer, Integer>> defaultMin, List<Pair<Integer, Integer>> defaultMax) {
+ mConfigIdentifier = configIdentifier;
+ mDefaultMaxTotal = mMaxTotal = defaultMaxTotal;
+ for (int i = defaultMin.size() - 1; i >= 0; --i) {
+ mDefaultMinReservedSlots.put(defaultMin.get(i).first, defaultMin.get(i).second);
+ }
+ for (int i = defaultMax.size() - 1; i >= 0; --i) {
+ mDefaultMaxAllowedSlots.put(defaultMax.get(i).first, defaultMax.get(i).second);
+ }
+ update(new DeviceConfig.Properties.Builder(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER).build());
+ }
- private int mNumRunningFgJobs;
- private int mNumRunningBgJobs;
+ void update(@NonNull DeviceConfig.Properties properties) {
+ // Ensure total in the range [1, MAX_JOB_CONTEXTS_COUNT].
+ mMaxTotal = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
+ properties.getInt(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mDefaultMaxTotal)));
+
+ mMaxAllowedSlots.clear();
+ // Ensure they're in the range [1, total].
+ final int maxTop = Math.max(1, Math.min(mMaxTotal,
+ properties.getInt(KEY_PREFIX_MAX_TOP + mConfigIdentifier,
+ mDefaultMaxAllowedSlots.get(WORK_TYPE_TOP, mMaxTotal))));
+ mMaxAllowedSlots.put(WORK_TYPE_TOP, maxTop);
+ final int maxBg = Math.max(1, Math.min(mMaxTotal,
+ properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier,
+ mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal))));
+ mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg);
+
+ int remaining = mMaxTotal;
+ mMinReservedSlots.clear();
+ // Ensure top is in the range [1, min(maxTop, total)]
+ final int minTop = Math.max(1, Math.min(Math.min(maxTop, mMaxTotal),
+ properties.getInt(KEY_PREFIX_MIN_TOP + mConfigIdentifier,
+ mDefaultMinReservedSlots.get(WORK_TYPE_TOP))));
+ mMinReservedSlots.put(WORK_TYPE_TOP, minTop);
+ remaining -= minTop;
+ // Ensure bg is in the range [0, min(maxBg, remaining)]
+ final int minBg = Math.max(0, Math.min(Math.min(maxBg, remaining),
+ properties.getInt(KEY_PREFIX_MIN_BG + mConfigIdentifier,
+ mDefaultMinReservedSlots.get(WORK_TYPE_BG))));
+ mMinReservedSlots.put(WORK_TYPE_BG, minBg);
+ }
- private int mNumPendingFgJobs;
- private int mNumPendingBgJobs;
+ int getMaxTotal() {
+ return mMaxTotal;
+ }
- private int mNumStartingFgJobs;
- private int mNumStartingBgJobs;
+ int getMax(@WorkType int workType) {
+ return mMaxAllowedSlots.get(workType, mMaxTotal);
+ }
- private int mNumReservedForBg;
- private int mNumActualMaxFgJobs;
- private int mNumActualMaxBgJobs;
+ int getMinReserved(@WorkType int workType) {
+ return mMinReservedSlots.get(workType);
+ }
- void reset(int numTotalMaxJobs, int numMaxBgJobs, int numMinBgJobs) {
- mConfigNumMaxTotalJobs = numTotalMaxJobs;
- mConfigNumMaxBgJobs = numMaxBgJobs;
- mConfigNumMinBgJobs = numMinBgJobs;
+ void dump(IndentingPrintWriter pw) {
+ pw.print(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mMaxTotal).println();
+ pw.print(KEY_PREFIX_MIN_TOP + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_TOP))
+ .println();
+ pw.print(KEY_PREFIX_MAX_TOP + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_TOP))
+ .println();
+ pw.print(KEY_PREFIX_MIN_BG + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_BG))
+ .println();
+ pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG))
+ .println();
+ }
+ }
- mNumRunningFgJobs = 0;
- mNumRunningBgJobs = 0;
+ /** {@link WorkTypeConfig} for each memory trim level. */
+ static class WorkConfigLimitsPerMemoryTrimLevel {
+ public final WorkTypeConfig normal;
+ public final WorkTypeConfig moderate;
+ public final WorkTypeConfig low;
+ public final WorkTypeConfig critical;
+
+ WorkConfigLimitsPerMemoryTrimLevel(WorkTypeConfig normal, WorkTypeConfig moderate,
+ WorkTypeConfig low, WorkTypeConfig critical) {
+ this.normal = normal;
+ this.moderate = moderate;
+ this.low = low;
+ this.critical = critical;
+ }
+ }
- mNumPendingFgJobs = 0;
- mNumPendingBgJobs = 0;
+ /**
+ * This class decides, taking into account the current {@link WorkTypeConfig} and how many jobs
+ * are running/pending, how many more job can start.
+ *
+ * Extracted for testing and logging.
+ */
+ @VisibleForTesting
+ static class WorkCountTracker {
+ private int mConfigMaxTotal;
+ private final SparseIntArray mConfigNumReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
+ private final SparseIntArray mConfigAbsoluteMaxSlots = new SparseIntArray(NUM_WORK_TYPES);
+
+ /**
+ * Numbers may be lower in this than in {@link #mConfigNumReservedSlots} if there aren't
+ * enough ready jobs of a type to take up all of the desired reserved slots.
+ */
+ private final SparseIntArray mNumActuallyReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
+ private final SparseIntArray mNumPendingJobs = new SparseIntArray(NUM_WORK_TYPES);
+ private final SparseIntArray mNumRunningJobs = new SparseIntArray(NUM_WORK_TYPES);
+ private final SparseIntArray mNumStartingJobs = new SparseIntArray(NUM_WORK_TYPES);
+ private int mNumUnspecialized = 0;
+ private int mNumUnspecializedRemaining = 0;
+
+ void setConfig(@NonNull WorkTypeConfig workTypeConfig) {
+ mConfigMaxTotal = workTypeConfig.getMaxTotal();
+ mConfigNumReservedSlots.put(WORK_TYPE_TOP,
+ workTypeConfig.getMinReserved(WORK_TYPE_TOP));
+ mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
+ mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
+ mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
+
+ mNumUnspecialized = mConfigMaxTotal;
+ mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_TOP);
+ mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BG);
+ mNumUnspecialized -= mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP);
+ mNumUnspecialized -= mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG);
+ calculateUnspecializedRemaining();
+ }
- mNumStartingFgJobs = 0;
- mNumStartingBgJobs = 0;
+ private void calculateUnspecializedRemaining() {
+ mNumUnspecializedRemaining = mNumUnspecialized;
+ for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) {
+ mNumUnspecializedRemaining -= mNumRunningJobs.valueAt(i);
+ }
+ }
- mNumReservedForBg = 0;
- mNumActualMaxFgJobs = 0;
- mNumActualMaxBgJobs = 0;
+ void resetCounts() {
+ mNumActuallyReservedSlots.clear();
+ mNumPendingJobs.clear();
+ mNumRunningJobs.clear();
+ resetStagingCount();
}
- void incrementRunningJobCount(boolean isFg) {
- if (isFg) {
- mNumRunningFgJobs++;
- } else {
- mNumRunningBgJobs++;
- }
+ void resetStagingCount() {
+ mNumStartingJobs.clear();
}
- void incrementPendingJobCount(boolean isFg) {
- if (isFg) {
- mNumPendingFgJobs++;
- } else {
- mNumPendingBgJobs++;
- }
+ void incrementRunningJobCount(@WorkType int workType) {
+ mNumRunningJobs.put(workType, mNumRunningJobs.get(workType) + 1);
}
- void onStartingNewJob(boolean isFg) {
- if (isFg) {
- mNumStartingFgJobs++;
- } else {
- mNumStartingBgJobs++;
+ void incrementPendingJobCount(int workTypes) {
+ // We don't know which type we'll classify the job as when we run it yet, so make sure
+ // we have space in all applicable slots.
+ if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
+ mNumPendingJobs.put(WORK_TYPE_TOP, mNumPendingJobs.get(WORK_TYPE_TOP) + 1);
+ }
+ if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
+ mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + 1);
}
}
- void onCountDone() {
- // Note some variables are used only here but are made class members in order to have
- // them on logcat / dumpsys.
-
- // How many slots should we allocate to BG jobs at least?
- // That's basically "getMinBg()", but if there are less jobs, decrease it.
- // (e.g. even if min-bg is 2, if there's only 1 running+pending job, this has to be 1.)
- final int reservedForBg = Math.min(
- mConfigNumMinBgJobs,
- mNumRunningBgJobs + mNumPendingBgJobs);
-
- // However, if there are FG jobs already running, we have to adjust it.
- mNumReservedForBg = Math.min(reservedForBg,
- mConfigNumMaxTotalJobs - mNumRunningFgJobs);
-
- // Max FG is [total - [number needed for BG jobs]]
- // [number needed for BG jobs] is the bigger one of [running BG] or [reserved BG]
- final int maxFg =
- mConfigNumMaxTotalJobs - Math.max(mNumRunningBgJobs, mNumReservedForBg);
-
- // The above maxFg is the theoretical max. If there are less FG jobs, the actual
- // max FG will be lower accordingly.
- mNumActualMaxFgJobs = Math.min(
- maxFg,
- mNumRunningFgJobs + mNumPendingFgJobs);
-
- // Max BG is [total - actual max FG], but cap at [config max BG].
- final int maxBg = Math.min(
- mConfigNumMaxBgJobs,
- mConfigNumMaxTotalJobs - mNumActualMaxFgJobs);
-
- // If there are less BG jobs than maxBg, then reduce the actual max BG accordingly.
- // This isn't needed for the logic to work, but this will give consistent output
- // on logcat and dumpsys.
- mNumActualMaxBgJobs = Math.min(
- maxBg,
- mNumRunningBgJobs + mNumPendingBgJobs);
- }
-
- boolean canJobStart(boolean isFg) {
- if (isFg) {
- return mNumRunningFgJobs + mNumStartingFgJobs < mNumActualMaxFgJobs;
- } else {
- return mNumRunningBgJobs + mNumStartingBgJobs < mNumActualMaxBgJobs;
+ void stageJob(@WorkType int workType) {
+ final int newNumStartingJobs = mNumStartingJobs.get(workType) + 1;
+ mNumStartingJobs.put(workType, newNumStartingJobs);
+ mNumPendingJobs.put(workType, Math.max(0, mNumPendingJobs.get(workType) - 1));
+ if (newNumStartingJobs + mNumRunningJobs.get(workType)
+ > mNumActuallyReservedSlots.get(workType)) {
+ mNumUnspecializedRemaining--;
}
}
- public int getNumStartingFgJobs() {
- return mNumStartingFgJobs;
+ void onStagedJobFailed(@WorkType int workType) {
+ final int oldNumStartingJobs = mNumStartingJobs.get(workType);
+ if (oldNumStartingJobs == 0) {
+ Slog.e(TAG, "# staged jobs for " + workType + " went negative.");
+ // We are in a bad state. We will eventually recover when the pending list is
+ // regenerated.
+ return;
+ }
+ mNumStartingJobs.put(workType, oldNumStartingJobs - 1);
+ maybeAdjustReservations(workType);
}
- public int getNumStartingBgJobs() {
- return mNumStartingBgJobs;
+ private void maybeAdjustReservations(@WorkType int workType) {
+ // Always make sure we reserve the minimum number of slots in case new jobs become ready
+ // soon.
+ final int numRemainingForType = Math.max(mConfigNumReservedSlots.get(workType),
+ mNumRunningJobs.get(workType) + mNumStartingJobs.get(workType)
+ + mNumPendingJobs.get(workType));
+ if (numRemainingForType < mNumActuallyReservedSlots.get(workType)) {
+ // We've run all jobs for this type. Let another type use it now.
+ mNumActuallyReservedSlots.put(workType, numRemainingForType);
+ mNumUnspecializedRemaining++;
+ }
}
- int getTotalRunningJobCountToNote() {
- return mNumRunningFgJobs + mNumRunningBgJobs
- + mNumStartingFgJobs + mNumStartingBgJobs;
+ void onJobStarted(@WorkType int workType) {
+ mNumRunningJobs.put(workType, mNumRunningJobs.get(workType) + 1);
+ final int oldNumStartingJobs = mNumStartingJobs.get(workType);
+ if (oldNumStartingJobs == 0) {
+ Slog.e(TAG, "# stated jobs for " + workType + " went negative.");
+ // We are in a bad state. We will eventually recover when the pending list is
+ // regenerated. For now, only modify the running count.
+ } else {
+ mNumStartingJobs.put(workType, oldNumStartingJobs - 1);
+ }
}
- int getFgRunningJobCountToNote() {
- return mNumRunningFgJobs + mNumStartingFgJobs;
+ void onCountDone() {
+ // Calculate how many slots to reserve for each work type. "Unspecialized" slots will
+ // be reserved for higher importance types first (ie. top before bg).
+ mNumUnspecialized = mConfigMaxTotal;
+ final int numTop = mNumRunningJobs.get(WORK_TYPE_TOP)
+ + mNumPendingJobs.get(WORK_TYPE_TOP);
+ final int resTop = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_TOP), numTop);
+ mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop);
+ mNumUnspecialized -= resTop;
+ final int numBg = mNumRunningJobs.get(WORK_TYPE_BG) + mNumPendingJobs.get(WORK_TYPE_BG);
+ final int resBg = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BG), numBg);
+ mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg);
+ mNumUnspecialized -= resBg;
+ calculateUnspecializedRemaining();
+
+ // Assign remaining unspecialized based on ranking.
+ int unspecializedAssigned = Math.max(0,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP),
+ Math.min(mNumUnspecializedRemaining, numTop - resTop)));
+ mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop + unspecializedAssigned);
+ mNumUnspecializedRemaining -= unspecializedAssigned;
+ unspecializedAssigned = Math.max(0,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG),
+ Math.min(mNumUnspecializedRemaining, numBg - resBg)));
+ mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
+ mNumUnspecializedRemaining -= unspecializedAssigned;
}
- void logStatus() {
- if (DEBUG) {
- Slog.d(TAG, "assignJobsToContexts: " + this);
+ int canJobStart(int workTypes) {
+ if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
+ final int maxAllowed = Math.min(
+ mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP),
+ mNumActuallyReservedSlots.get(WORK_TYPE_TOP) + mNumUnspecializedRemaining);
+ if (mNumRunningJobs.get(WORK_TYPE_TOP) + mNumStartingJobs.get(WORK_TYPE_TOP)
+ < maxAllowed) {
+ return WORK_TYPE_TOP;
+ }
+ }
+ if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
+ final int maxAllowed = Math.min(
+ mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG),
+ mNumActuallyReservedSlots.get(WORK_TYPE_BG) + mNumUnspecializedRemaining);
+ if (mNumRunningJobs.get(WORK_TYPE_BG) + mNumStartingJobs.get(WORK_TYPE_BG)
+ < maxAllowed) {
+ return WORK_TYPE_BG;
+ }
}
+ return WORK_TYPE_NONE;
}
- public String toString() {
- final int totalFg = mNumRunningFgJobs + mNumStartingFgJobs;
- final int totalBg = mNumRunningBgJobs + mNumStartingBgJobs;
- return String.format(
- "Config={tot=%d bg min/max=%d/%d}"
- + " Running[FG/BG (total)]: %d / %d (%d)"
- + " Pending: %d / %d (%d)"
- + " Actual max: %d%s / %d%s (%d%s)"
- + " Res BG: %d"
- + " Starting: %d / %d (%d)"
- + " Total: %d%s / %d%s (%d%s)",
- mConfigNumMaxTotalJobs, mConfigNumMinBgJobs, mConfigNumMaxBgJobs,
-
- mNumRunningFgJobs, mNumRunningBgJobs, mNumRunningFgJobs + mNumRunningBgJobs,
-
- mNumPendingFgJobs, mNumPendingBgJobs, mNumPendingFgJobs + mNumPendingBgJobs,
-
- mNumActualMaxFgJobs, (totalFg <= mConfigNumMaxTotalJobs) ? "" : "*",
- mNumActualMaxBgJobs, (totalBg <= mConfigNumMaxBgJobs) ? "" : "*",
- mNumActualMaxFgJobs + mNumActualMaxBgJobs,
- (mNumActualMaxFgJobs + mNumActualMaxBgJobs <= mConfigNumMaxTotalJobs)
- ? "" : "*",
-
- mNumReservedForBg,
-
- mNumStartingFgJobs, mNumStartingBgJobs, mNumStartingFgJobs + mNumStartingBgJobs,
-
- totalFg, (totalFg <= mNumActualMaxFgJobs) ? "" : "*",
- totalBg, (totalBg <= mNumActualMaxBgJobs) ? "" : "*",
- totalFg + totalBg, (totalFg + totalBg <= mConfigNumMaxTotalJobs) ? "" : "*"
- );
+ int getRunningJobCount(@WorkType final int workType) {
+ return mNumRunningJobs.get(workType, 0);
}
- public void dumpProto(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
-
- proto.write(JobCountTrackerProto.CONFIG_NUM_MAX_TOTAL_JOBS, mConfigNumMaxTotalJobs);
- proto.write(JobCountTrackerProto.CONFIG_NUM_MAX_BG_JOBS, mConfigNumMaxBgJobs);
- proto.write(JobCountTrackerProto.CONFIG_NUM_MIN_BG_JOBS, mConfigNumMinBgJobs);
-
- proto.write(JobCountTrackerProto.NUM_RUNNING_FG_JOBS, mNumRunningFgJobs);
- proto.write(JobCountTrackerProto.NUM_RUNNING_BG_JOBS, mNumRunningBgJobs);
-
- proto.write(JobCountTrackerProto.NUM_PENDING_FG_JOBS, mNumPendingFgJobs);
- proto.write(JobCountTrackerProto.NUM_PENDING_BG_JOBS, mNumPendingBgJobs);
-
- proto.write(JobCountTrackerProto.NUM_ACTUAL_MAX_FG_JOBS, mNumActualMaxFgJobs);
- proto.write(JobCountTrackerProto.NUM_ACTUAL_MAX_BG_JOBS, mNumActualMaxBgJobs);
-
- proto.write(JobCountTrackerProto.NUM_RESERVED_FOR_BG, mNumReservedForBg);
-
- proto.write(JobCountTrackerProto.NUM_STARTING_FG_JOBS, mNumStartingFgJobs);
- proto.write(JobCountTrackerProto.NUM_STARTING_BG_JOBS, mNumStartingBgJobs);
-
- proto.end(token);
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Config={");
+ sb.append("tot=").append(mConfigMaxTotal);
+ sb.append(" mins=");
+ sb.append(mConfigNumReservedSlots);
+ sb.append(" maxs=");
+ sb.append(mConfigAbsoluteMaxSlots);
+ sb.append("}");
+
+ sb.append(", act res=").append(mNumActuallyReservedSlots);
+ sb.append(", Pending=").append(mNumPendingJobs);
+ sb.append(", Running=").append(mNumRunningJobs);
+ sb.append(", Staged=").append(mNumStartingJobs);
+ sb.append(", # unspecialized remaining=").append(mNumUnspecializedRemaining);
+
+ return sb.toString();
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 885662c24147..ba78bda0d2fa 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -380,7 +380,6 @@ public class JobSchedulerService extends com.android.server.SystemService
default:
if (name.startsWith(JobConcurrencyManager.CONFIG_KEY_PREFIX_CONCURRENCY)
&& !concurrencyUpdated) {
- mConstants.updateConcurrencyConstantsLocked();
mConcurrencyManager.updateConfigLocked();
concurrencyUpdated = true;
} else {
@@ -408,119 +407,6 @@ public class JobSchedulerService extends com.android.server.SystemService
mConstants.API_QUOTA_SCHEDULE_WINDOW_MS);
}
- static class MaxJobCounts {
- private final int mTotalDefault;
- private final String mTotalKey;
- private final int mMaxBgDefault;
- private final String mMaxBgKey;
- private final int mMinBgDefault;
- private final String mMinBgKey;
- private int mTotal;
- private int mMaxBg;
- private int mMinBg;
-
- MaxJobCounts(int totalDefault, String totalKey,
- int maxBgDefault, String maxBgKey, int minBgDefault, String minBgKey) {
- mTotalKey = totalKey;
- mTotal = mTotalDefault = totalDefault;
- mMaxBgKey = maxBgKey;
- mMaxBg = mMaxBgDefault = maxBgDefault;
- mMinBgKey = minBgKey;
- mMinBg = mMinBgDefault = minBgDefault;
- }
-
- public void update() {
- mTotal = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
- mTotalKey, mTotalDefault);
- mMaxBg = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
- mMaxBgKey, mMaxBgDefault);
- mMinBg = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
- mMinBgKey, mMinBgDefault);
-
- // Ensure total in the range [1, MAX_JOB_CONTEXTS_COUNT].
- mTotal = Math.min(Math.max(1, mTotal), MAX_JOB_CONTEXTS_COUNT);
-
- // Ensure maxBg in the range [1, total].
- mMaxBg = Math.min(Math.max(1, mMaxBg), mTotal);
-
- // Ensure minBg in the range [0, min(maxBg, total - 1)]
- mMinBg = Math.min(Math.max(0, mMinBg), Math.min(mMaxBg, mTotal - 1));
- }
-
- /** Total number of jobs to run simultaneously. */
- public int getMaxTotal() {
- return mTotal;
- }
-
- /** Max number of BG (== owned by non-TOP apps) jobs to run simultaneously. */
- public int getMaxBg() {
- return mMaxBg;
- }
-
- /**
- * We try to run at least this many BG (== owned by non-TOP apps) jobs, when there are any
- * pending, rather than always running the TOTAL number of FG jobs.
- */
- public int getMinBg() {
- return mMinBg;
- }
-
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix);
- pw.print(mTotalKey);
- pw.print("=");
- pw.print(mTotal);
- pw.println();
-
- pw.print(prefix);
- pw.print(mMaxBgKey);
- pw.print("=");
- pw.print(mMaxBg);
- pw.println();
-
- pw.print(prefix);
- pw.print(mMinBgKey);
- pw.print("=");
- pw.print(mMinBg);
- pw.println();
- }
-
- public void dumpProto(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
- proto.write(MaxJobCountsProto.TOTAL_JOBS, mTotal);
- proto.write(MaxJobCountsProto.MAX_BG, mMaxBg);
- proto.write(MaxJobCountsProto.MIN_BG, mMinBg);
- proto.end(token);
- }
- }
-
- /** {@link MaxJobCounts} for each memory trim level. */
- static class MaxJobCountsPerMemoryTrimLevel {
- public final MaxJobCounts normal;
- public final MaxJobCounts moderate;
- public final MaxJobCounts low;
- public final MaxJobCounts critical;
-
- MaxJobCountsPerMemoryTrimLevel(
- MaxJobCounts normal,
- MaxJobCounts moderate, MaxJobCounts low,
- MaxJobCounts critical) {
- this.normal = normal;
- this.moderate = moderate;
- this.low = low;
- this.critical = critical;
- }
-
- public void dumpProto(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
- normal.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.NORMAL);
- moderate.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.MODERATE);
- low.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.LOW);
- critical.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.CRITICAL);
- proto.end(token);
- }
- }
-
/**
* All times are in milliseconds. Any access to this class or its fields should be done while
* holding the JobSchedulerService.mLock lock.
@@ -580,49 +466,6 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
float MODERATE_USE_FACTOR = DEFAULT_MODERATE_USE_FACTOR;
- /** Prefix for all of the max_job constants. */
- private static final String KEY_PREFIX_MAX_JOB =
- JobConcurrencyManager.CONFIG_KEY_PREFIX_CONCURRENCY + "max_job_";
-
- // Max job counts for screen on / off, for each memory trim level.
- final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_ON =
- new MaxJobCountsPerMemoryTrimLevel(
- new MaxJobCounts(
- 8, KEY_PREFIX_MAX_JOB + "total_on_normal",
- 6, KEY_PREFIX_MAX_JOB + "max_bg_on_normal",
- 2, KEY_PREFIX_MAX_JOB + "min_bg_on_normal"),
- new MaxJobCounts(
- 8, KEY_PREFIX_MAX_JOB + "total_on_moderate",
- 4, KEY_PREFIX_MAX_JOB + "max_bg_on_moderate",
- 2, KEY_PREFIX_MAX_JOB + "min_bg_on_moderate"),
- new MaxJobCounts(
- 5, KEY_PREFIX_MAX_JOB + "total_on_low",
- 1, KEY_PREFIX_MAX_JOB + "max_bg_on_low",
- 1, KEY_PREFIX_MAX_JOB + "min_bg_on_low"),
- new MaxJobCounts(
- 5, KEY_PREFIX_MAX_JOB + "total_on_critical",
- 1, KEY_PREFIX_MAX_JOB + "max_bg_on_critical",
- 1, KEY_PREFIX_MAX_JOB + "min_bg_on_critical"));
-
- final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_OFF =
- new MaxJobCountsPerMemoryTrimLevel(
- new MaxJobCounts(
- 10, KEY_PREFIX_MAX_JOB + "total_off_normal",
- 6, KEY_PREFIX_MAX_JOB + "max_bg_off_normal",
- 2, KEY_PREFIX_MAX_JOB + "min_bg_off_normal"),
- new MaxJobCounts(
- 10, KEY_PREFIX_MAX_JOB + "total_off_moderate",
- 4, KEY_PREFIX_MAX_JOB + "max_bg_off_moderate",
- 2, KEY_PREFIX_MAX_JOB + "min_bg_off_moderate"),
- new MaxJobCounts(
- 5, KEY_PREFIX_MAX_JOB + "total_off_low",
- 1, KEY_PREFIX_MAX_JOB + "max_bg_off_low",
- 1, KEY_PREFIX_MAX_JOB + "min_bg_off_low"),
- new MaxJobCounts(
- 5, KEY_PREFIX_MAX_JOB + "total_off_critical",
- 1, KEY_PREFIX_MAX_JOB + "max_bg_off_critical",
- 1, KEY_PREFIX_MAX_JOB + "min_bg_off_critical"));
-
/**
* The minimum backoff time to allow for linear backoff.
*/
@@ -686,18 +529,6 @@ public class JobSchedulerService extends com.android.server.SystemService
DEFAULT_MODERATE_USE_FACTOR);
}
- void updateConcurrencyConstantsLocked() {
- MAX_JOB_COUNTS_SCREEN_ON.normal.update();
- MAX_JOB_COUNTS_SCREEN_ON.moderate.update();
- MAX_JOB_COUNTS_SCREEN_ON.low.update();
- MAX_JOB_COUNTS_SCREEN_ON.critical.update();
-
- MAX_JOB_COUNTS_SCREEN_OFF.normal.update();
- MAX_JOB_COUNTS_SCREEN_OFF.moderate.update();
- MAX_JOB_COUNTS_SCREEN_OFF.low.update();
- MAX_JOB_COUNTS_SCREEN_OFF.critical.update();
- }
-
private void updateBackoffConstantsLocked() {
MIN_LINEAR_BACKOFF_TIME_MS = DeviceConfig.getLong(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_MIN_LINEAR_BACKOFF_TIME_MS,
@@ -747,16 +578,6 @@ public class JobSchedulerService extends com.android.server.SystemService
pw.print(KEY_HEAVY_USE_FACTOR, HEAVY_USE_FACTOR).println();
pw.print(KEY_MODERATE_USE_FACTOR, MODERATE_USE_FACTOR).println();
- MAX_JOB_COUNTS_SCREEN_ON.normal.dump(pw, "");
- MAX_JOB_COUNTS_SCREEN_ON.moderate.dump(pw, "");
- MAX_JOB_COUNTS_SCREEN_ON.low.dump(pw, "");
- MAX_JOB_COUNTS_SCREEN_ON.critical.dump(pw, "");
-
- MAX_JOB_COUNTS_SCREEN_OFF.normal.dump(pw, "");
- MAX_JOB_COUNTS_SCREEN_OFF.moderate.dump(pw, "");
- MAX_JOB_COUNTS_SCREEN_OFF.low.dump(pw, "");
- MAX_JOB_COUNTS_SCREEN_OFF.critical.dump(pw, "");
-
pw.print(KEY_MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS).println();
pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
@@ -781,9 +602,6 @@ public class JobSchedulerService extends com.android.server.SystemService
proto.write(ConstantsProto.HEAVY_USE_FACTOR, HEAVY_USE_FACTOR);
proto.write(ConstantsProto.MODERATE_USE_FACTOR, MODERATE_USE_FACTOR);
- MAX_JOB_COUNTS_SCREEN_ON.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_ON);
- MAX_JOB_COUNTS_SCREEN_OFF.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_OFF);
-
proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS);
proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS);
proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 26b5abed745c..247b4211fdf9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -16,6 +16,7 @@
package com.android.server.job;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
@@ -124,9 +125,12 @@ public final class JobServiceContext implements ServiceConnection {
*
* Any reads (dereferences) not done from the handler thread must be synchronized on
* {@link #mLock}.
- * Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}.
+ * Writes can only be done from the handler thread,
+ * or {@link #executeRunnableJob(JobStatus, int)}.
*/
private JobStatus mRunningJob;
+ @JobConcurrencyManager.WorkType
+ private int mRunningJobWorkType;
private JobCallback mRunningCallback;
/** Used to store next job to run when current job is to be preempted. */
private int mPreferredUid;
@@ -181,30 +185,26 @@ public final class JobServiceContext implements ServiceConnection {
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
JobPackageTracker tracker, Looper looper) {
- this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
- }
-
- @VisibleForTesting
- JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
- JobPackageTracker tracker, JobCompletedListener completedListener, Looper looper) {
- mContext = context;
- mLock = lock;
+ mContext = service.getContext();
+ mLock = service.getLock();
mBatteryStats = batteryStats;
mJobPackageTracker = tracker;
mCallbackHandler = new JobServiceHandler(looper);
- mCompletedListener = completedListener;
+ mCompletedListener = service;
mAvailable = true;
mVerb = VERB_FINISHED;
mPreferredUid = NO_PREFERRED_UID;
}
/**
- * Give a job to this context for execution. Callers must first check {@link #getRunningJobLocked()}
+ * Give a job to this context for execution. Callers must first check {@link
+ * #getRunningJobLocked()}
* and ensure it is null to make sure this is a valid context.
+ *
* @param job The status of the job that we are going to run.
* @return True if the job is valid and is running. False if the job cannot be executed.
*/
- boolean executeRunnableJob(JobStatus job) {
+ boolean executeRunnableJob(JobStatus job, @JobConcurrencyManager.WorkType int workType) {
synchronized (mLock) {
if (!mAvailable) {
Slog.e(TAG, "Starting new runnable but context is unavailable > Error.");
@@ -214,6 +214,7 @@ public final class JobServiceContext implements ServiceConnection {
mPreferredUid = NO_PREFERRED_UID;
mRunningJob = job;
+ mRunningJobWorkType = workType;
mRunningCallback = new JobCallback();
final boolean isDeadlineExpired =
job.hasDeadlineConstraint() &&
@@ -282,6 +283,7 @@ public final class JobServiceContext implements ServiceConnection {
Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable.");
}
mRunningJob = null;
+ mRunningJobWorkType = WORK_TYPE_NONE;
mRunningCallback = null;
mParams = null;
mExecutionStartTimeElapsed = 0L;
@@ -326,6 +328,11 @@ public final class JobServiceContext implements ServiceConnection {
return mRunningJob;
}
+ @JobConcurrencyManager.WorkType
+ int getRunningJobWorkType() {
+ return mRunningJobWorkType;
+ }
+
/**
* Used only for debugging. Will return <code>"&lt;null&gt;"</code> if there is no job running.
*/
@@ -831,6 +838,7 @@ public final class JobServiceContext implements ServiceConnection {
mContext.unbindService(JobServiceContext.this);
mWakeLock = null;
mRunningJob = null;
+ mRunningJobWorkType = WORK_TYPE_NONE;
mRunningCallback = null;
mParams = null;
mVerb = VERB_FINISHED;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 09dc7d281cb4..539c3c960f2e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -305,6 +305,7 @@ public final class JobStatus {
public Network network;
public ServiceInfo serviceInfo;
+ /** The evaluated priority of the job when it started running. */
public int lastEvaluatedPriority;
// If non-null, this is work that has been enqueued for the job.
diff --git a/core/api/current.txt b/core/api/current.txt
index ec712d875323..b49e7247708c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -657,6 +657,7 @@ package android {
field @Deprecated public static final int fontProviderCerts = 16844125; // 0x101055d
field @Deprecated public static final int fontProviderPackage = 16844119; // 0x1010557
field @Deprecated public static final int fontProviderQuery = 16844113; // 0x1010551
+ field public static final int fontProviderSystemFontFamily = 16844322; // 0x1010622
field public static final int fontStyle = 16844095; // 0x101053f
field public static final int fontVariationSettings = 16844144; // 0x1010570
field public static final int fontWeight = 16844083; // 0x1010533
@@ -46182,6 +46183,7 @@ package android.view {
method @NonNull public android.graphics.Rect getBoundingRectRight();
method @NonNull public android.graphics.Rect getBoundingRectTop();
method @NonNull public java.util.List<android.graphics.Rect> getBoundingRects();
+ method @Nullable public android.graphics.Path getCutoutPath();
method public int getSafeInsetBottom();
method public int getSafeInsetLeft();
method public int getSafeInsetRight();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 0915d0763604..2b9f1712bd87 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -157,6 +157,7 @@ package android.media.session {
package android.net {
public class ConnectivityManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
}
@@ -164,6 +165,14 @@ package android.net {
method public int getResourceId();
}
+ public final class NetworkAgentConfig implements android.os.Parcelable {
+ method @Nullable public String getSubscriberId();
+ }
+
+ public static final class NetworkAgentConfig.Builder {
+ method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+ }
+
public final class NetworkCapabilities implements android.os.Parcelable {
field public static final int TRANSPORT_TEST = 7; // 0x7
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0a0f77e33ed4..214b995f0b27 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1628,8 +1628,10 @@ package android.app.usage {
package android.apphibernation {
public final class AppHibernationManager {
- method public boolean isHibernating(@NonNull String);
- method public void setHibernating(@NonNull String, boolean);
+ method public boolean isHibernatingForUser(@NonNull String);
+ method public boolean isHibernatingGlobally(@NonNull String);
+ method public void setHibernatingForUser(@NonNull String, boolean);
+ method public void setHibernatingGlobally(@NonNull String, boolean);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 09c46c2a6991..db31d08100c0 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -685,6 +685,7 @@ package android.content.pm {
method public void holdLock(android.os.IBinder, int);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+ field public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 68d3a9203f12..49f508d83f91 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5255,6 +5255,7 @@ public class Notification implements Parcelable
// We still want a time to be set but gone, such that we can show and hide it
// on demand in case it's a child notification without anything in the header
contentView.setLong(R.id.time, "setTime", mN.when != 0 ? mN.when : mN.creationTime);
+ setTextViewColorSecondary(contentView, R.id.time, p);
}
}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index afa1560420f7..e6aa7a77357c 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -47,8 +47,19 @@ per-file *Notification* = file:/packages/SystemUI/OWNERS
per-file *Zen* = file:/packages/SystemUI/OWNERS
per-file *StatusBar* = file:/packages/SystemUI/OWNERS
+# PackageManager
+per-file ApplicationPackageManager.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file InstantAppResolverService.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file LoadedApk.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file PackageDeleteObserver.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file PackageInstallObserver.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file EphemeralResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file IEphemeralResolver.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file IInstantAppResolver.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file InstantAppResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+
# ResourcesManager
-per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
+per-file ResourcesManager.java = rtmitchell@google.com, toddke@google.com
# VoiceInteraction
per-file *VoiceInteract* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d5f01499793c..1498dae764a9 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -72,6 +72,7 @@ import android.content.res.Resources;
import android.content.rollback.RollbackManagerFrameworkInitializer;
import android.debug.AdbManager;
import android.debug.IAdbManager;
+import android.graphics.GameManager;
import android.graphics.fonts.FontManager;
import android.hardware.ConsumerIrManager;
import android.hardware.ISerialManager;
@@ -1426,6 +1427,16 @@ public final class SystemServiceRegistry {
return new MediaMetricsManager(service, ctx.getUserId());
}});
+ registerService(Context.GAME_SERVICE, GameManager.class,
+ new CachedServiceFetcher<GameManager>() {
+ @Override
+ public GameManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new GameManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }
+ });
+
sInitializing = true;
try {
// Note: the following functions need to be @SystemApis, once they become mainline
diff --git a/services/core/jni/stats/PowerStatsPuller.h b/core/java/android/app/people/ConversationChannel.aidl
index db07d600d251..78df2f10c337 100644
--- a/services/core/jni/stats/PowerStatsPuller.h
+++ b/core/java/android/app/people/ConversationChannel.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
+/**
+ * Copyright (c) 2021, 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
+ * 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,
@@ -14,24 +14,6 @@
* limitations under the License.
*/
-#pragma once
-
-#include <stats_event.h>
-#include <stats_pull_atom_callback.h>
-
-namespace android {
-namespace server {
-namespace stats {
-
-/**
- * Reads hal for power.stats
- */
-class PowerStatsPuller {
-public:
- PowerStatsPuller();
- AStatsManager_PullAtomCallbackReturn Pull(int32_t atomTag, AStatsEventList* data);
-};
+package android.app.people;
-} // namespace stats
-} // namespace server
-} // namespace android
+parcelable ConversationChannel; \ No newline at end of file
diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl
index 0d12ed02f610..ebe9f60dc150 100644
--- a/core/java/android/app/people/IPeopleManager.aidl
+++ b/core/java/android/app/people/IPeopleManager.aidl
@@ -17,6 +17,7 @@
package android.app.people;
import android.app.people.ConversationStatus;
+import android.app.people.ConversationChannel;
import android.content.pm.ParceledListSlice;
import android.net.Uri;
import android.os.IBinder;
@@ -26,6 +27,13 @@ import android.os.IBinder;
* {@hide}
*/
interface IPeopleManager {
+
+ /**
+ * Returns the specified conversation from the conversations list. If the conversation can't be
+ * found, returns null.
+ */
+ ConversationChannel getConversation(in String packageName, int userId, in String shortcutId);
+
/**
* Returns the recent conversations. The conversations that have customized notification
* settings are excluded from the returned list.
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
index 8f1934c7b77a..7281d50a33a5 100644
--- a/core/java/android/apphibernation/AppHibernationManager.java
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -49,31 +49,61 @@ public final class AppHibernationManager {
}
/**
- * Returns true if the package is hibernating, false otherwise.
+ * Returns true if the package is hibernating for this context's user, false otherwise.
*
* @hide
*/
@SystemApi
- public boolean isHibernating(@NonNull String packageName) {
+ public boolean isHibernatingForUser(@NonNull String packageName) {
try {
- return mIAppHibernationService.isHibernating(packageName, mContext.getUserId());
+ return mIAppHibernationService.isHibernatingForUser(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Set whether the package is hibernating.
+ * Set whether the package is hibernating for this context's user.
*
* @hide
*/
@SystemApi
- public void setHibernating(@NonNull String packageName, boolean isHibernating) {
+ public void setHibernatingForUser(@NonNull String packageName, boolean isHibernating) {
try {
- mIAppHibernationService.setHibernating(packageName, mContext.getUserId(),
+ mIAppHibernationService.setHibernatingForUser(packageName, mContext.getUserId(),
isHibernating);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Returns true if app is hibernating globally / at the package level.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isHibernatingGlobally(@NonNull String packageName) {
+ try {
+ return mIAppHibernationService.isHibernatingGlobally(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set whether a package should be globally hibernating. This hibernates the package at a
+ * package level. User-level hibernation (e.g.. {@link #isHibernatingForUser} is independent
+ * from global hibernation.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void setHibernatingGlobally(@NonNull String packageName, boolean isHibernating) {
+ try {
+ mIAppHibernationService.setHibernatingGlobally(packageName, isHibernating);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl
index db57ecb73051..6a068ee2b147 100644
--- a/core/java/android/apphibernation/IAppHibernationService.aidl
+++ b/core/java/android/apphibernation/IAppHibernationService.aidl
@@ -21,6 +21,8 @@ package android.apphibernation;
* @hide
*/
interface IAppHibernationService {
- boolean isHibernating(String packageName, int userId);
- void setHibernating(String packageName, int userId, boolean isHibernating);
+ boolean isHibernatingForUser(String packageName, int userId);
+ void setHibernatingForUser(String packageName, int userId, boolean isHibernating);
+ boolean isHibernatingGlobally(String packageName);
+ void setHibernatingGlobally(String packageName, boolean isHibernating);
} \ No newline at end of file
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0c50446e0a4e..6a2329e5235f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5418,6 +5418,16 @@ public abstract class Context {
public static final String SPEECH_RECOGNITION_SERVICE = "speech_recognition";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.graphics.GameManager}.
+ *
+ * @see #getSystemService(String)
+ *
+ * @hide
+ */
+ public static final String GAME_SERVICE = "game";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 68792b2f47de..9ae9c25c8c08 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3385,6 +3385,7 @@ public abstract class PackageManager {
* {@link #hasSystemFeature}: This device supports HDMI-CEC.
* @hide
*/
+ @TestApi
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index fe8bf9d163c7..e6c0f6a4c2fa 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6265,6 +6265,55 @@ public class PackageParser {
}
/**
+ * Returns whether this {@code SigningDetails} has a signer in common with the provided
+ * {@code otherDetails} with the specified {@code flags} capabilities provided by this
+ * signer.
+ *
+ * <p>Note this method allows for the signing lineage to diverge, so this should only be
+ * used for instances where the only requirement is a common signer in the lineage with
+ * the specified capabilities. If the current signer of this instance is an ancestor of
+ * {@code otherDetails} then {@code true} is immediately returned since the current signer
+ * has all capabilities granted.
+ */
+ public boolean hasCommonSignerWithCapability(SigningDetails otherDetails,
+ @CertCapabilities int flags) {
+ if (this == UNKNOWN || otherDetails == UNKNOWN) {
+ return false;
+ }
+ // If either is signed with more than one signer then both must be signed by the same
+ // signers to consider the capabilities granted.
+ if (signatures.length > 1 || otherDetails.signatures.length > 1) {
+ return signaturesMatchExactly(otherDetails);
+ }
+ // The Signature class does not use the granted capabilities in the hashCode
+ // computation, so a Set can be used to check for a common signer.
+ Set<Signature> otherSignatures = new ArraySet<>();
+ if (otherDetails.hasPastSigningCertificates()) {
+ otherSignatures.addAll(Arrays.asList(otherDetails.pastSigningCertificates));
+ } else {
+ otherSignatures.addAll(Arrays.asList(otherDetails.signatures));
+ }
+ // If the current signer of this instance is an ancestor of the other than return true
+ // since all capabilities are granted to the current signer.
+ if (otherSignatures.contains(signatures[0])) {
+ return true;
+ }
+ if (hasPastSigningCertificates()) {
+ // Since the current signer was checked above and the last signature in the
+ // pastSigningCertificates is the current signer skip checking the last element.
+ for (int i = 0; i < pastSigningCertificates.length - 1; i++) {
+ if (otherSignatures.contains(pastSigningCertificates[i])) {
+ // If the caller specified multiple capabilities ensure all are set.
+ if ((pastSigningCertificates[i].getFlags() & flags) == flags) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Determines if the provided {@code oldDetails} is an ancestor of this one, and whether or
* not this one grants it the provided capability, represented by the {@code flags}
* parameter. In the event of signing certificate rotation, a package may still interact
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index 14eb11ab8863..ecd240d9e4dc 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -47,14 +47,17 @@ public class FontResourcesParser {
private final @NonNull String mProviderAuthority;
private final @NonNull String mProviderPackage;
private final @NonNull String mQuery;
+ private final @Nullable String mSystemFontFamilyName;
private final @Nullable List<List<String>> mCerts;
public ProviderResourceEntry(@NonNull String authority, @NonNull String pkg,
- @NonNull String query, @Nullable List<List<String>> certs) {
+ @NonNull String query, @Nullable List<List<String>> certs,
+ @Nullable String systemFontFamilyName) {
mProviderAuthority = authority;
mProviderPackage = pkg;
mQuery = query;
mCerts = certs;
+ mSystemFontFamilyName = systemFontFamilyName;
}
public @NonNull String getAuthority() {
@@ -69,6 +72,10 @@ public class FontResourcesParser {
return mQuery;
}
+ public @NonNull String getSystemFontFamilyName() {
+ return mSystemFontFamilyName;
+ }
+
public @Nullable List<List<String>> getCerts() {
return mCerts;
}
@@ -166,6 +173,8 @@ public class FontResourcesParser {
String providerPackage = array.getString(R.styleable.FontFamily_fontProviderPackage);
String query = array.getString(R.styleable.FontFamily_fontProviderQuery);
int certsId = array.getResourceId(R.styleable.FontFamily_fontProviderCerts, 0);
+ String systemFontFamilyName = array.getString(
+ R.styleable.FontFamily_fontProviderSystemFontFamily);
array.recycle();
if (authority != null && providerPackage != null && query != null) {
while (parser.next() != XmlPullParser.END_TAG) {
@@ -191,7 +200,13 @@ public class FontResourcesParser {
}
}
}
- return new ProviderResourceEntry(authority, providerPackage, query, certs);
+ return new ProviderResourceEntry(
+ authority,
+ providerPackage,
+ query,
+ certs,
+ systemFontFamilyName
+ );
}
List<FontFileResourceEntry> fonts = new ArrayList<>();
while (parser.next() != XmlPullParser.END_TAG) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2e45ed8504c9..ac8f9c9e62fd 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -15,7 +15,9 @@
*/
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.LISTEN;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
@@ -28,6 +30,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
@@ -4964,4 +4967,92 @@ public class ConnectivityManager {
}
return null;
}
+
+ /**
+ * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+ * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
+ * be used to request that the system provide a network without causing the network to be
+ * in the foreground.
+ *
+ * <p>This method will attempt to find the best network that matches the passed
+ * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
+ * criteria. The platform will evaluate which network is the best at its own discretion.
+ * Throughput, latency, cost per byte, policy, user preference and other considerations
+ * may be factored in the decision of what is considered the best network.
+ *
+ * <p>As long as this request is outstanding, the platform will try to maintain the best network
+ * matching this request, while always attempting to match the request to a better network if
+ * possible. If a better match is found, the platform will switch this request to the now-best
+ * network and inform the app of the newly best network by invoking
+ * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform
+ * will not try to maintain any other network than the best one currently matching the request:
+ * a network not matching any network request may be disconnected at any time.
+ *
+ * <p>For example, an application could use this method to obtain a connected cellular network
+ * even if the device currently has a data connection over Ethernet. This may cause the cellular
+ * radio to consume additional power. Or, an application could inform the system that it wants
+ * a network supporting sending MMSes and have the system let it know about the currently best
+ * MMS-supporting network through the provided {@link NetworkCallback}.
+ *
+ * <p>The status of the request can be followed by listening to the various callbacks described
+ * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be
+ * used to direct traffic to the network (although accessing some networks may be subject to
+ * holding specific permissions). Callers will learn about the specific characteristics of the
+ * network through
+ * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and
+ * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the
+ * provided {@link NetworkCallback} will only be invoked due to changes in the best network
+ * matching the request at any given time; therefore when a better network matching the request
+ * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called
+ * with the new network after which no further updates are given about the previously-best
+ * network, unless it becomes the best again at some later time. All callbacks are invoked
+ * in order on the same thread, which by default is a thread created by the framework running
+ * in the app.
+ *
+ * <p>This{@link NetworkRequest} will live until released via
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at
+ * which point the system may let go of the network at any time.
+ *
+ * <p>It is presently unsupported to request a network with mutable
+ * {@link NetworkCapabilities} such as
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+ * as these {@code NetworkCapabilities} represent states that a particular
+ * network may never attain, and whether a network will attain these states
+ * is unknown prior to bringing up the network so the framework does not
+ * know how to go about satisfying a request with these capabilities.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #registerNetworkCallback} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * If null, the callback is invoked on the default internal Handler.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @SuppressLint("ExecutorRegistration")
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public void requestBackgroundNetwork(@NonNull NetworkRequest request,
+ @Nullable Handler handler, @NonNull NetworkCallback networkCallback) {
+ final NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
+ TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 719783163ab9..1b4d2e413943 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -31,7 +31,6 @@ import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ProxyInfo;
import android.net.UidRange;
-import android.net.VpnInfo;
import android.net.QosSocketInfo;
import android.os.Bundle;
import android.os.IBinder;
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index d5aede71011f..0baf11e850c7 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -23,7 +23,7 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.IBinder;
@@ -70,7 +70,7 @@ interface INetworkStatsService {
in Network[] defaultNetworks,
in NetworkState[] networkStates,
in String activeIface,
- in VpnInfo[] vpnInfos);
+ in UnderlyingNetworkInfo[] underlyingNetworkInfos);
/** Force update of statistics. */
@UnsupportedAppUsage
void forceUpdate();
diff --git a/core/java/android/net/MatchAllNetworkSpecifier.java b/core/java/android/net/MatchAllNetworkSpecifier.java
index 84985b6584c8..9a11be00663b 100644
--- a/core/java/android/net/MatchAllNetworkSpecifier.java
+++ b/core/java/android/net/MatchAllNetworkSpecifier.java
@@ -32,17 +32,6 @@ import android.os.Parcelable;
*/
@SystemApi
public final class MatchAllNetworkSpecifier extends NetworkSpecifier implements Parcelable {
- /**
- * Utility method which verifies that the ns argument is not a MatchAllNetworkSpecifier and
- * throws an IllegalArgumentException if it is.
- * @hide
- */
- public static void checkNotMatchAllNetworkSpecifier(NetworkSpecifier ns) {
- if (ns instanceof MatchAllNetworkSpecifier) {
- throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
- }
- }
-
/** @hide */
@Override
public boolean canBeSatisfiedBy(NetworkSpecifier other) {
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
index fe1268d79b89..664c2650ff0c 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -125,6 +127,7 @@ public final class NetworkAgentConfig implements Parcelable {
* @return the subscriber ID, or null if none.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
@Nullable
public String getSubscriberId() {
return subscriberId;
@@ -275,6 +278,7 @@ public final class NetworkAgentConfig implements Parcelable {
* @hide
*/
@NonNull
+ @SystemApi(client = MODULE_LIBRARIES)
public Builder setSubscriberId(@Nullable String subscriberId) {
mConfig.subscriberId = subscriberId;
return this;
diff --git a/core/java/android/net/VpnInfo.aidl b/core/java/android/net/UnderlyingNetworkInfo.aidl
index 8bcaa81f3992..a56f2f40583b 100644
--- a/core/java/android/net/VpnInfo.aidl
+++ b/core/java/android/net/UnderlyingNetworkInfo.aidl
@@ -16,4 +16,4 @@
package android.net;
-parcelable VpnInfo;
+parcelable UnderlyingNetworkInfo;
diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java
new file mode 100644
index 000000000000..8fb4832e06c8
--- /dev/null
+++ b/core/java/android/net/UnderlyingNetworkInfo.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 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.net;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A lightweight container used to carry information on the networks that underly a given
+ * virtual network.
+ *
+ * @hide
+ */
+public final class UnderlyingNetworkInfo implements Parcelable {
+ /** The owner of this network. */
+ public final int ownerUid;
+ /** The interface name of this network. */
+ @NonNull
+ public final String iface;
+ /** The names of the interfaces underlying this network. */
+ @NonNull
+ public final List<String> underlyingIfaces;
+
+ public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface,
+ @NonNull List<String> underlyingIfaces) {
+ Objects.requireNonNull(iface);
+ Objects.requireNonNull(underlyingIfaces);
+ this.ownerUid = ownerUid;
+ this.iface = iface;
+ this.underlyingIfaces = underlyingIfaces;
+ }
+
+ private UnderlyingNetworkInfo(@NonNull Parcel in) {
+ this.ownerUid = in.readInt();
+ this.iface = in.readString();
+ this.underlyingIfaces = new ArrayList<>();
+ in.readList(this.underlyingIfaces, null /*classLoader*/);
+ }
+
+ @Override
+ public String toString() {
+ return "UnderlyingNetworkInfo{"
+ + "ownerUid=" + ownerUid
+ + ", iface='" + iface + '\''
+ + ", underlyingIfaces='" + underlyingIfaces.toString() + '\''
+ + '}';
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(ownerUid);
+ dest.writeString(iface);
+ dest.writeList(underlyingIfaces);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<UnderlyingNetworkInfo> CREATOR =
+ new Parcelable.Creator<UnderlyingNetworkInfo>() {
+ @NonNull
+ @Override
+ public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) {
+ return new UnderlyingNetworkInfo(in);
+ }
+
+ @NonNull
+ @Override
+ public UnderlyingNetworkInfo[] newArray(int size) {
+ return new UnderlyingNetworkInfo[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof UnderlyingNetworkInfo)) return false;
+ final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o;
+ return ownerUid == that.ownerUid
+ && Objects.equals(iface, that.iface)
+ && Objects.equals(underlyingIfaces, that.underlyingIfaces);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ownerUid, iface, underlyingIfaces);
+ }
+}
diff --git a/core/java/android/net/VpnInfo.java b/core/java/android/net/VpnInfo.java
deleted file mode 100644
index cf58c570f21f..000000000000
--- a/core/java/android/net/VpnInfo.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2015 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.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * A lightweight container used to carry information of the ongoing VPN.
- * Internal use only.
- *
- * @hide
- */
-public class VpnInfo implements Parcelable {
- public final int ownerUid;
- @Nullable
- public final String vpnIface;
- @Nullable
- public final String[] underlyingIfaces;
-
- public VpnInfo(int ownerUid, @Nullable String vpnIface, @Nullable String[] underlyingIfaces) {
- this.ownerUid = ownerUid;
- this.vpnIface = vpnIface;
- this.underlyingIfaces = underlyingIfaces;
- }
-
- private VpnInfo(@NonNull Parcel in) {
- this.ownerUid = in.readInt();
- this.vpnIface = in.readString();
- this.underlyingIfaces = in.createStringArray();
- }
-
- @Override
- public String toString() {
- return "VpnInfo{"
- + "ownerUid=" + ownerUid
- + ", vpnIface='" + vpnIface + '\''
- + ", underlyingIfaces='" + Arrays.toString(underlyingIfaces) + '\''
- + '}';
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(ownerUid);
- dest.writeString(vpnIface);
- dest.writeStringArray(underlyingIfaces);
- }
-
- @NonNull
- public static final Parcelable.Creator<VpnInfo> CREATOR = new Parcelable.Creator<VpnInfo>() {
- @NonNull
- @Override
- public VpnInfo createFromParcel(@NonNull Parcel in) {
- return new VpnInfo(in);
- }
-
- @NonNull
- @Override
- public VpnInfo[] newArray(int size) {
- return new VpnInfo[size];
- }
- };
-}
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 80ac64b87d4d..4f293eeb3c3b 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -16,8 +16,11 @@
package android.net.vcn;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.os.ParcelUuid;
/**
@@ -29,4 +32,5 @@ interface IVcnManagementService {
void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
+ VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp);
}
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 2d0a6d74cb86..33beb6a9d188 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -21,6 +21,8 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -62,7 +64,7 @@ import java.util.concurrent.Executor;
* @hide
*/
@SystemService(Context.VCN_MANAGEMENT_SERVICE)
-public final class VcnManager {
+public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
/** @hide */
@@ -223,6 +225,37 @@ public final class VcnManager {
}
/**
+ * Queries the underlying network policy for a network with the given parameters.
+ *
+ * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
+ * may have changed via {@link VcnUnderlyingNetworkPolicyListener#onPolicyChanged()}, a Network
+ * Provider MUST poll for the updated Network policy based on that Network's capabilities and
+ * properties.
+ *
+ * @param networkCapabilities the NetworkCapabilities to be used in determining the Network
+ * policy for this Network.
+ * @param linkProperties the LinkProperties to be used in determining the Network policy for
+ * this Network.
+ * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+ * @return the VcnUnderlyingNetworkPolicy to be used for this Network.
+ * @hide
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties) {
+ requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+ requireNonNull(linkProperties, "linkProperties must not be null");
+
+ try {
+ return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
* Server.
*
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 71344f90de75..f853e67f87d0 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -288,6 +288,20 @@ public final class ServiceManager {
}
/**
+ * Get service debug info.
+ * @return an array of information for each service (like listServices, but with PIDs)
+ * @hide
+ */
+ public static ServiceDebugInfo[] getServiceDebugInfo() {
+ try {
+ return getIServiceManager().getServiceDebugInfo();
+ } catch (RemoteException e) {
+ Log.e(TAG, "error in getServiceDebugInfo", e);
+ return null;
+ }
+ }
+
+ /**
* This is only intended to be called when the process is first being brought
* up and bound by the activity manager. There is only one thread in the process
* at that time, so no locking is done.
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index b70b6b5d209e..60acc57d0cfe 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -103,6 +103,10 @@ class ServiceManagerProxy implements IServiceManager {
throw new RemoteException();
}
+ public ServiceDebugInfo[] getServiceDebugInfo() throws RemoteException {
+ return mServiceManager.getServiceDebugInfo();
+ }
+
/**
* Same as mServiceManager but used by apps.
*
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 7db5a80b6cf9..3fbc28402405 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -38,14 +38,20 @@ interface IIncrementalService {
* Opens or creates a storage given a target path and data loader params. Returns the storage ID.
*/
int openStorage(in @utf8InCpp String path);
- int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, int createMode,
- in IDataLoaderStatusListener statusListener,
- in StorageHealthCheckParams healthCheckParams,
- in IStorageHealthListener healthListener,
- in PerUidReadTimeouts[] perUidReadTimeouts);
+ int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, int createMode);
int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
/**
+ * Loops DataLoader through bind/create/start with params.
+ */
+ boolean startLoading(int storageId,
+ in DataLoaderParamsParcel params,
+ in IDataLoaderStatusListener statusListener,
+ in StorageHealthCheckParams healthCheckParams,
+ in IStorageHealthListener healthListener,
+ in PerUidReadTimeouts[] perUidReadTimeouts);
+
+ /**
* Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
*/
const int BIND_TEMPORARY = 0;
@@ -101,6 +107,14 @@ interface IIncrementalService {
int isFileFullyLoaded(int storageId, in @utf8InCpp String path);
/**
+ * Checks if all files in the storage are fully loaded.
+ * 0 - fully loaded
+ * >0 - certain pages missing
+ * <0 - -errcode
+ */
+ int isFullyLoaded(int storageId);
+
+ /**
* Returns overall loading progress of all the files on a storage, progress value between [0,1].
* Returns a negative value on error.
*/
@@ -113,11 +127,6 @@ interface IIncrementalService {
byte[] getMetadataById(int storageId, in byte[] fileId);
/**
- * Starts loading data for a storage.
- */
- boolean startLoading(int storageId);
-
- /**
* Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
*/
void deleteStorage(int storageId);
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 59292baa110c..f2fe71913bb1 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -37,7 +37,6 @@ import android.content.Context;
import android.content.pm.DataLoaderParams;
import android.content.pm.IDataLoaderStatusListener;
import android.content.pm.InstallationFileParcel;
-import android.text.TextUtils;
import java.io.File;
import java.io.IOException;
@@ -53,6 +52,7 @@ public final class IncrementalFileStorages {
private @NonNull final IncrementalManager mIncrementalManager;
private @NonNull final File mStageDir;
+ private @Nullable IncrementalStorage mInheritedStorage;
private @Nullable IncrementalStorage mDefaultStorage;
/**
@@ -65,6 +65,7 @@ public final class IncrementalFileStorages {
*/
public static IncrementalFileStorages initialize(Context context,
@NonNull File stageDir,
+ @Nullable File inheritedDir,
@NonNull DataLoaderParams dataLoaderParams,
@Nullable IDataLoaderStatusListener statusListener,
@Nullable StorageHealthCheckParams healthCheckParams,
@@ -79,9 +80,8 @@ public final class IncrementalFileStorages {
throw new IOException("Failed to obtain incrementalManager.");
}
- final IncrementalFileStorages result = new IncrementalFileStorages(stageDir,
- incrementalManager, dataLoaderParams, statusListener, healthCheckParams,
- healthListener, perUidReadTimeouts);
+ final IncrementalFileStorages result = new IncrementalFileStorages(stageDir, inheritedDir,
+ incrementalManager, dataLoaderParams);
for (InstallationFileParcel file : addedFiles) {
if (file.location == LOCATION_DATA_APP) {
try {
@@ -95,43 +95,46 @@ public final class IncrementalFileStorages {
throw new IOException("Unknown file location: " + file.location);
}
}
-
- result.startLoading();
+ result.startLoading(dataLoaderParams, statusListener, healthCheckParams, healthListener,
+ perUidReadTimeouts);
return result;
}
private IncrementalFileStorages(@NonNull File stageDir,
+ @Nullable File inheritedDir,
@NonNull IncrementalManager incrementalManager,
- @NonNull DataLoaderParams dataLoaderParams,
- @Nullable IDataLoaderStatusListener statusListener,
- @Nullable StorageHealthCheckParams healthCheckParams,
- @Nullable IStorageHealthListener healthListener,
- @NonNull PerUidReadTimeouts[] perUidReadTimeouts) throws IOException {
+ @NonNull DataLoaderParams dataLoaderParams) throws IOException {
try {
mStageDir = stageDir;
mIncrementalManager = incrementalManager;
- if (dataLoaderParams.getComponentName().getPackageName().equals("local")) {
- final String incrementalPath = dataLoaderParams.getArguments();
- if (TextUtils.isEmpty(incrementalPath)) {
- throw new IOException("Failed to create storage: incrementalPath is empty");
- }
- mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
- if (mDefaultStorage == null) {
- throw new IOException(
- "Couldn't open incremental storage at " + incrementalPath);
- }
- mDefaultStorage.bind(stageDir.getAbsolutePath());
- } else {
- mDefaultStorage = mIncrementalManager.createStorage(stageDir.getAbsolutePath(),
- dataLoaderParams, IncrementalManager.CREATE_MODE_CREATE
- | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false,
- statusListener, healthCheckParams, healthListener, perUidReadTimeouts);
- if (mDefaultStorage == null) {
- throw new IOException(
- "Couldn't create incremental storage at " + stageDir);
+ if (inheritedDir != null && IncrementalManager.isIncrementalPath(
+ inheritedDir.getAbsolutePath())) {
+ mInheritedStorage = mIncrementalManager.openStorage(
+ inheritedDir.getAbsolutePath());
+ if (mInheritedStorage != null) {
+ if (!mInheritedStorage.isFullyLoaded()) {
+ throw new IOException("Inherited storage has missing pages.");
+ }
+
+ mDefaultStorage = mIncrementalManager.createStorage(stageDir.getAbsolutePath(),
+ mInheritedStorage, IncrementalManager.CREATE_MODE_CREATE
+ | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
+ if (mDefaultStorage == null) {
+ throw new IOException(
+ "Couldn't create linked incremental storage at " + stageDir);
+ }
+ return;
}
}
+
+ mDefaultStorage = mIncrementalManager.createStorage(stageDir.getAbsolutePath(),
+ dataLoaderParams, IncrementalManager.CREATE_MODE_CREATE
+ | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
+ if (mDefaultStorage == null) {
+ throw new IOException(
+ "Couldn't create incremental storage at " + stageDir);
+ }
} catch (IOException e) {
cleanUp();
throw e;
@@ -149,9 +152,16 @@ public final class IncrementalFileStorages {
/**
* Starts or re-starts loading of data.
*/
- public void startLoading() throws IOException {
- if (!mDefaultStorage.startLoading()) {
- throw new IOException("Failed to start loading data for Incremental installation.");
+ void startLoading(
+ @NonNull DataLoaderParams dataLoaderParams,
+ @Nullable IDataLoaderStatusListener statusListener,
+ @Nullable StorageHealthCheckParams healthCheckParams,
+ @Nullable IStorageHealthListener healthListener,
+ @NonNull PerUidReadTimeouts[] perUidReadTimeouts) throws IOException {
+ if (!mDefaultStorage.startLoading(dataLoaderParams, statusListener, healthCheckParams,
+ healthListener, perUidReadTimeouts)) {
+ throw new IOException(
+ "Failed to start or restart loading data for Incremental installation.");
}
}
@@ -163,6 +173,21 @@ public final class IncrementalFileStorages {
}
/**
+ * Creates a hardlink from inherited storage to default.
+ */
+ public boolean makeLink(@NonNull String relativePath, @NonNull String fromBase,
+ @NonNull String toBase) throws IOException {
+ if (mInheritedStorage == null) {
+ return false;
+ }
+ final File sourcePath = new File(fromBase, relativePath);
+ final File destPath = new File(toBase, relativePath);
+ mInheritedStorage.makeLink(sourcePath.getAbsolutePath(), mDefaultStorage,
+ destPath.getAbsolutePath());
+ return true;
+ }
+
+ /**
* Permanently disables readlogs.
*/
public void disallowReadLogs() {
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 4b9327021cb0..7e7057fe56cb 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.Context;
import android.content.pm.DataLoaderParams;
-import android.content.pm.IDataLoaderStatusListener;
import android.content.pm.IPackageLoadingProgressCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -95,32 +94,20 @@ public final class IncrementalManager {
* @param params IncrementalDataLoaderParams object to configure data loading.
* @param createMode Mode for opening an old Incremental File System mount or creating
* a new mount.
- * @param autoStartDataLoader Set true to immediately start data loader after creating storage.
* @return IncrementalStorage object corresponding to the mounted directory.
*/
@Nullable
public IncrementalStorage createStorage(@NonNull String path,
@NonNull DataLoaderParams params,
- @CreateMode int createMode,
- boolean autoStartDataLoader,
- @Nullable IDataLoaderStatusListener statusListener,
- @Nullable StorageHealthCheckParams healthCheckParams,
- @Nullable IStorageHealthListener healthListener,
- @NonNull PerUidReadTimeouts[] perUidReadTimeouts) {
+ @CreateMode int createMode) {
Objects.requireNonNull(path);
Objects.requireNonNull(params);
- Objects.requireNonNull(perUidReadTimeouts);
try {
- final int id = mService.createStorage(path, params.getData(), createMode,
- statusListener, healthCheckParams, healthListener, perUidReadTimeouts);
+ final int id = mService.createStorage(path, params.getData(), createMode);
if (id < 0) {
return null;
}
- final IncrementalStorage storage = new IncrementalStorage(mService, id);
- if (autoStartDataLoader) {
- storage.startLoading();
- }
- return storage;
+ return new IncrementalStorage(mService, id);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -281,15 +268,18 @@ public final class IncrementalManager {
* Unbinds the target dir and deletes the corresponding storage instance.
* Deletes the package name and associated storage id from maps.
*/
- public void onPackageRemoved(@NonNull String codePath) {
+ public void onPackageRemoved(@NonNull File codeFile) {
try {
+ final String codePath = codeFile.getAbsolutePath();
final IncrementalStorage storage = openStorage(codePath);
if (storage == null) {
return;
}
mLoadingProgressCallbacks.cleanUpCallbacks(storage);
unregisterHealthListener(codePath);
- mService.deleteStorage(storage.getId());
+
+ // Parent since we bind-mount a folder one level above.
+ mService.deleteBindMount(storage.getId(), codeFile.getParent());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 5b688bbd0655..e6ce8cd56d28 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -18,11 +18,14 @@ package android.os.incremental;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.DataLoaderParams;
+import android.content.pm.IDataLoaderStatusListener;
import android.os.RemoteException;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Objects;
import java.util.UUID;
/**
@@ -323,6 +326,24 @@ public final class IncrementalStorage {
}
}
+
+ /**
+ * Checks if all files in the storage are fully loaded.
+ */
+ public boolean isFullyLoaded() throws IOException {
+ try {
+ final int res = mService.isFullyLoaded(mId);
+ if (res < 0) {
+ throw new IOException(
+ "isFullyLoaded() failed at querying loading progress, errno " + -res);
+ }
+ return res == 0;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
+ }
+
/**
* Returns the loading progress of a storage
*
@@ -376,13 +397,21 @@ public final class IncrementalStorage {
}
/**
- * Informs the data loader service associated with the current storage to start data loader
- *
- * @return True if data loader is successfully started.
+ * Iinitializes and starts the DataLoader.
+ * This makes sure all install-time parameters are applied.
+ * Does not affect persistent DataLoader params.
+ * @return True if start request was successfully queued.
*/
- public boolean startLoading() {
+ public boolean startLoading(
+ @NonNull DataLoaderParams dataLoaderParams,
+ @Nullable IDataLoaderStatusListener statusListener,
+ @Nullable StorageHealthCheckParams healthCheckParams,
+ @Nullable IStorageHealthListener healthListener,
+ @NonNull PerUidReadTimeouts[] perUidReadTimeouts) {
+ Objects.requireNonNull(perUidReadTimeouts);
try {
- return mService.startLoading(mId);
+ return mService.startLoading(mId, dataLoaderParams.getData(), statusListener,
+ healthCheckParams, healthListener, perUidReadTimeouts);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return false;
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index b1b29254783c..85e9fdb9a9d1 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -28,7 +28,10 @@ import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
import static android.app.AppOpsManager.opToPermission;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED;
+import static android.media.AudioSystem.MODE_IN_COMMUNICATION;
+import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+import android.Manifest;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.ComponentName;
@@ -41,12 +44,14 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.icu.text.ListFormatter;
import android.location.LocationManager;
+import android.media.AudioManager;
import android.os.Process;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.speech.RecognitionService;
import android.speech.RecognizerIntent;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.inputmethod.InputMethodInfo;
@@ -75,6 +80,9 @@ public class PermissionUsageHelper {
private static final String PROPERTY_LOCATION_INDICATORS_ENABLED =
"location_indicators_enabled";
+ /** Whether to show the Permissions Hub. */
+ private static final String PROPERTY_PERMISSIONS_HUB_2_ENABLED = "permissions_hub_2_enabled";
+
/** How long after an access to show it as "recent" */
private static final String RECENT_ACCESS_TIME_MS = "recent_acccess_time_ms";
@@ -84,17 +92,25 @@ public class PermissionUsageHelper {
/** The name of the expected voice IME subtype */
private static final String VOICE_IME_SUBTYPE = "voice";
+ private static final String SYSTEM_PKG = "android";
+
private static final long DEFAULT_RUNNING_TIME_MS = 5000L;
- private static final long DEFAULT_RECENT_TIME_MS = 30000L;
+ private static final long DEFAULT_RECENT_TIME_MS = 15000L;
+
+ private static boolean shouldShowPermissionsHub() {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_PERMISSIONS_HUB_2_ENABLED, false);
+ }
private static boolean shouldShowIndicators() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_CAMERA_MIC_ICONS_ENABLED, true);
+ PROPERTY_CAMERA_MIC_ICONS_ENABLED, true) || shouldShowPermissionsHub();
}
private static boolean shouldShowLocationIndicator() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_LOCATION_INDICATORS_ENABLED, false);
+ PROPERTY_LOCATION_INDICATORS_ENABLED, false)
+ || shouldShowPermissionsHub();
}
private static long getRecentThreshold(Long now) {
@@ -113,7 +129,7 @@ public class PermissionUsageHelper {
);
private static final List<String> MIC_OPS = List.of(
- OPSTR_PHONE_CALL_CAMERA,
+ OPSTR_PHONE_CALL_MICROPHONE,
OPSTR_RECORD_AUDIO
);
@@ -163,6 +179,13 @@ public class PermissionUsageHelper {
return mUserContexts.get(user);
}
+ // TODO ntmyren: Replace this with better check if this moves beyond teamfood
+ private boolean isAppPredictor(String packageName, UserHandle user) {
+ return shouldShowPermissionsHub() && getUserContext(user).getPackageManager()
+ .checkPermission(Manifest.permission.MANAGE_APP_PREDICTIONS, packageName)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
/**
* @see PermissionManager.getIndicatorAppOpUsageData
*/
@@ -186,7 +209,28 @@ public class PermissionUsageHelper {
Map<PackageAttribution, CharSequence> packagesWithAttributionLabels =
getTrustedAttributions(rawUsages.get(MICROPHONE), proxyChains);
- List<String> usedPermGroups = new ArrayList<>(rawUsages.keySet());
+ ArrayList<String> usedPermGroups = new ArrayList<>(rawUsages.keySet());
+
+ // If we have a phone call, and a carrier privileged app using microphone, hide the
+ // phone call.
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ boolean hasPhoneCall = usedPermGroups.contains(OPSTR_PHONE_CALL_CAMERA)
+ || usedPermGroups.contains(OPSTR_PHONE_CALL_MICROPHONE);
+ if (hasPhoneCall && usedPermGroups.contains(MICROPHONE) && audioManager.getMode()
+ == MODE_IN_COMMUNICATION) {
+ TelephonyManager telephonyManager =
+ mContext.getSystemService(TelephonyManager.class);
+ List<OpUsage> permUsages = rawUsages.get(MICROPHONE);
+ for (int usageNum = 0; usageNum < permUsages.size(); usageNum++) {
+ if (telephonyManager.checkCarrierPrivilegesForPackage(
+ permUsages.get(usageNum).packageName)
+ == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ usedPermGroups.remove(OPSTR_PHONE_CALL_CAMERA);
+ usedPermGroups.remove(OPSTR_PHONE_CALL_MICROPHONE);
+ }
+ }
+ }
+
for (int permGroupNum = 0; permGroupNum < usedPermGroups.size(); permGroupNum++) {
boolean isPhone = false;
String permGroup = usedPermGroups.get(permGroupNum);
@@ -269,8 +313,11 @@ public class PermissionUsageHelper {
if (lastAccessTime < recentThreshold && !attrOpEntry.isRunning()) {
continue;
}
- if (!isUserSensitive(packageName, user, op)
- && !isLocationProvider(packageName, user)) {
+
+ if (packageName.equals(SYSTEM_PKG)
+ || (!isUserSensitive(packageName, user, op)
+ && !isLocationProvider(packageName, user)
+ && !isAppPredictor(packageName, user))) {
continue;
}
diff --git a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
index 7f8158f433be..dc0718a13fbc 100644
--- a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
@@ -18,8 +18,6 @@ package android.service.voice;
import android.os.Bundle;
-import android.service.voice.IVoiceInteractionSession;
-
/**
* @hide
*/
diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java
index 424ff9def41c..8300343d03b6 100644
--- a/core/java/android/service/voice/VoiceInteractionSessionService.java
+++ b/core/java/android/service/voice/VoiceInteractionSessionService.java
@@ -21,11 +21,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.Log;
+
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
@@ -38,6 +41,8 @@ import java.io.PrintWriter;
*/
public abstract class VoiceInteractionSessionService extends Service {
+ private static final String TAG = "VoiceInteractionSession";
+
static final int MSG_NEW_SESSION = 1;
IVoiceInteractionManagerService mSystemService;
@@ -120,10 +125,22 @@ public abstract class VoiceInteractionSessionService extends Service {
mSession = null;
}
mSession = onNewSession(args);
- try {
- mSystemService.deliverNewSession(token, mSession.mSession, mSession.mInteractor);
+ if (deliverSession(token)) {
mSession.doCreate(mSystemService, token);
+ } else {
+ // TODO(b/178777121): Add an onError() method to let the application know what happened.
+ mSession.doDestroy();
+ mSession = null;
+ }
+ }
+
+ private boolean deliverSession(IBinder token) {
+ try {
+ return mSystemService.deliverNewSession(token, mSession.mSession, mSession.mInteractor);
+ } catch (DeadObjectException ignored) {
} catch (RemoteException e) {
+ Log.e(TAG, "Failed to deliver session: " + e);
}
+ return false;
}
}
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
index a44ed59c14d4..698cb77947cf 100644
--- a/core/java/android/util/RotationUtils.java
+++ b/core/java/android/util/RotationUtils.java
@@ -21,7 +21,9 @@ import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import android.annotation.Dimension;
import android.graphics.Insets;
+import android.graphics.Matrix;
import android.view.Surface.Rotation;
/**
@@ -69,4 +71,34 @@ public class RotationUtils {
}
return rotated;
}
+
+ /**
+ * Sets a matrix such that given a rotation, it transforms physical display
+ * coordinates to that rotation's logical coordinates.
+ *
+ * @param rotation the rotation to which the matrix should transform
+ * @param out the matrix to be set
+ */
+ public static void transformPhysicalToLogicalCoordinates(@Rotation int rotation,
+ @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
+ switch (rotation) {
+ case ROTATION_0:
+ out.reset();
+ break;
+ case ROTATION_90:
+ out.setRotate(270);
+ out.postTranslate(0, physicalWidth);
+ break;
+ case ROTATION_180:
+ out.setRotate(180);
+ out.postTranslate(physicalWidth, physicalHeight);
+ break;
+ case ROTATION_270:
+ out.setRotate(90);
+ out.postTranslate(physicalHeight, 0);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown rotation: " + rotation);
+ }
+ }
}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 525ac534612d..e1a4402d8964 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -23,6 +23,7 @@ import static android.view.DisplayCutoutProto.BOUND_LEFT;
import static android.view.DisplayCutoutProto.BOUND_RIGHT;
import static android.view.DisplayCutoutProto.BOUND_TOP;
import static android.view.DisplayCutoutProto.INSETS;
+import static android.view.Surface.ROTATION_0;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
@@ -31,13 +32,16 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Insets;
+import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Pair;
+import android.util.RotationUtils;
import android.util.proto.ProtoOutputStream;
+import android.view.Surface.Rotation;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -69,6 +73,9 @@ public final class DisplayCutout {
"com.android.internal.display_cutout_emulation";
private static final Rect ZERO_RECT = new Rect();
+ private static final CutoutPathParserInfo EMPTY_PARSER_INFO = new CutoutPathParserInfo(
+ 0 /* displayWidth */, 0 /* displayHeight */, 0f /* density */, "" /* cutoutSpec */,
+ 0 /* rotation */, 0f /* scale */);
/**
* An instance where {@link #isEmpty()} returns {@code true}.
@@ -76,7 +83,7 @@ public final class DisplayCutout {
* @hide
*/
public static final DisplayCutout NO_CUTOUT = new DisplayCutout(
- ZERO_RECT, Insets.NONE, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT,
+ ZERO_RECT, Insets.NONE, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT, EMPTY_PARSER_INFO,
false /* copyArguments */);
@@ -96,11 +103,15 @@ public final class DisplayCutout {
@GuardedBy("CACHE_LOCK")
private static Insets sCachedWaterfallInsets;
+ @GuardedBy("CACHE_LOCK")
+ private static CutoutPathParserInfo sCachedCutoutPathParserInfo;
+ @GuardedBy("CACHE_LOCK")
+ private static Path sCachedCutoutPath;
+
private final Rect mSafeInsets;
@NonNull
private final Insets mWaterfallInsets;
-
/**
* The bound is at the left of the screen.
* @hide
@@ -210,6 +221,7 @@ public final class DisplayCutout {
}
return result;
}
+
@Override
public boolean equals(@Nullable Object o) {
if (o == this) {
@@ -232,6 +244,106 @@ public final class DisplayCutout {
private final Bounds mBounds;
/**
+ * Stores all the needed info to create the cutout paths.
+ *
+ * @hide
+ */
+ public static class CutoutPathParserInfo {
+ private final int mDisplayWidth;
+ private final int mDisplayHeight;
+ private final float mDensity;
+ private final String mCutoutSpec;
+ private final @Rotation int mRotation;
+ private final float mScale;
+
+ public CutoutPathParserInfo(int displayWidth, int displayHeight, float density,
+ String cutoutSpec, @Rotation int rotation, float scale) {
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ mDensity = density;
+ mCutoutSpec = cutoutSpec == null ? "" : cutoutSpec;
+ mRotation = rotation;
+ mScale = scale;
+ }
+
+ public CutoutPathParserInfo(CutoutPathParserInfo cutoutPathParserInfo) {
+ mDisplayWidth = cutoutPathParserInfo.mDisplayWidth;
+ mDisplayHeight = cutoutPathParserInfo.mDisplayHeight;
+ mDensity = cutoutPathParserInfo.mDensity;
+ mCutoutSpec = cutoutPathParserInfo.mCutoutSpec;
+ mRotation = cutoutPathParserInfo.mRotation;
+ mScale = cutoutPathParserInfo.mScale;
+ }
+
+ public int getDisplayWidth() {
+ return mDisplayWidth;
+ }
+
+ public int getDisplayHeight() {
+ return mDisplayHeight;
+ }
+
+ public float getDensity() {
+ return mDensity;
+ }
+
+ public @NonNull String getCutoutSpec() {
+ return mCutoutSpec;
+ }
+
+ public int getRotation() {
+ return mRotation;
+ }
+
+ public float getScale() {
+ return mScale;
+ }
+
+ private boolean hasCutout() {
+ return !mCutoutSpec.isEmpty();
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 0;
+ result = result * 48271 + Integer.hashCode(mDisplayWidth);
+ result = result * 48271 + Integer.hashCode(mDisplayHeight);
+ result = result * 48271 + Float.hashCode(mDensity);
+ result = result * 48271 + mCutoutSpec.hashCode();
+ result = result * 48271 + Integer.hashCode(mRotation);
+ result = result * 48271 + Float.hashCode(mScale);
+ return result;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof CutoutPathParserInfo) {
+ CutoutPathParserInfo c = (CutoutPathParserInfo) o;
+ return mDisplayWidth == c.mDisplayWidth && mDisplayHeight == c.mDisplayHeight
+ && mDensity == c.mDensity && mCutoutSpec.equals(c.mCutoutSpec)
+ && mRotation == c.mRotation && mScale == c.mScale;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "CutoutPathParserInfo{displayWidth=" + mDisplayWidth
+ + " displayHeight=" + mDisplayHeight
+ + " density={" + mDensity + "}"
+ + " cutoutSpec={" + mCutoutSpec + "}"
+ + " rotation={" + mRotation + "}"
+ + " scale={" + mScale + "}"
+ + "}";
+ }
+ }
+
+ private final @NonNull CutoutPathParserInfo mCutoutPathParserInfo;
+
+ /**
* Creates a DisplayCutout instance.
*
* <p>Note that this is only useful for tests. For production code, developers should always
@@ -251,7 +363,8 @@ public final class DisplayCutout {
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
@Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) {
- this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, true);
+ this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, null,
+ true);
}
/**
@@ -276,7 +389,7 @@ public final class DisplayCutout {
@Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom,
@NonNull Insets waterfallInsets) {
this(safeInsets.toRect(), waterfallInsets, boundLeft, boundTop, boundRight, boundBottom,
- true);
+ null, true);
}
/**
@@ -294,7 +407,7 @@ public final class DisplayCutout {
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
@Deprecated
public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
- this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects),
+ this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects), null,
true /* copyArguments */);
}
@@ -303,28 +416,42 @@ public final class DisplayCutout {
*
* @param safeInsets the insets from each edge which avoid the display cutout as returned by
* {@link #getSafeInsetTop()} etc.
+ * @param waterfallInsets the insets for the curved areas in waterfall display.
+ * @param boundLeft the left bounding rect of the display cutout in pixels. If null is passed,
+ * it's treated as an empty rectangle (0,0)-(0,0).
+ * @param boundTop the top bounding rect of the display cutout in pixels. If null is passed,
+ * it's treated as an empty rectangle (0,0)-(0,0).
+ * @param boundRight the right bounding rect of the display cutout in pixels. If null is
+ * passed, it's treated as an empty rectangle (0,0)-(0,0).
+ * @param boundBottom the bottom bounding rect of the display cutout in pixels. If null is
+ * passed, it's treated as an empty rectangle (0,0)-(0,0).
+ * @param info the cutout path parser info.
* @param copyArguments if true, create a copy of the arguments. If false, the passed arguments
* are not copied and MUST remain unchanged forever.
*/
- private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft,
- Rect boundTop, Rect boundRight, Rect boundBottom, boolean copyArguments) {
+ private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft, Rect boundTop,
+ Rect boundRight, Rect boundBottom, CutoutPathParserInfo info,
+ boolean copyArguments) {
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = new Bounds(boundLeft, boundTop, boundRight, boundBottom, copyArguments);
+ mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
}
private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect[] bounds,
- boolean copyArguments) {
+ CutoutPathParserInfo info, boolean copyArguments) {
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = new Bounds(bounds, copyArguments);
+ mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
}
- private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds) {
+ private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds,
+ CutoutPathParserInfo info) {
mSafeInsets = safeInsets;
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = bounds;
-
+ mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
}
private static Rect getCopyOrRef(Rect r, boolean copyArguments) {
@@ -534,10 +661,70 @@ public final class DisplayCutout {
return mBounds.getRect(BOUNDS_POSITION_BOTTOM);
}
+ /**
+ * Returns a {@link Path} that contains the cutout paths of all sides on the display.
+ *
+ * To get a cutout path for one specific side, apps can intersect the {@link Path} with the
+ * {@link Rect} obtained from {@link #getBoundingRectLeft()}, {@link #getBoundingRectTop()},
+ * {@link #getBoundingRectRight()} or {@link #getBoundingRectBottom()}.
+ *
+ * @return a {@link Path} contains all the cutout paths based on display coordinate. Returns
+ * null if there is no cutout on the display.
+ */
+ public @Nullable Path getCutoutPath() {
+ if (!mCutoutPathParserInfo.hasCutout()) {
+ return null;
+ }
+ synchronized (CACHE_LOCK) {
+ if (mCutoutPathParserInfo.equals(sCachedCutoutPathParserInfo)) {
+ return sCachedCutoutPath;
+ }
+ }
+ final CutoutSpecification cutoutSpec = new CutoutSpecification.Parser(
+ mCutoutPathParserInfo.getDensity(), mCutoutPathParserInfo.getDisplayWidth(),
+ mCutoutPathParserInfo.getDisplayHeight())
+ .parse(mCutoutPathParserInfo.getCutoutSpec());
+
+ final Path cutoutPath = cutoutSpec.getPath();
+ if (cutoutPath == null || cutoutPath.isEmpty()) {
+ return null;
+ }
+ final Matrix matrix = new Matrix();
+ if (mCutoutPathParserInfo.getRotation() != ROTATION_0) {
+ RotationUtils.transformPhysicalToLogicalCoordinates(
+ mCutoutPathParserInfo.getRotation(),
+ mCutoutPathParserInfo.getDisplayWidth(),
+ mCutoutPathParserInfo.getDisplayHeight(),
+ matrix
+ );
+ }
+ matrix.postScale(mCutoutPathParserInfo.getScale(), mCutoutPathParserInfo.getScale());
+ cutoutPath.transform(matrix);
+
+ synchronized (CACHE_LOCK) {
+ sCachedCutoutPathParserInfo = new CutoutPathParserInfo(mCutoutPathParserInfo);
+ sCachedCutoutPath = cutoutPath;
+ }
+ return cutoutPath;
+ }
+
+ /**
+ * @return the {@link CutoutPathParserInfo};
+ *
+ * @hide
+ */
+ public CutoutPathParserInfo getCutoutPathParserInfo() {
+ return mCutoutPathParserInfo;
+ }
+
@Override
public int hashCode() {
- return (mSafeInsets.hashCode() * 48271 + mBounds.hashCode()) * 48271
- + mWaterfallInsets.hashCode();
+ int result = 0;
+ result = 48271 * result + mSafeInsets.hashCode();
+ result = 48271 * result + mBounds.hashCode();
+ result = 48271 * result + mWaterfallInsets.hashCode();
+ result = 48271 * result + mCutoutPathParserInfo.hashCode();
+ return result;
}
@Override
@@ -548,7 +735,8 @@ public final class DisplayCutout {
if (o instanceof DisplayCutout) {
DisplayCutout c = (DisplayCutout) o;
return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds)
- && mWaterfallInsets.equals(c.mWaterfallInsets);
+ && mWaterfallInsets.equals(c.mWaterfallInsets)
+ && mCutoutPathParserInfo.equals(c.mCutoutPathParserInfo);
}
return false;
}
@@ -558,6 +746,7 @@ public final class DisplayCutout {
return "DisplayCutout{insets=" + mSafeInsets
+ " waterfall=" + mWaterfallInsets
+ " boundingRect={" + mBounds + "}"
+ + " cutoutPathParserInfo={" + mCutoutPathParserInfo + "}"
+ "}";
}
@@ -607,7 +796,7 @@ public final class DisplayCutout {
}
return new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds,
- false /* copyArguments */);
+ mCutoutPathParserInfo, false /* copyArguments */);
}
private Rect insetInsets(int insetLeft, int insetTop, int insetRight, int insetBottom,
@@ -638,7 +827,8 @@ public final class DisplayCutout {
* @hide
*/
public DisplayCutout replaceSafeInsets(Rect safeInsets) {
- return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds);
+ return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds,
+ mCutoutPathParserInfo);
}
private static int atLeastZero(int value) {
@@ -658,16 +848,18 @@ public final class DisplayCutout {
for (int i = 0; i < BOUNDS_POSITION_LENGTH; ++i) {
bounds[i] = (pos == i) ? new Rect(left, top, right, bottom) : new Rect();
}
- return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
+ return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, null, false /* copyArguments */);
}
/**
- * Creates an instance from a bounding and waterfall insets.
+ * Creates an instance from bounds, waterfall insets and CutoutPathParserInfo.
*
* @hide
*/
- public static DisplayCutout fromBoundsAndWaterfall(Rect[] bounds, Insets waterfallInsets) {
- return new DisplayCutout(ZERO_RECT, waterfallInsets, bounds, false /* copyArguments */);
+ public static DisplayCutout constructDisplayCutout(Rect[] bounds, Insets waterfallInsets,
+ CutoutPathParserInfo info) {
+ return new DisplayCutout(ZERO_RECT, waterfallInsets, bounds, info,
+ false /* copyArguments */);
}
/**
@@ -676,7 +868,8 @@ public final class DisplayCutout {
* @hide
*/
public static DisplayCutout fromBounds(Rect[] bounds) {
- return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
+ return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, null /* cutoutPathParserInfo */,
+ false /* copyArguments */);
}
/**
@@ -686,10 +879,12 @@ public final class DisplayCutout {
*
* @hide
*/
- public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) {
- return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
+ public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth,
+ int displayHeight) {
+ return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+ res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
- loadWaterfallInset(res));
+ loadWaterfallInset(res)).second;
}
/**
@@ -699,7 +894,7 @@ public final class DisplayCutout {
*/
public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
return pathAndDisplayCutoutFromSpec(
- res.getString(R.string.config_mainBuiltInDisplayCutout),
+ res.getString(R.string.config_mainBuiltInDisplayCutout), null,
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
loadWaterfallInset(res)).first;
}
@@ -710,14 +905,30 @@ public final class DisplayCutout {
* @hide
*/
@VisibleForTesting(visibility = PRIVATE)
- public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight,
- float density, Insets waterfallInsets) {
+ public static DisplayCutout fromSpec(String pathSpec, int displayWidth,
+ int displayHeight, float density, Insets waterfallInsets) {
return pathAndDisplayCutoutFromSpec(
- spec, displayWidth, displayHeight, density, waterfallInsets).second;
+ pathSpec, null, displayWidth, displayHeight, density, waterfallInsets)
+ .second;
}
- private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec(String spec,
- int displayWidth, int displayHeight, float density, Insets waterfallInsets) {
+ /**
+ * Gets the cutout path and the corresponding DisplayCutout instance from the spec string.
+ *
+ * @param pathSpec the spec string read from config_mainBuiltInDisplayCutout.
+ * @param rectSpec the spec string read from config_mainBuiltInDisplayCutoutRectApproximation.
+ * @param displayWidth the display width.
+ * @param displayHeight the display height.
+ * @param density the display density.
+ * @param waterfallInsets the waterfall insets of the display.
+ * @return a Pair contains the cutout path and the corresponding DisplayCutout instance.
+ */
+ private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec(
+ String pathSpec, String rectSpec, int displayWidth, int displayHeight, float density,
+ Insets waterfallInsets) {
+ // Always use the rect approximation spec to create the cutout if it's not null because
+ // transforming and sending a Region constructed from a path is very costly.
+ String spec = rectSpec != null ? rectSpec : pathSpec;
if (TextUtils.isEmpty(spec) && waterfallInsets.equals(Insets.NONE)) {
return NULL_PAIR;
}
@@ -750,9 +961,12 @@ public final class DisplayCutout {
Math.max(waterfallInsets.bottom, safeInset.bottom));
}
+ final CutoutPathParserInfo cutoutPathParserInfo = new CutoutPathParserInfo(displayWidth,
+ displayHeight, density, pathSpec.trim(), ROTATION_0, 1f /* scale */);
+
final DisplayCutout cutout = new DisplayCutout(
- safeInset, waterfallInsets, boundLeft, boundTop,
- boundRight, boundBottom, false /* copyArguments */);
+ safeInset, waterfallInsets, boundLeft, boundTop, boundRight, boundBottom,
+ cutoutPathParserInfo , false /* copyArguments */);
final Pair<Path, DisplayCutout> result = new Pair<>(cutoutSpec.getPath(), cutout);
synchronized (CACHE_LOCK) {
sCachedSpec = spec;
@@ -817,6 +1031,12 @@ public final class DisplayCutout {
out.writeTypedObject(cutout.mSafeInsets, flags);
out.writeTypedArray(cutout.mBounds.getRects(), flags);
out.writeTypedObject(cutout.mWaterfallInsets, flags);
+ out.writeInt(cutout.mCutoutPathParserInfo.getDisplayWidth());
+ out.writeInt(cutout.mCutoutPathParserInfo.getDisplayHeight());
+ out.writeFloat(cutout.mCutoutPathParserInfo.getDensity());
+ out.writeString(cutout.mCutoutPathParserInfo.getCutoutSpec());
+ out.writeInt(cutout.mCutoutPathParserInfo.getRotation());
+ out.writeFloat(cutout.mCutoutPathParserInfo.getScale());
}
}
@@ -860,9 +1080,17 @@ public final class DisplayCutout {
Rect[] bounds = new Rect[BOUNDS_POSITION_LENGTH];
in.readTypedArray(bounds, Rect.CREATOR);
Insets waterfallInsets = in.readTypedObject(Insets.CREATOR);
+ int displayWidth = in.readInt();
+ int displayHeight = in.readInt();
+ float density = in.readFloat();
+ String cutoutSpec = in.readString();
+ int rotation = in.readInt();
+ float scale = in.readFloat();
+ final CutoutPathParserInfo info = new CutoutPathParserInfo(
+ displayWidth, displayHeight, density, cutoutSpec, rotation, scale);
return new DisplayCutout(
- safeInsets, waterfallInsets, bounds, false /* copyArguments */);
+ safeInsets, waterfallInsets, bounds, info, false /* copyArguments */);
}
public DisplayCutout get() {
@@ -884,7 +1112,15 @@ public final class DisplayCutout {
bounds.scale(scale);
final Rect waterfallInsets = mInner.mWaterfallInsets.toRect();
waterfallInsets.scale(scale);
- mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds);
+ final CutoutPathParserInfo info = new CutoutPathParserInfo(
+ mInner.mCutoutPathParserInfo.getDisplayWidth(),
+ mInner.mCutoutPathParserInfo.getDisplayHeight(),
+ mInner.mCutoutPathParserInfo.getDensity(),
+ mInner.mCutoutPathParserInfo.getCutoutSpec(),
+ mInner.mCutoutPathParserInfo.getRotation(),
+ scale);
+
+ mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds, info);
}
@Override
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 106e3927656f..0a1a23116941 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -414,6 +414,15 @@ public final class SurfaceControl implements Parcelable {
*/
public static final int SECURE = 0x00000080;
+
+ /**
+ * Queue up BufferStateLayer buffers instead of dropping the oldest buffer when this flag is
+ * set. This blocks the client until all the buffers have been presented. If the buffers
+ * have presentation timestamps, then we may drop buffers.
+ * @hide
+ */
+ public static final int ENABLE_BACKPRESSURE = 0x00000100;
+
/**
* Surface creation flag: Creates a surface where color components are interpreted
* as "non pre-multiplied" by their alpha channel. Of course this flag is
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index acbcbfad1a75..b10370aa5d4c 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -85,13 +85,12 @@ public class SyncRtSurfaceTransactionApplier {
for (int i = params.length - 1; i >= 0; i--) {
SurfaceParams surfaceParams = params[i];
SurfaceControl surface = surfaceParams.surface;
+ if (frame > 0) {
+ t.deferTransactionUntil(surface, mTargetSc, frame);
+ }
applyParams(t, surfaceParams, mTmpFloat9);
}
- if (mTargetViewRootImpl != null) {
- mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
- } else {
- t.apply();
- }
+ t.apply();
}
public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 52d0062abdf2..844fc267c3cb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10109,7 +10109,7 @@ public final class ViewRootImpl implements ViewParent,
* Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures
* you can add transactions to the upcoming frame.
*/
- public void mergeWithNextTransaction(Transaction t, long frameNumber) {
+ void mergeWithNextTransaction(Transaction t, long frameNumber) {
if (mBlastBufferQueue != null) {
mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber);
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0e878fcf0e24..4ef63ae93016 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -262,7 +262,7 @@ public:
}
}
- binder::Status onScreenCaptureComplete(
+ binder::Status onScreenCaptureCompleted(
const gui::ScreenCaptureResults& captureResults) override {
JNIEnv* env = getenv();
if (captureResults.result != NO_ERROR || captureResults.buffer == nullptr) {
@@ -270,6 +270,7 @@ public:
gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
return binder::Status::ok();
}
+ captureResults.fence->waitForever("");
jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
env, captureResults.buffer->toAHardwareBuffer());
const jint namedColorSpace =
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 396f95446bf6..4acdb1663403 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2541,7 +2541,7 @@
<!-- Allows an application to start a task from a ActivityManager#RecentTaskInfo.
@hide -->
<permission android:name="android.permission.START_TASKS_FROM_RECENTS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|recents" />
<!-- @SystemApi @hide Allows an application to call APIs that allow it to do interactions
across the users on the device, using singleton services and
@@ -2606,7 +2606,7 @@
<!-- @SystemApi @TestApi @hide Allows an application to change to remove/kill tasks -->
<permission android:name="android.permission.REMOVE_TASKS"
- android:protectionLevel="signature|documenter" />
+ android:protectionLevel="signature|documenter|recents" />
<!-- @deprecated Use MANAGE_ACTIVITY_TASKS instead.
@SystemApi @TestApi @hide Allows an application to create/manage/remove stacks -->
@@ -2615,7 +2615,7 @@
<!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove tasks -->
<permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|recents" />
<!-- @SystemApi @TestApi @hide Allows an application to embed other activities -->
<permission android:name="android.permission.ACTIVITY_EMBEDDING"
@@ -2697,11 +2697,11 @@
The app can check whether it has this authorization by calling
{@link android.provider.Settings#canDrawOverlays
Settings.canDrawOverlays()}.
- <p>Protection level: signature|appop|preinstalled|pre23|development -->
+ <p>Protection level: signature|appop|installer|recents|appPredictor|pre23|development -->
<permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
android:label="@string/permlab_systemAlertWindow"
android:description="@string/permdesc_systemAlertWindow"
- android:protectionLevel="signature|appop|preinstalled|pre23|development" />
+ android:protectionLevel="signature|appop|installer|recents|appPredictor|pre23|development" />
<!-- @SystemApi @hide Allows an application to create windows using the type
{@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY},
@@ -3284,7 +3284,7 @@
and its icons.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.STATUS_BAR"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|recents" />
<!-- Allows an application to trigger bugreport via shell using the bugreport API.
<p>Not for use by third-party applications.
@@ -3451,7 +3451,7 @@
critical UI such as the home screen.
@hide -->
<permission android:name="android.permission.STOP_APP_SWITCHES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|recents" />
<!-- @SystemApi Allows an application to retrieve private information about
the current top activity, such as any assist context it can provide.
@@ -3836,7 +3836,7 @@
@hide
-->
<permission android:name="android.permission.SET_ORIENTATION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|recents" />
<!-- @SystemApi Allows low-level access to setting the pointer speed.
<p>Not for use by third-party applications.
@@ -4100,7 +4100,7 @@
@hide
@removed -->
<permission android:name="android.permission.READ_FRAME_BUFFER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|recents" />
<!-- Allows an application to use InputFlinger's low level features.
@hide -->
@@ -5277,7 +5277,7 @@
<!-- @SystemApi Allows modifying accessibility state.
@hide -->
<permission android:name="android.permission.MANAGE_ACCESSIBILITY"
- android:protectionLevel="signature|setup" />
+ android:protectionLevel="signature|setup|recents" />
<!-- @SystemApi Allows an app to grant a profile owner access to device identifiers.
<p>Not for use by third-party applications.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 415a0a2ed595..14f1e0e20ef6 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9276,6 +9276,12 @@
{@deprecated Use app:fontProviderCerts with Jetpack Core library instead.}
-->
<attr name="fontProviderCerts" format="reference" />
+ <!-- Provides the system font family name to check before downloading the font. For example
+ if the fontProviderQuery asked for "Sans Serif", it is possible to define
+ fontProviderSystemFontFamily as "sans-serif" to tell the system to use "sans-serif" font
+ family if it exists on the system.
+ -->
+ <attr name="fontProviderSystemFontFamily" format="string" />
</declare-styleable>
<!-- Attributes that are read when parsing a tag. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ddf3c5f09e9e..9c1c51cdd48e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3058,6 +3058,7 @@
<public name="sspSuffix" />
<public name="pathAdvancedPattern" />
<public name="sspAdvancedPattern" />
+ <public name="fontProviderSystemFontFamily" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp
new file mode 100644
index 000000000000..e1787762e067
--- /dev/null
+++ b/core/tests/GameManagerTests/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2021 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.
+
+android_test {
+ name: "FrameworksCoreGameManagerTests",
+ // Include all test java files
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "junit",
+ "truth-prebuilt",
+ ],
+ libs: ["android.test.runner"],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/GameManagerTests/AndroidManifest.xml b/core/tests/GameManagerTests/AndroidManifest.xml
new file mode 100644
index 000000000000..da6636b7b192
--- /dev/null
+++ b/core/tests/GameManagerTests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.graphics.gamemanagertests"
+ android:sharedUserId="android.uid.system" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.graphics.gamemanagertests"
+ android:label="Game Manager Tests"/>
+
+</manifest>
diff --git a/core/tests/GameManagerTests/AndroidTest.xml b/core/tests/GameManagerTests/AndroidTest.xml
new file mode 100644
index 000000000000..bfb9802ba1ad
--- /dev/null
+++ b/core/tests/GameManagerTests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Runs Game Manager Tests.">
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-suite-tag" value="apct-instrumentation"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="FrameworksCoreGameManagerTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.graphics.gamemanagertests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/core/tests/GameManagerTests/src/android/graphics/GameManagerTests.java b/core/tests/GameManagerTests/src/android/graphics/GameManagerTests.java
new file mode 100644
index 000000000000..d861a894500a
--- /dev/null
+++ b/core/tests/GameManagerTests/src/android/graphics/GameManagerTests.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 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.graphics;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.graphics.GameManager.GameMode;
+import android.util.ArrayMap;
+import android.util.Pair;
+
+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;
+
+/**
+ * Unit tests for {@link GameManager}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class GameManagerTests {
+ private static final String PACKAGE_NAME_0 = "com.android.app0";
+ private static final String PACKAGE_NAME_1 = "com.android.app1";
+
+ private TestGameManagerService mService;
+ private GameManager mGameManager;
+
+ @Before
+ public void setUp() {
+ mService = new TestGameManagerService();
+ mGameManager = new GameManager(
+ InstrumentationRegistry.getContext(), mService);
+ }
+
+ @Test
+ public void testGameModeGetterSetter() {
+ assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ mGameManager.getGameMode(PACKAGE_NAME_0));
+
+ mGameManager.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD);
+ assertEquals(GameManager.GAME_MODE_STANDARD,
+ mGameManager.getGameMode(PACKAGE_NAME_1));
+
+ mGameManager.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_PERFORMANCE);
+ assertEquals(GameManager.GAME_MODE_PERFORMANCE,
+ mGameManager.getGameMode(PACKAGE_NAME_1));
+ }
+
+ private final class TestGameManagerService extends IGameManagerService.Stub {
+ private final ArrayMap<Pair<String, Integer>, Integer> mGameModes = new ArrayMap<>();
+
+ @Override
+ public @GameMode int getGameMode(String packageName, int userId) {
+ final Pair key = Pair.create(packageName, userId);
+ if (mGameModes.containsKey(key)) {
+ return mGameModes.get(key);
+ }
+ return GameManager.GAME_MODE_UNSUPPORTED;
+ }
+
+ @Override
+ public void setGameMode(String packageName, @GameMode int gameMode, int userId) {
+ mGameModes.put(Pair.create(packageName, userId), gameMode);
+ }
+ }
+}
diff --git a/core/tests/coretests/res/font/samplexmldownloadedfont.xml b/core/tests/coretests/res/font/samplexmldownloadedfont.xml
index f1bdc473b9d2..9c32ffb0f4c9 100644
--- a/core/tests/coretests/res/font/samplexmldownloadedfont.xml
+++ b/core/tests/coretests/res/font/samplexmldownloadedfont.xml
@@ -2,5 +2,6 @@
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
android:fontProviderAuthority="com.example.test.fontprovider.authority"
android:fontProviderPackage="com.example.test.fontprovider.package"
- android:fontProviderQuery="MyRequestedFont">
+ android:fontProviderQuery="MyRequestedFont"
+ android:fontProviderSystemFontFamily="my-request-font">
</font-family> \ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java b/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
index 24f45a57dabc..bffd1e4a86d6 100644
--- a/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
+++ b/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
@@ -28,6 +28,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.pm.PackageParser.SigningDetails;
+import android.util.ArraySet;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -35,6 +36,8 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Set;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SigningDetailsTest {
@@ -208,8 +211,8 @@ public class SigningDetailsTest {
SigningDetails result1 = noLineageDetails.mergeLineageWith(lineageDetails);
SigningDetails result2 = lineageDetails.mergeLineageWith(noLineageDetails);
- assertTrue(result1 == lineageDetails);
- assertTrue(result2 == lineageDetails);
+ assertSigningDetailsContainsLineage(result1, FIRST_SIGNATURE, SECOND_SIGNATURE);
+ assertSigningDetailsContainsLineage(result2, FIRST_SIGNATURE, SECOND_SIGNATURE);
}
@Test
@@ -271,8 +274,10 @@ public class SigningDetailsTest {
SigningDetails result1 = singleSignerDetails.mergeLineageWith(fullLineageDetails);
SigningDetails result2 = fullLineageDetails.mergeLineageWith(singleSignerDetails);
- assertTrue(result1 == fullLineageDetails);
- assertTrue(result2 == fullLineageDetails);
+ assertSigningDetailsContainsLineage(result1, FIRST_SIGNATURE, SECOND_SIGNATURE,
+ THIRD_SIGNATURE);
+ assertSigningDetailsContainsLineage(result2, FIRST_SIGNATURE, SECOND_SIGNATURE,
+ THIRD_SIGNATURE);
}
@Test
@@ -605,6 +610,213 @@ public class SigningDetailsTest {
assertTrue(secondLineageDetails.hasCommonAncestor(firstLineageDetails));
}
+ @Test
+ public void hasCommonSignerWithCapabilities_singleMatchingSigner_returnsTrue()
+ throws Exception {
+ // The hasCommonSignerWithCapabilities method is intended to grant the specified
+ // capabilities to a requesting package that has a common signer in the lineage (or as the
+ // current signer) even if their signing identities have diverged. This test verifies if the
+ // two SigningDetails have the same single signer then the requested capability can be
+ // granted since the current signer always has all capabilities granted.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE);
+ SigningDetails secondSignerDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertTrue(firstDetails.hasCommonSignerWithCapability(secondSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleDifferentSigners_returnsFalse()
+ throws Exception {
+ // If each package is signed by a single different signer then the method should return
+ // false since there is no shared signer.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_oneWithMultipleSigners_returnsFalse()
+ throws Exception {
+ // If one of the packages is signed with multiple signers and the other only a single signer
+ // this method should return false since all signers must match exactly for multiple signer
+ // cases.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_multipleMatchingSigners_returnsTrue()
+ throws Exception {
+ // if both packages are signed by the same multiple signers then this method should return
+ // true since the current signer is granted all capabilities.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE, FIRST_SIGNATURE);
+
+ assertTrue(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertTrue(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleSignerInLineage_returnsTrue()
+ throws Exception {
+ // if a single signer is in the lineage and that previous signer has the requested
+ // capability then this method should return true.
+ SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE},
+ new int[]{DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails singleSignerDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertTrue(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleSignerInLineageWOCapability_returnsFalse()
+ throws Exception {
+ // If a single signer is in the lineage and that previous signer does not have the requested
+ // capability then this method should return false.
+ SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES});
+ SigningDetails singleSignerDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertFalse(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleSignerMatchesCurrentSigner_returnsTrue()
+ throws Exception {
+ // If a requesting app is signed by the same current signer as an app with a lineage the
+ // method should return true since the current signer is granted all capabilities.
+ SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES});
+ SigningDetails singleSignerDetails = createSigningDetails(SECOND_SIGNATURE);
+
+ assertTrue(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_divergingSignersWithCommonSigner_returnsTrue()
+ throws Exception {
+ // This method is intended to allow granting a capability to another app that has a common
+ // signer in the lineage with the capability still granted; this test verifies when the
+ // current signers diverge but a common ancestor has the requested capability this method
+ // returns true.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_divergingSignersOneGrantsCapability_returnsTrue()
+ throws Exception {
+ // If apps have multiple common signers in the lineage with one denying the requested
+ // capability but the other granting it this method should return true.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_divergingSignersNoneGrantCapability_returnsFalse()
+ throws Exception {
+ // If apps have multiple common signers in the lineage with all denying the requested
+ // capability this method should return false.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, AUTH, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertFalse(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void
+ hasCommonSignerWithCapabilities_divergingSignersNoneGrantsAllCapabilities_returnsTrue()
+ throws Exception {
+ // If an app has multiple common signers in the lineage, each granting one of the requested
+ // capabilities but neither granting all this method should return false since a single
+ // common ancestor must grant all requested capabilities.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, PERMISSION, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertFalse(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION | SHARED_USER_ID));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_currentSignerInLineageOfRequestingApp_returnsTrue()
+ throws Exception {
+ // If the current signer of an app is in the lineage of the requesting app then this method
+ // should return true since the current signer is granted all capabilities.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE);
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, THIRD_SIGNATURE);
+
+ assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_currentSignerInLineageOfDeclaringApp_returnsTrue()
+ throws Exception {
+ // If the current signer of a requesting app with a lineage is in the lineage of the
+ // declaring app and that previous signature is granted the requested capability the method
+ // should return true.
+ SigningDetails declaringDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails requestingDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE);
+
+ assertTrue(declaringDetails.hasCommonSignerWithCapability(requestingDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_oneSignerNullLineage_returns() throws Exception {
+ // While the pastSigningCertificates should only be null in the case of multiple current
+ // signers there are instances where this can be null with a single signer; verify that a
+ // null pastSigningCertificates array in either SigningDetails does not result in a
+ // NullPointerException.
+ SigningDetails firstDetails = createSigningDetails(true, FIRST_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_unknownSigner_returnsFalse() throws Exception {
+ // An unknown SigningDetails for either instance should immediately result in false being
+ // returned.
+ SigningDetails firstDetails = SigningDetails.UNKNOWN;
+ SigningDetails secondDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
private SigningDetails createSigningDetailsWithLineage(String... signers) throws Exception {
int[] capabilities = new int[signers.length];
for (int i = 0; i < capabilities.length; i++) {
@@ -629,10 +841,34 @@ public class SigningDetailsTest {
}
private SigningDetails createSigningDetails(String... signers) throws Exception {
+ return createSigningDetails(false, signers);
+ }
+
+ private SigningDetails createSigningDetails(boolean useNullPastSigners, String... signers)
+ throws Exception {
Signature[] currentSignatures = new Signature[signers.length];
for (int i = 0; i < signers.length; i++) {
currentSignatures[i] = new Signature(signers[i]);
}
- return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, null);
+ // If there are multiple signers then the pastSigningCertificates should be set to null, but
+ // if there is only a single signer both the current signer and the past signers should be
+ // set to that one signer.
+ if (signers.length > 1) {
+ return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, null);
+ }
+ return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, currentSignatures);
+ }
+
+ private void assertSigningDetailsContainsLineage(SigningDetails details,
+ String... pastSigners) {
+ // This method should only be invoked for results that contain a single signer.
+ assertEquals(1, details.signatures.length);
+ assertTrue(details.signatures[0].toCharsString().equalsIgnoreCase(
+ pastSigners[pastSigners.length - 1]));
+ Set<String> signatures = new ArraySet<>(pastSigners);
+ for (Signature pastSignature : details.pastSigningCertificates) {
+ assertTrue(signatures.remove(pastSignature.toCharsString()));
+ }
+ assertEquals(0, signatures.size());
}
}
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 7ab9d7f4ffe1..57f01e988440 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -105,6 +105,7 @@ public class FontResourcesParserTest {
assertEquals("com.example.test.fontprovider.authority", providerEntry.getAuthority());
assertEquals("com.example.test.fontprovider.package", providerEntry.getPackage());
assertEquals("MyRequestedFont", providerEntry.getQuery());
+ assertEquals("my-request-font", providerEntry.getSystemFontFamilyName());
}
@Test
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index d02c6d588585..a5261aecdbfb 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -22,6 +22,8 @@ import static android.view.DisplayCutout.fromSpec;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -30,6 +32,7 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import android.graphics.Insets;
+import android.graphics.Path;
import android.graphics.Rect;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -130,6 +133,8 @@ public class DisplayCutoutTest {
@Test
public void testHasCutout_noCutout() throws Exception {
assertTrue(NO_CUTOUT.isBoundsEmpty());
+ assertThat(NO_CUTOUT.getWaterfallInsets(), equalTo(Insets.NONE));
+ assertThat(NO_CUTOUT.getCutoutPath(), nullValue());
}
@Test
@@ -165,6 +170,59 @@ public class DisplayCutoutTest {
}
@Test
+ public void testGetCutoutPath() throws Exception {
+ final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE);
+ assertThat(cutout.getCutoutPath(), notNullValue());
+ }
+
+ @Test
+ public void testGetCutoutPath_caches() throws Exception {
+ final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final Path first = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ final Path second = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ assertThat(first, equalTo(second));
+ }
+
+ @Test
+ public void testGetCutoutPath_wontCacheIfCutoutPathParerInfoChanged() throws Exception {
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final Path first = fromSpec("L1,0 L1,1 L0,1 z", displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ final Path second = fromSpec("L2,0 L2,2 L0,2 z", displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ assertThat(first, not(equalTo(second)));
+ }
+
+ @Test
+ public void testGetCutoutPathParserInfo() throws Exception {
+ final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE);
+ assertThat(displayWidth, equalTo(cutout.getCutoutPathParserInfo().getDisplayWidth()));
+ assertThat(displayHeight, equalTo(cutout.getCutoutPathParserInfo().getDisplayHeight()));
+ assertThat(density, equalTo(cutout.getCutoutPathParserInfo().getDensity()));
+ assertThat(cutoutSpecString.trim(),
+ equalTo(cutout.getCutoutPathParserInfo().getCutoutSpec()));
+ assertThat(0, equalTo(cutout.getCutoutPathParserInfo().getRotation()));
+ assertThat(1f, equalTo(cutout.getCutoutPathParserInfo().getScale()));
+ }
+
+ @Test
public void testHashCode() throws Exception {
assertEquals(mCutoutWithWaterfall.hashCode(), createCutoutWithWaterfall().hashCode());
assertNotEquals(mCutoutWithWaterfall.hashCode(), mCutoutNumbers.hashCode());
diff --git a/core/tests/mockingcoretests/src/android/view/OWNERS b/core/tests/mockingcoretests/src/android/view/OWNERS
new file mode 100644
index 000000000000..9c9f824ba12b
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/view/OWNERS
@@ -0,0 +1,2 @@
+# Display
+per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml
index 99c38dbe6ac9..598d2027a0e9 100644
--- a/data/etc/com.android.launcher3.xml
+++ b/data/etc/com.android.launcher3.xml
@@ -21,5 +21,8 @@
<permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
+ <permission name="android.permission.START_TASKS_FROM_RECENTS"/>
+ <permission name="android.permission.STATUS_BAR"/>
+ <permission name="android.permission.STOP_APP_SWITCHES"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f84d947b51ed..ae8e3ce854e3 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -355,7 +355,6 @@ applications that come with the platform
<permission name="android.permission.MOVE_PACKAGE"/>
<!-- Needed for test only -->
<permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
- <permission name="android.permission.NETWORK_AIRPLANE_MODE"/>
<permission name="android.permission.OBSERVE_APP_USAGE"/>
<permission name="android.permission.NETWORK_SCAN"/>
<permission name="android.permission.PACKAGE_USAGE_STATS" />
diff --git a/graphics/java/android/graphics/GameManager.java b/graphics/java/android/graphics/GameManager.java
new file mode 100644
index 000000000000..a58aeb4298d6
--- /dev/null
+++ b/graphics/java/android/graphics/GameManager.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 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.graphics;
+
+import android.annotation.IntDef;
+import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The GameManager allows system apps to modify and query the game mode of apps.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+@SystemService(Context.GAME_SERVICE)
+public final class GameManager {
+
+ private static final String TAG = "GameManager";
+
+ private final Context mContext;
+ private final IGameManagerService mService;
+
+ @IntDef(flag = false, prefix = { "GAME_MODE_" }, value = {
+ GAME_MODE_UNSUPPORTED, // 0
+ GAME_MODE_STANDARD, // 1
+ GAME_MODE_PERFORMANCE, // 2
+ GAME_MODE_BATTERY, // 3
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GameMode {}
+
+ public static final int GAME_MODE_UNSUPPORTED = 0;
+ public static final int GAME_MODE_STANDARD = 1;
+ public static final int GAME_MODE_PERFORMANCE = 2;
+ public static final int GAME_MODE_BATTERY = 3;
+
+ public GameManager(Context context, Handler handler) throws ServiceNotFoundException {
+ mContext = context;
+ mService = IGameManagerService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.GAME_SERVICE));
+ }
+
+ @VisibleForTesting
+ public GameManager(Context context, IGameManagerService gameManagerService) {
+ mContext = context;
+ mService = gameManagerService;
+ }
+
+ /**
+ * Returns the game mode for the given package.
+ */
+ // TODO(b/178111358): Add @RequiresPermission.
+ @UserHandleAware
+ public @GameMode int getGameMode(String packageName) {
+ try {
+ return mService.getGameMode(packageName, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the game mode for the given package.
+ */
+ // TODO(b/178111358): Add @RequiresPermission.
+ @UserHandleAware
+ public void setGameMode(String packageName, @GameMode int gameMode) {
+ try {
+ mService.setGameMode(packageName, gameMode, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/IGameManagerService.aidl b/graphics/java/android/graphics/IGameManagerService.aidl
new file mode 100644
index 000000000000..7d3a4fba562e
--- /dev/null
+++ b/graphics/java/android/graphics/IGameManagerService.aidl
@@ -0,0 +1,25 @@
+/*
+** Copyright 2021, 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.graphics;
+
+/**
+ * @hide
+ */
+interface IGameManagerService {
+ int getGameMode(String packageName, int userId);
+ void setGameMode(String packageName, int gameMode, int userId);
+} \ No newline at end of file
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index a0568bf3bf5c..005a72661091 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -70,6 +70,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* The Typeface class specifies the typeface and intrinsic style of a font.
@@ -249,6 +250,21 @@ public class Typeface {
}
/**
+ * Returns true if the system has the font family with the name [familyName]. For example
+ * querying with "sans-serif" would check if the "sans-serif" family is defined in the system
+ * and return true if does.
+ *
+ * @param familyName The name of the font family, cannot be null. If null, exception will be
+ * thrown.
+ */
+ private static boolean hasFontFamily(@NonNull String familyName) {
+ Objects.requireNonNull(familyName, "familyName cannot be null");
+ synchronized (SYSTEM_FONT_MAP_LOCK) {
+ return sSystemFontMap.containsKey(familyName);
+ }
+ }
+
+ /**
* @hide
* Used by Resources to load a font resource of type xml.
*/
@@ -257,6 +273,11 @@ public class Typeface {
FamilyResourceEntry entry, AssetManager mgr, String path) {
if (entry instanceof ProviderResourceEntry) {
final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
+
+ String systemFontFamilyName = providerEntry.getSystemFontFamilyName();
+ if (systemFontFamilyName != null && hasFontFamily(systemFontFamilyName)) {
+ return Typeface.create(systemFontFamilyName, NORMAL);
+ }
// Downloadable font
List<List<String>> givenCerts = providerEntry.getCerts();
List<List<byte[]>> certs = new ArrayList<>();
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 2e0a5e09e34f..b581f555c234 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
@@ -36,8 +36,8 @@
android:layout_height="match_parent">
<ImageButton
android:id="@+id/expand_button"
- android:layout_width="60dp"
- android:layout_height="60dp"
+ android:layout_width="@dimen/pip_expand_action_size"
+ android:layout_height="@dimen/pip_expand_action_size"
android:layout_gravity="center"
android:contentDescription="@string/pip_phone_expand"
android:padding="10dp"
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index e25a05c4cfaf..034e65c608a3 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -26,6 +26,9 @@
<!-- The height of the PiP actions container in which the actions are vertically centered. -->
<dimen name="pip_action_size">48dp</dimen>
+ <!-- The width and height of the PiP expand action. -->
+ <dimen name="pip_expand_action_size">60dp</dimen>
+
<!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect
the configuration of the device, so we can't use -land resources. -->
<dimen name="pip_between_action_padding_land">8dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 1df2a4a9030d..bb8a97344664 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -225,8 +225,9 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
mTaskOrganizer.applyTransaction(wct);
// TODO(b/151449487): Only call callback once we enable synchronization
if (mListener != null) {
+ final int taskId = mTaskInfo.taskId;
mListenerExecutor.execute(() -> {
- mListener.onTaskVisibilityChanged(mTaskInfo.taskId, mSurfaceCreated);
+ mListener.onTaskVisibilityChanged(taskId, mSurfaceCreated);
});
}
}
@@ -256,8 +257,10 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
}
if (mListener != null) {
+ final int taskId = taskInfo.taskId;
+ final ComponentName baseActivity = taskInfo.baseActivity;
mListenerExecutor.execute(() -> {
- mListener.onTaskCreated(taskInfo.taskId, taskInfo.baseActivity);
+ mListener.onTaskCreated(taskId, baseActivity);
});
}
}
@@ -267,8 +270,9 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
if (mListener != null) {
+ final int taskId = taskInfo.taskId;
mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskInfo.taskId);
+ mListener.onTaskRemovalStarted(taskId);
});
}
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
@@ -289,8 +293,9 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
if (mListener != null) {
+ final int taskId = taskInfo.taskId;
mListenerExecutor.execute(() -> {
- mListener.onBackPressedOnTaskRoot(taskInfo.taskId);
+ mListener.onBackPressedOnTaskRoot(taskId);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 3181dbf74ace..58a4baf39614 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -356,11 +356,11 @@ public class DisplayLayout {
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
return null;
}
- final Insets waterfallInsets =
- RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
if (rotation == ROTATION_0) {
return computeSafeInsets(cutout, displayWidth, displayHeight);
}
+ final Insets waterfallInsets =
+ RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
Rect[] cutoutRects = cutout.getBoundingRectsAll();
final Rect[] newBounds = new Rect[cutoutRects.length];
@@ -372,8 +372,12 @@ public class DisplayLayout {
}
newBounds[getBoundIndexFromRotation(i, rotation)] = rect;
}
+ final DisplayCutout.CutoutPathParserInfo info = cutout.getCutoutPathParserInfo();
+ final DisplayCutout.CutoutPathParserInfo newInfo = new DisplayCutout.CutoutPathParserInfo(
+ info.getDisplayWidth(), info.getDisplayHeight(), info.getDensity(),
+ info.getCutoutSpec(), rotation, info.getScale());
return computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
+ DisplayCutout.constructDisplayCutout(newBounds, waterfallInsets, newInfo),
rotated ? displayHeight : displayWidth,
rotated ? displayWidth : displayHeight);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
index 4874d3ccae7e..a4cd3c5a583d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
@@ -47,6 +47,11 @@ public class HandlerExecutor implements ShellExecutor {
}
@Override
+ public void removeAllCallbacks() {
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
+ @Override
public void removeCallbacks(@NonNull Runnable r) {
mHandler.removeCallbacks(r);
}
@@ -55,9 +60,4 @@ public class HandlerExecutor implements ShellExecutor {
public boolean hasCallback(Runnable r) {
return mHandler.hasCallbacks(r);
}
-
- @Override
- public Looper getLooper() {
- return mHandler.getLooper();
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
index 1149cceb1068..b736fb0b9895 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
@@ -73,6 +73,11 @@ public interface ShellExecutor extends Executor {
void executeDelayed(Runnable runnable, long delayMillis);
/**
+ * Removes all pending callbacks.
+ */
+ void removeAllCallbacks();
+
+ /**
* See {@link android.os.Handler#removeCallbacks}.
*/
void removeCallbacks(Runnable runnable);
@@ -81,9 +86,4 @@ public interface ShellExecutor extends Executor {
* See {@link android.os.Handler#hasCallbacks(Runnable)}.
*/
boolean hasCallback(Runnable runnable);
-
- /**
- * Returns the looper that this executor is running on.
- */
- Looper getLooper();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
index a74f4761af0c..37a91d0c121c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
@@ -56,7 +56,7 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
private final float[] mColor;
private final float mAlpha;
private final Rect mRect;
- private final Handler mHandler;
+ private final Executor mMainExecutor;
private final Point mDisplaySize = new Point();
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@@ -76,13 +76,13 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
@Override
public void onOneHandedAnimationStart(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- mHandler.post(() -> showBackgroundPanelLayer());
+ mMainExecutor.execute(() -> showBackgroundPanelLayer());
}
};
@Override
public void onStopFinished(Rect bounds) {
- mHandler.post(() -> removeBackgroundPanelLayer());
+ mMainExecutor.execute(() -> removeBackgroundPanelLayer());
}
public OneHandedBackgroundPanelOrganizer(Context context, DisplayController displayController,
@@ -94,7 +94,7 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
mColor = new float[]{defaultRGB, defaultRGB, defaultRGB};
mAlpha = res.getFloat(R.dimen.config_one_handed_background_alpha);
mRect = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
- mHandler = new Handler();
+ mMainExecutor = executor;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
index 1ed121f35a59..49b7e050c48b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
@@ -221,8 +221,14 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
displaySize.y);
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"onehanded-gesture-offset", DEFAULT_DISPLAY);
- mInputEventReceiver = new EventReceiver(
- mInputMonitor.getInputChannel(), mMainExecutor.getLooper());
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ mInputEventReceiver = new EventReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper());
+ });
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to create input event receiver", e);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java
index 60709bef4daf..c7a49ff01d15 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java
@@ -132,8 +132,14 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback {
if (mIsEnabled) {
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"onehanded-touch", DEFAULT_DISPLAY);
- mInputEventReceiver = new EventReceiver(
- mInputMonitor.getInputChannel(), mMainExecutor.getLooper());
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ mInputEventReceiver = new EventReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper());
+ });
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to create input event receiver", e);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 8bf1b468cb7d..4b118f121767 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -34,6 +34,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Size;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
@@ -210,6 +211,11 @@ public class PhonePipMenuController implements PipMenuController {
}
}
+ @Nullable
+ Size getEstimatedMenuSize() {
+ return mPipMenuView == null ? null : mPipMenuView.getEstimatedMenuSize();
+ }
+
/**
* When other components requests the menu controller directly to show the menu, we must
* first fire off the request to the other listeners who will then propagate the call
@@ -224,13 +230,13 @@ public class PhonePipMenuController implements PipMenuController {
* Similar to {@link #showMenu(int, Rect, boolean, boolean, boolean)} but only show the menu
* upon PiP window transition is finished.
*/
- public void showMenuWithDelay(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ public void showMenuWithPossibleDelay(int menuState, Rect stackBounds, boolean allowMenuTimeout,
boolean willResizeMenu, boolean showResizeHandle) {
// hide all visible controls including close button and etc. first, this is to ensure
// menu is totally invisible during the transition to eliminate unpleasant artifacts
fadeOutMenu();
showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu,
- true /* withDelay */, showResizeHandle);
+ willResizeMenu /* withDelay=willResizeMenu here */, showResizeHandle);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index 7a634c3eef78..6e3a20d5f2b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -147,7 +147,7 @@ public class PipInputConsumer {
// Choreographer.getSfInstance() must be called on the thread that the input event
// receiver should be receiving events
mInputEventReceiver = new InputEventReceiver(inputChannel,
- mMainExecutor.getLooper(), Choreographer.getSfInstance());
+ Looper.myLooper(), Choreographer.getSfInstance());
if (mRegistrationListener != null) {
mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 2e515ee91d3a..48942b604a8d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -48,6 +48,7 @@ import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
+import android.util.Size;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -76,9 +77,6 @@ public class PipMenuView extends FrameLayout {
private static final String TAG = "PipMenuView";
- private static final int MESSAGE_INVALID_TYPE = -1;
- public static final int MESSAGE_MENU_EXPANDED = 8;
-
private static final int INITIAL_DISMISS_DELAY = 3500;
private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
private static final long MENU_FADE_DURATION = 125;
@@ -86,8 +84,6 @@ public class PipMenuView extends FrameLayout {
private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30;
private static final float MENU_BACKGROUND_ALPHA = 0.3f;
- private static final float DISMISS_BACKGROUND_ALPHA = 0.6f;
-
private static final float DISABLED_ACTION_ALPHA = 0.54f;
private static final boolean ENABLE_RESIZE_HANDLE = false;
@@ -370,6 +366,19 @@ public class PipMenuView extends FrameLayout {
}
}
+ /**
+ * @return estimated {@link Size} for which the width is based on number of actions and
+ * height based on the height of expand button + top and bottom action bar.
+ */
+ Size getEstimatedMenuSize() {
+ final int pipActionSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.pip_action_size);
+ final int width = mActions.size() * pipActionSize;
+ final int height = pipActionSize * 2 + mContext.getResources().getDimensionPixelSize(
+ R.dimen.pip_expand_action_size);
+ return new Size(width, height);
+ }
+
void setActions(Rect stackBounds, List<RemoteAction> actions) {
mActions.clear();
mActions.addAll(actions);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 41cc59d138fa..8fb358ad74d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -212,8 +212,14 @@ public class PipResizeGestureHandler {
// Register input event receiver
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"pip-resize", mDisplayId);
- mInputEventReceiver = new PipResizeInputEventReceiver(
- mInputMonitor.getInputChannel(), mMainExecutor.getLooper());
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ mInputEventReceiver = new PipResizeInputEventReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper());
+ });
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to create input event receiver", e);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index c9f5ae28175c..128d13c2ce2e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -32,6 +32,7 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Handler;
import android.provider.DeviceConfig;
+import android.util.Log;
import android.util.Size;
import android.view.InputEvent;
import android.view.MotionEvent;
@@ -95,7 +96,6 @@ public class PipTouchHandler {
private int mDeferResizeToNormalBoundsUntilRotation = -1;
private int mDisplayRotation;
- private final Handler mHandler = new Handler();
private final PipAccessibilityInteractionConnection mConnection;
// Behaviour states
@@ -176,7 +176,7 @@ public class PipTouchHandler {
mPipDismissTargetHandler = new PipDismissTargetHandler(context, pipUiEventLogger,
mMotionHelper, mainExecutor);
mTouchState = new PipTouchState(ViewConfiguration.get(context),
- () -> mMenuController.showMenuWithDelay(MENU_STATE_FULL,
+ () -> mMenuController.showMenuWithPossibleDelay(MENU_STATE_FULL,
mPipBoundsState.getBounds(), true /* allowMenuTimeout */, willResizeMenu(),
shouldShowResizeHandle()),
menuController::hideMenu,
@@ -925,16 +925,21 @@ public class PipTouchHandler {
}
/**
- * @return whether the menu will resize as a part of showing the full menu.
+ * @return {@code true} if the menu should be resized on tap because app explicitly specifies
+ * PiP window size that is too small to hold all the actions.
*/
private boolean willResizeMenu() {
if (!mEnableResize) {
return false;
}
- return mPipBoundsState.getExpandedBounds().width()
- != mPipBoundsState.getNormalBounds().width()
- || mPipBoundsState.getExpandedBounds().height()
- != mPipBoundsState.getNormalBounds().height();
+ final Size estimatedMenuSize = mMenuController.getEstimatedMenuSize();
+ if (estimatedMenuSize == null) {
+ Log.wtf(TAG, "Failed to get estimated menu size");
+ return false;
+ }
+ final Rect currentBounds = mPipBoundsState.getBounds();
+ return currentBounds.width() < estimatedMenuSize.getWidth()
+ || currentBounds.height() < estimatedMenuSize.getHeight();
}
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index b5d5d0fe8a38..564a418a1082 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -54,7 +54,7 @@ class AppPairsTestCannotPairNonResizeableApps(
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<Array<Any>> {
- val testTag = "testAppPairs_unpairPrimaryAndSecondaryApps"
+ val testTag = "testAppPairs_cannotPairNonResizeableApps"
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
withTestName {
buildTestTag(testTag, configuration)
@@ -71,7 +71,7 @@ class AppPairsTestCannotPairNonResizeableApps(
appPairsDividerIsInvisible()
}
windowManagerTrace {
- end {
+ end("onlyResizeableAppWindowVisible") {
val nonResizeableApp = nonResizeableApp
require(nonResizeableApp != null) {
"Non resizeable app not initialized"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 54e074c9c25d..f63eb1db4d5c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -76,7 +76,7 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
}
}
windowManagerTrace {
- end {
+ end("bothAppWindowsVisible") {
isVisible(primaryApp.defaultWindowName)
isVisible(secondaryApp.defaultWindowName)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 854a5041f631..731d99829b1d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -85,7 +85,7 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
}
}
windowManagerTrace {
- end {
+ end("bothAppWindowsInvisible") {
isInvisible(primaryApp.defaultWindowName)
isInvisible(secondaryApp.defaultWindowName)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index c436eb2d01d5..da3450bf9ff6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -66,7 +66,7 @@ class RotateTwoLaunchedAppsInAppPairsMode(
val instrumentation = InstrumentationRegistry.getInstrumentation()
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
withTestName {
- buildTestTag("testRotateAndEnterAppPairsMode", configuration)
+ buildTestTag("testRotateTwoLaunchedAppsInAppPairsMode", configuration)
}
transitions {
executeShellCommand(composePairsCommand(
@@ -88,7 +88,7 @@ class RotateTwoLaunchedAppsInAppPairsMode(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("bothAppWindowsVisible") {
isVisible(primaryApp.defaultWindowName)
.isVisible(secondaryApp.defaultWindowName)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index cd4f4f62d1b3..05543fdb3445 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -88,7 +88,7 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("bothAppWindowsVisible") {
isVisible(primaryApp.defaultWindowName)
isVisible(secondaryApp.defaultWindowName)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
index af99543199ac..dea5c300f590 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.dsl.runWithFlicker
@@ -115,7 +116,7 @@ class EnterLegacySplitScreenTest(
)
}
windowManagerTrace {
- end {
+ end("appWindowIsVisible") {
isVisible(splitScreenApp.defaultWindowName)
}
}
@@ -150,7 +151,7 @@ class EnterLegacySplitScreenTest(
)
}
windowManagerTrace {
- end {
+ end("appWindowIsVisible") {
isVisible(splitScreenApp.defaultWindowName)
.isVisible(secondaryApp.defaultWindowName)
}
@@ -162,6 +163,7 @@ class EnterLegacySplitScreenTest(
}
}
+ @FlakyTest(bugId = 173875043)
@Test
fun testNonResizeableNotDocked() {
val testTag = "testNonResizeableNotDocked"
@@ -185,7 +187,7 @@ class EnterLegacySplitScreenTest(
)
}
windowManagerTrace {
- end {
+ end("appWindowIsVisible") {
isInvisible(nonResizeableApp.defaultWindowName)
}
visibleWindowsShownMoreThanOneConsecutiveEntry(
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
index cd9a3c998d58..701b0d05e65c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
@@ -104,7 +104,7 @@ class ExitLegacySplitScreenTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("appWindowIsInvisible") {
isInvisible(splitScreenApp.defaultWindowName)
}
}
@@ -132,7 +132,7 @@ class ExitLegacySplitScreenTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("appWindowIsVisible") {
isVisible(splitScreenApp.defaultWindowName)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
index e79820f520dd..6fca5809b4fa 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
@@ -72,7 +72,7 @@ class NonResizableDismissInLegacySplitScreenTest(
)
}
windowManagerTrace {
- end {
+ end("nonResizeableAppWindowIsVisible") {
isVisible(nonResizeableApp.defaultWindowName)
.isInvisible(splitScreenApp.defaultWindowName)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
index 280af5d708c9..deae41fae0ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
@@ -72,7 +72,7 @@ class NonResizableLaunchInLegacySplitScreenTest(
)
}
windowManagerTrace {
- end {
+ end("nonResizeableAppWindowIsVisible") {
isVisible(nonResizeableApp.defaultWindowName)
.isInvisible(splitScreenApp.defaultWindowName)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
index fdf88df0f697..07571c3218a8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
@@ -99,7 +99,7 @@ class RotateOneLaunchedAppTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("appWindowIsVisible") {
isVisible(splitScreenApp.defaultWindowName)
}
}
@@ -131,7 +131,7 @@ class RotateOneLaunchedAppTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("appWindowIsVisible") {
isVisible(splitScreenApp.defaultWindowName)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
index 785ccf003504..d8014d37dfad 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.dsl.runWithFlicker
@@ -104,7 +105,7 @@ class RotateTwoLaunchedAppTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("appWindowIsVisible") {
isVisible(splitScreenApp.defaultWindowName)
.isVisible(secondaryApp.defaultWindowName)
}
@@ -113,6 +114,7 @@ class RotateTwoLaunchedAppTest(
}
}
+ @FlakyTest(bugId = 173875043)
@Test
fun testRotateAndEnterSplitScreenMode() {
val testTag = "testRotateAndEnterSplitScreenMode"
@@ -141,7 +143,7 @@ class RotateTwoLaunchedAppTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- end {
+ end("appWindowIsVisible") {
isVisible(splitScreenApp.defaultWindowName)
.isVisible(secondaryApp.defaultWindowName)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 812353ffe955..c21b594246b9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -131,7 +131,7 @@ class PipKeyboardTest(
}
assertions {
windowManagerTrace {
- end {
+ end("imeWindowAboveApp") {
isAboveWindow(IME_WINDOW_NAME, testApp.defaultWindowName)
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
index 5f5c30bb6207..bf84a6e30c98 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
@@ -40,6 +40,11 @@ public class TestShellExecutor implements ShellExecutor {
}
@Override
+ public void removeAllCallbacks() {
+ mRunnables.clear();
+ }
+
+ @Override
public void removeCallbacks(Runnable r) {
mRunnables.remove(r);
}
@@ -49,11 +54,6 @@ public class TestShellExecutor implements ShellExecutor {
return mRunnables.contains(r);
}
- @Override
- public Looper getLooper() {
- return null;
- }
-
public void flushAll() {
for (Runnable r : mRunnables) {
r.run();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java
index 9219f15afc7f..bbe8891817d6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java
@@ -33,6 +33,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
@@ -48,7 +49,7 @@ import java.util.ArrayList;
@RunWith(AndroidTestingRunner.class)
public class OneHandedTimeoutHandlerTest extends OneHandedTestCase {
private OneHandedTimeoutHandler mTimeoutHandler;
- private ShellExecutor mMainExecutor;
+ private TestShellExecutor mMainExecutor;
@Before
public void setUp() throws Exception {
@@ -104,34 +105,4 @@ public class OneHandedTimeoutHandlerTest extends OneHandedTestCase {
mTimeoutHandler.resetTimer();
assertTrue(mTimeoutHandler.hasScheduledTimeout());
}
-
- private class TestShellExecutor implements ShellExecutor {
- private ArrayList<Runnable> mExecuted = new ArrayList<>();
- private ArrayList<Runnable> mDelayed = new ArrayList<>();
-
- @Override
- public void execute(Runnable runnable) {
- mExecuted.add(runnable);
- }
-
- @Override
- public void executeDelayed(Runnable r, long delayMillis) {
- mDelayed.add(r);
- }
-
- @Override
- public void removeCallbacks(Runnable r) {
- mDelayed.remove(r);
- }
-
- @Override
- public boolean hasCallback(Runnable r) {
- return mDelayed.contains(r);
- }
-
- @Override
- public Looper getLooper() {
- return Looper.myLooper();
- }
- }
}
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index ab9b8b55a4cb..859a5556323d 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -362,13 +362,8 @@ static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& sourc
return source;
} else {
SkBitmap bitmap;
- const SkImageInfo& info = source.info();
- bitmap.allocPixels(info.makeColorType(kN32_SkColorType));
-
- SkCanvas canvas(bitmap);
- canvas.drawColor(0);
- canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
-
+ bitmap.allocPixels(source.info().makeColorType(kN32_SkColorType));
+ bitmap.writePixels(source.pixmap());
return bitmap;
}
}
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index f4c633fbe58f..ca2ada9e8141 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -127,10 +127,11 @@ void Layer::draw(SkCanvas* canvas) {
const SkMatrix& totalMatrix = canvas->getTotalMatrix();
SkRect imageRect = SkRect::MakeIWH(layerImage->width(), layerImage->height());
+ SkSamplingOptions sampling;
if (getForceFilter() || shouldFilterRect(totalMatrix, imageRect, imageRect)) {
- paint.setFilterQuality(kLow_SkFilterQuality);
+ sampling = SkSamplingOptions(SkFilterMode::kLinear);
}
- canvas->drawImage(layerImage.get(), 0, 0, &paint);
+ canvas->drawImage(layerImage.get(), 0, 0, sampling, &paint);
// restore the original matrix
if (nonIdentityMatrix) {
canvas->restore();
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 11a908696903..96118aaec29b 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -487,7 +487,9 @@ struct DrawVectorDrawable final : Op {
tree->getPaintFor(&paint, tree->stagingProperties());
}
- void draw(SkCanvas* canvas, const SkMatrix&) const { mRoot->draw(canvas, mBounds, paint); }
+ void draw(SkCanvas* canvas, const SkMatrix&) const {
+ mRoot->draw(canvas, mBounds, paint);
+ }
sp<VectorDrawableRoot> mRoot;
SkRect mBounds;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 1a8d9eb1f74f..8fddf713f1fa 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -565,7 +565,8 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
auto image = bitmap.makeImage();
apply_looper(paint, [&](const SkPaint& p) {
- mCanvas->drawImage(image, left, top, &p);
+ auto sampling = SkSamplingOptions(p.getFilterQuality());
+ mCanvas->drawImage(image, left, top, sampling, &p);
});
}
@@ -574,7 +575,8 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint*
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
apply_looper(paint, [&](const SkPaint& p) {
- mCanvas->drawImage(image, 0, 0, &p);
+ auto sampling = SkSamplingOptions(p.getFilterQuality());
+ mCanvas->drawImage(image, 0, 0, sampling, &p);
});
}
@@ -586,10 +588,17 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
apply_looper(paint, [&](const SkPaint& p) {
- mCanvas->drawImageRect(image, srcRect, dstRect, &p, SkCanvas::kFast_SrcRectConstraint);
+ auto sampling = SkSamplingOptions(p.getFilterQuality());
+ mCanvas->drawImageRect(image, srcRect, dstRect, sampling, &p,
+ SkCanvas::kFast_SrcRectConstraint);
});
}
+static SkFilterMode paintToFilter(const Paint* paint) {
+ return paint && paint->isFilterBitmap() ? SkFilterMode::kLinear
+ : SkFilterMode::kNearest;
+}
+
void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const Paint* paint) {
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
@@ -664,18 +673,25 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
}
#endif
+ auto image = bitmap.makeImage();
+
// cons-up a shader for the bitmap
Paint pnt;
if (paint) {
pnt = *paint;
}
- SkSamplingOptions sampling(pnt.isFilterBitmap() ? SkFilterMode::kLinear
- : SkFilterMode::kNearest,
- SkMipmapMode::kNone);
- pnt.setShader(bitmap.makeImage()->makeShader(sampling));
+ SkSamplingOptions sampling(paintToFilter(&pnt));
+ pnt.setShader(image->makeShader(sampling));
+
auto v = builder.detach();
apply_looper(&pnt, [&](const SkPaint& p) {
- mCanvas->drawVertices(v, SkBlendMode::kModulate, p);
+ SkPaint copy(p);
+ auto s = SkSamplingOptions(p.getFilterQuality());
+ if (s != sampling) {
+ // apply_looper changed the quality?
+ copy.setShader(image->makeShader(s));
+ }
+ mCanvas->drawVertices(v, SkBlendMode::kModulate, copy);
});
}
@@ -700,13 +716,11 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa
NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk, colors.get());
}
- SkFilterMode filter = paint && paint->isFilterBitmap() ? SkFilterMode::kLinear
- : SkFilterMode::kNearest;
-
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
auto image = bitmap.makeImage();
apply_looper(paint, [&](const SkPaint& p) {
+ auto filter = SkSamplingOptions(p.getFilterQuality()).filter;
mCanvas->drawImageLattice(image.get(), lattice, dst, filter, &p);
});
}
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 6030c36add7a..4a21ad6ab945 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -507,10 +507,12 @@ void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint)
sk_sp<SkImage> cachedBitmap = getBitmapUpdateIfDirty().makeImage();
+ // HWUI always draws VD with bilinear filtering.
+ auto sampling = SkSamplingOptions(SkFilterMode::kLinear);
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
canvas->drawImageRect(cachedBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
- &paint, SkCanvas::kFast_SrcRectConstraint);
+ sampling, &paint, SkCanvas::kFast_SrcRectConstraint);
}
void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index cceba59cc639..86b1ac71f692 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -351,21 +351,24 @@ struct CanvasOp<CanvasOpType::DrawImage> {
const sk_sp<Bitmap>& bitmap,
float left,
float top,
+ SkFilterMode filter,
SkPaint paint
) : left(left),
top(top),
+ filter(filter),
paint(std::move(paint)),
bitmap(bitmap),
image(bitmap->makeImage()) { }
float left;
float top;
+ SkFilterMode filter;
SkPaint paint;
sk_sp<Bitmap> bitmap;
sk_sp<SkImage> image;
void draw(SkCanvas* canvas) const {
- canvas->drawImage(image, left, top, &paint);
+ canvas->drawImage(image, left, top, SkSamplingOptions(filter), &paint);
}
ASSERT_DRAWABLE()
};
@@ -377,15 +380,18 @@ struct CanvasOp<CanvasOpType::DrawImageRect> {
const sk_sp<Bitmap>& bitmap,
SkRect src,
SkRect dst,
+ SkFilterMode filter,
SkPaint paint
) : src(src),
dst(dst),
+ filter(filter),
paint(std::move(paint)),
bitmap(bitmap),
image(bitmap->makeImage()) { }
SkRect src;
SkRect dst;
+ SkFilterMode filter;
SkPaint paint;
sk_sp<Bitmap> bitmap;
sk_sp<SkImage> image;
@@ -394,6 +400,7 @@ struct CanvasOp<CanvasOpType::DrawImageRect> {
canvas->drawImageRect(image,
src,
dst,
+ SkSamplingOptions(filter),
&paint,
SkCanvas::kFast_SrcRectConstraint
);
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index f055c6e0fa44..ade63e5b832c 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -437,11 +437,11 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
if (outputMatrix.invert(&inverse)) {
SkCanvas canvas(tmp, SkCanvas::ColorBehavior::kLegacy);
canvas.setMatrix(inverse);
- SkPaint paint;
- paint.setFilterQuality(kLow_SkFilterQuality); // bilinear
SkBitmap priorFrame;
priorFrame.installPixels(outputInfo, pixels, rowBytes);
- canvas.drawBitmap(priorFrame, 0, 0, &paint);
+ priorFrame.setImmutable(); // Don't want asImage() to force a copy
+ canvas.drawImage(priorFrame.asImage(), 0, 0,
+ SkSamplingOptions(SkFilterMode::kLinear));
} else {
ALOGE("Failed to invert matrix!");
}
@@ -458,11 +458,11 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
- paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering
SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
canvas.setMatrix(outputMatrix);
- canvas.drawBitmap(tmp, 0.0f, 0.0f, &paint);
+ tmp.setImmutable(); // Don't want asImage() to force copy
+ canvas.drawImage(tmp.asImage(), 0, 0, SkSamplingOptions(SkFilterMode::kLinear), &paint);
}
return result;
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index cf02051831c6..4e9daa4b0c16 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -457,11 +457,12 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
// outputBitmap. Otherwise we would blend by default, which is not
// what we want.
paint.setBlendMode(SkBlendMode::kSrc);
- paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering
SkCanvas canvas(outputBitmap, SkCanvas::ColorBehavior::kLegacy);
canvas.scale(scaleX, scaleY);
- canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
+ decodingBitmap.setImmutable(); // so .asImage() doesn't make a copy
+ canvas.drawImage(decodingBitmap.asImage(), 0.0f, 0.0f,
+ SkSamplingOptions(SkFilterMode::kLinear), &paint);
} else {
outputBitmap.swap(decodingBitmap);
}
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index f95f347cffaf..34df5ddbb210 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -141,18 +141,20 @@ bool LayerDrawable::DrawLayer(GrRecordingContext* context,
// then use nearest neighbor, otherwise use bilerp sampling.
// Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works
// only for SrcOver blending and without color filter (readback uses Src blending).
+ SkSamplingOptions sampling(SkFilterMode::kNearest);
if (layer->getForceFilter() ||
shouldFilterRect(totalMatrix, skiaSrcRect, skiaDestRect)) {
- paint.setFilterQuality(kLow_SkFilterQuality);
+ sampling = SkSamplingOptions(SkFilterMode::kLinear);
}
- canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint,
+ canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
SkCanvas::kFast_SrcRectConstraint);
} else {
SkRect imageRect = SkRect::MakeIWH(layerImage->width(), layerImage->height());
+ SkSamplingOptions sampling(SkFilterMode::kNearest);
if (layer->getForceFilter() || shouldFilterRect(totalMatrix, imageRect, imageRect)) {
- paint.setFilterQuality(kLow_SkFilterQuality);
+ sampling = SkSamplingOptions(SkFilterMode::kLinear);
}
- canvas->drawImage(layerImage.get(), 0, 0, &paint);
+ canvas->drawImage(layerImage.get(), 0, 0, sampling, &paint);
}
// restore the original matrix
if (nonIdentityMatrix) {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 070a765cf7ca..75815bb6e63d 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -169,7 +169,6 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) const {
static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier,
SkPaint* paint) {
- paint->setFilterQuality(kLow_SkFilterQuality);
if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
properties.getImageFilter() != nullptr) {
@@ -226,6 +225,7 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer);
SkPaint paint;
layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
+ SkSamplingOptions sampling(SkFilterMode::kLinear);
// surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so
// we need to restrict the portion of the surface drawn to the size of the renderNode.
@@ -239,7 +239,7 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
"SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
}
canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot(), bounds,
- bounds, &paint);
+ bounds, sampling, &paint, SkCanvas::kStrict_SrcRectConstraint);
if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 80eddafbde4f..6456e36a847a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -656,7 +656,7 @@ void SkiaPipeline::renderOverdraw(const SkRect& clip,
SkPaint paint;
const SkColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
paint.setColorFilter(SkOverdrawColorFilter::MakeWithSkColors(colors));
- surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint);
+ surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, SkSamplingOptions(), &paint);
}
} /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index bc8ce428ce2e..bae11f7d074c 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -182,7 +182,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
auto functorImage = SkImage::MakeFromAHardwareBuffer(mFrameBuffer.get(), kPremul_SkAlphaType,
canvas->imageInfo().refColorSpace(),
kBottomLeft_GrSurfaceOrigin);
- canvas->drawImage(functorImage, 0, 0, &paint);
+ canvas->drawImage(functorImage, 0, 0, SkSamplingOptions(), &paint);
canvas->restore();
}
diff --git a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
index 1d17a021069b..716d3979bdcb 100644
--- a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
+++ b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
@@ -51,7 +51,7 @@ public:
hardwareBitmap->height(), &canvasBitmap));
SkCanvas skCanvas(canvasBitmap);
- skCanvas.drawBitmap(readback, 0, 0);
+ skCanvas.drawImage(readback.asImage(), 0, 0);
canvas.drawBitmap(*heapBitmap, 0, 0, nullptr);
canvas.drawBitmap(*hardwareBitmap, 0, 500, nullptr);
diff --git a/libs/hwui/tests/microbench/CanvasOpBench.cpp b/libs/hwui/tests/microbench/CanvasOpBench.cpp
index ef5749e6b79b..e7ba471ee807 100644
--- a/libs/hwui/tests/microbench/CanvasOpBench.cpp
+++ b/libs/hwui/tests/microbench/CanvasOpBench.cpp
@@ -85,6 +85,7 @@ void BM_CanvasOpBuffer_record_simpleBitmapView(benchmark::State& benchState) {
iconBitmap,
0,
0,
+ SkFilterMode::kNearest,
SkPaint{}
});
canvas.restore();
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index c9e8d808f995..54970df534b9 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -474,6 +474,7 @@ TEST(CanvasOp, simpleDrawImage) {
bitmap,
7,
19,
+ SkFilterMode::kNearest,
SkPaint{}
}
);
@@ -496,7 +497,7 @@ TEST(CanvasOp, simpleDrawImageRect) {
buffer.push<Op::DrawImageRect> ({
bitmap, SkRect::MakeWH(100, 100),
SkRect::MakeLTRB(120, 110, 220, 210),
- SkPaint{}
+ SkFilterMode::kNearest, SkPaint{}
}
);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index decf68f26c0e..67a2c49e5746 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -166,6 +166,11 @@ cc_library_shared {
"tv_tuner_aidl_interface-ndk_platform",
"tv_tuner_resource_manager_aidl_interface-ndk_platform"
],
+
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+
defaults: [
"libcodec2-impl-defaults",
],
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index eb63d76741c4..9ec84d9d2265 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1458,7 +1458,7 @@ int JTuner::tune(const FrontendSettings& settings, const FrontendSettingsExt1_1&
ALOGE("frontend is not initialized");
return (int)Result::INVALID_STATE;
}
- return (int) mFeClient->tune(settings,settingsExt1_1);
+ return (int) mFeClient->tune(settings, settingsExt1_1);
}
int JTuner::stopTune() {
diff --git a/media/jni/tuner/DemuxClient.cpp b/media/jni/tuner/DemuxClient.cpp
index e290c60db8ce..1a2f8c065bd3 100644
--- a/media/jni/tuner/DemuxClient.cpp
+++ b/media/jni/tuner/DemuxClient.cpp
@@ -142,7 +142,16 @@ long DemuxClient::getAvSyncTime(int avSyncHwId) {
}
sp<DvrClient> DemuxClient::openDvr(DvrType dvbType, int bufferSize, sp<DvrClientCallback> cb) {
- // TODO: pending aidl interface
+ if (mTunerDemux != NULL) {
+ shared_ptr<ITunerDvr> tunerDvr;
+ shared_ptr<TunerDvrCallback> callback =
+ ::ndk::SharedRefBase::make<TunerDvrCallback>(cb);
+ Status s = mTunerDemux->openDvr((int)dvbType, bufferSize, callback, &tunerDvr);
+ if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
+ return NULL;
+ }
+ return new DvrClient(tunerDvr);
+ }
if (mDemux != NULL) {
sp<HidlDvrCallback> callback = new HidlDvrCallback(cb);
@@ -178,7 +187,10 @@ Result DemuxClient::disconnectCiCam() {
}
Result DemuxClient::close() {
- // TODO: pending aidl interface
+ if (mTunerDemux != NULL) {
+ Status s = mTunerDemux->close();
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mDemux != NULL) {
Result res = mDemux->close();
diff --git a/media/jni/tuner/DvrClient.cpp b/media/jni/tuner/DvrClient.cpp
index be592af30f5d..04004858aaee 100644
--- a/media/jni/tuner/DvrClient.cpp
+++ b/media/jni/tuner/DvrClient.cpp
@@ -210,14 +210,13 @@ Result DvrClient::configure(DvrSettings settings) {
return res;
}
- AidlMQDesc* aidlMqDesc = NULL;
- s = mTunerDvr->getQueueDesc(aidlMqDesc);
+ AidlMQDesc aidlMqDesc;
+ s = mTunerDvr->getQueueDesc(&aidlMqDesc);
res = ClientHelper::getServiceSpecificErrorCode(s);
if (res != Result::SUCCESS) {
return res;
}
-
- mDvrMQ = new (nothrow) AidlMQ(*aidlMqDesc);
+ mDvrMQ = new (nothrow) AidlMQ(aidlMqDesc);
EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
return res;
}
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index bcef0a2f4413..bdc8a4f1eb36 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -16,14 +16,21 @@
#define LOG_TAG "FilterClient"
+#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
#include <utils/Log.h>
#include "FilterClient.h"
+using ::aidl::android::media::tv::tuner::TunerFilterAvSettings;
+using ::aidl::android::media::tv::tuner::TunerFilterSharedHandleInfo;
+using ::aidl::android::media::tv::tuner::TunerFilterTsConfiguration;
+
using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxStreamId;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
namespace android {
@@ -48,7 +55,6 @@ FilterClient::~FilterClient() {
void FilterClient::setHidlFilter(sp<IFilter> filter) {
mFilter = filter;
mFilter_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilter);
- handleAvShareMemory();
}
int FilterClient::read(uint8_t* buffer, int size) {
@@ -66,23 +72,20 @@ int FilterClient::read(uint8_t* buffer, int size) {
}
SharedHandleInfo FilterClient::getAvSharedHandleInfo() {
+ handleAvShareMemory();
SharedHandleInfo info{
- .sharedHandle = NULL,
- .size = 0,
+ .sharedHandle = mAvSharedHandle,
+ .size = mAvSharedMemSize,
};
- // TODO: pending aidl interface
-
- if (mFilter_1_1 != NULL) {
- info.sharedHandle = mAvSharedHandle;
- info.size = mAvSharedMemSize;
- }
-
return info;
}
Result FilterClient::configure(DemuxFilterSettings configure) {
- // TODO: pending aidl interface
+ if (mTunerFilter != NULL) {
+ Status s = mTunerFilter->configure(getAidlFilterSettings(configure));
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mFilter != NULL) {
return mFilter->configure(configure);
@@ -122,7 +125,10 @@ Result FilterClient::configureAvStreamType(AvStreamType avStreamType) {
}
Result FilterClient::start() {
- // TODO: pending aidl interface
+ if (mTunerFilter != NULL) {
+ Status s = mTunerFilter->start();
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mFilter != NULL) {
return mFilter->start();
@@ -132,7 +138,10 @@ Result FilterClient::start() {
}
Result FilterClient::stop() {
- // TODO: pending aidl interface
+ if (mTunerFilter != NULL) {
+ Status s = mTunerFilter->stop();
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mFilter != NULL) {
return mFilter->stop();
@@ -142,7 +151,10 @@ Result FilterClient::stop() {
}
Result FilterClient::flush() {
- // TODO: pending aidl interface
+ if (mTunerFilter != NULL) {
+ Status s = mTunerFilter->flush();
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mFilter != NULL) {
return mFilter->flush();
@@ -192,7 +204,10 @@ Result FilterClient::getId64Bit(uint64_t& id) {
}
Result FilterClient::releaseAvHandle(native_handle_t* handle, uint64_t avDataId) {
- // TODO: pending aidl interface
+ if (mTunerFilter != NULL) {
+ Status s = mTunerFilter->releaseAvHandle(makeToAidl(handle), avDataId);
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mFilter != NULL) {
return mFilter->releaseAvHandle(hidl_handle(handle), avDataId);
@@ -216,13 +231,18 @@ Result FilterClient::setDataSource(sp<FilterClient> filterClient){
}
Result FilterClient::close() {
- // TODO: pending aidl interface
+ if (mTunerFilter != NULL) {
+ Status s = mTunerFilter->close();
+ closeAvSharedMemory();
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mFilter != NULL) {
Result res = mFilter->close();
if (res == Result::SUCCESS) {
mFilter = NULL;
}
+ closeAvSharedMemory();
return res;
}
@@ -269,13 +289,103 @@ Status TunerFilterCallback::onFilterStatus(int status) {
return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
}
-Status TunerFilterCallback::onFilterEvent(vector<TunerFilterEvent>* /*filterEvent*/) {
- // TODO: complete onFilterEvent
+Status TunerFilterCallback::onFilterEvent(const vector<TunerFilterEvent>& filterEvents) {
+ if (mFilterClientCallback == NULL) {
+ return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
+ }
+
+ DemuxFilterEvent event;
+ DemuxFilterEventExt eventExt;
+ getHidlFilterEvent(filterEvents, event, eventExt);
+ if (eventExt.events.size() > 0) {
+ mFilterClientCallback->onFilterEvent_1_1(event, eventExt);
+ } else {
+ mFilterClientCallback->onFilterEvent(event);
+ }
+
return Status::ok();
}
/////////////// FilterClient Helper Methods ///////////////////////
+TunerFilterConfiguration FilterClient::getAidlFilterSettings(DemuxFilterSettings configure) {
+ TunerFilterConfiguration config;
+ // TODO: complete filter setting conversion
+ switch (configure.getDiscriminator()) {
+ case DemuxFilterSettings::hidl_discriminator::ts: {
+ TunerFilterSettings filterSettings;
+ switch (configure.ts().filterSettings.getDiscriminator()) {
+ case DemuxTsFilterSettings::FilterSettings::hidl_discriminator::av: {
+ TunerFilterAvSettings av{
+ .isPassthrough = configure.ts().filterSettings.av().isPassthrough,
+ };
+ filterSettings.set<TunerFilterSettings::av>(av);
+ break;
+ }
+ default:
+ break;
+ }
+
+ TunerFilterTsConfiguration ts{
+ .tpid = configure.ts().tpid,
+ .filterSettings = filterSettings,
+ };
+ config.set<TunerFilterConfiguration::ts>(ts);
+
+ return config;
+ }
+ case DemuxFilterSettings::hidl_discriminator::mmtp:
+ break;
+ case DemuxFilterSettings::hidl_discriminator::ip:
+ break;
+ case DemuxFilterSettings::hidl_discriminator::tlv:
+ break;
+ default:
+ break;
+ }
+ return config;
+}
+
+
+void TunerFilterCallback::getHidlFilterEvent(const vector<TunerFilterEvent>& filterEvents,
+ DemuxFilterEvent& event, DemuxFilterEventExt& /*eventExt*/) {
+ // TODO: finish handling extended evets and other filter event types
+ switch (filterEvents[0].getTag()) {
+ case TunerFilterEvent::media: {
+ for (int i = 0; i < filterEvents.size(); i++) {
+ hidl_handle handle = hidl_handle(
+ makeFromAidl(filterEvents[i].get<TunerFilterEvent::media>().avMemory));
+ int size = event.events.size();
+ event.events.resize(size + 1);
+ event.events[size].media({
+ .avMemory = handle,
+ .streamId = static_cast<DemuxStreamId>(
+ filterEvents[i].get<TunerFilterEvent::media>().streamId),
+ .isPtsPresent =
+ filterEvents[i].get<TunerFilterEvent::media>().isPtsPresent,
+ .pts = static_cast<uint64_t>(
+ filterEvents[i].get<TunerFilterEvent::media>().pts),
+ .dataLength = static_cast<uint32_t>(
+ filterEvents[i].get<TunerFilterEvent::media>().dataLength),
+ .offset = static_cast<uint32_t>(
+ filterEvents[i].get<TunerFilterEvent::media>().offset),
+ .isSecureMemory =
+ filterEvents[i].get<TunerFilterEvent::media>().isSecureMemory,
+ .avDataId = static_cast<uint64_t>(
+ filterEvents[i].get<TunerFilterEvent::media>().avDataId),
+ .mpuSequenceNumber = static_cast<uint32_t>(
+ filterEvents[i].get<TunerFilterEvent::media>().offset),
+ .isPesPrivateData =
+ filterEvents[i].get<TunerFilterEvent::media>().isPesPrivateData,
+ });
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
Result FilterClient::getFilterMq() {
if (mFilter == NULL) {
return Result::INVALID_STATE;
@@ -333,6 +443,20 @@ void FilterClient::checkIsMediaFilter(DemuxFilterType type) {
}
void FilterClient::handleAvShareMemory() {
+ if (mAvSharedHandle != NULL) {
+ return;
+ }
+
+ if (mTunerFilter != NULL && mIsMediaFilter) {
+ TunerFilterSharedHandleInfo aidlHandleInfo;
+ Status s = mTunerFilter->getAvSharedHandleInfo(&aidlHandleInfo);
+ if (ClientHelper::getServiceSpecificErrorCode(s) == Result::SUCCESS) {
+ mAvSharedHandle = native_handle_clone(makeFromAidl(aidlHandleInfo.handle));
+ mAvSharedMemSize = aidlHandleInfo.size;
+ }
+ return;
+ }
+
if (mFilter_1_1 != NULL && mIsMediaFilter) {
mFilter_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
if (r == Result::SUCCESS) {
@@ -342,4 +466,10 @@ void FilterClient::handleAvShareMemory() {
});
}
}
+
+void FilterClient::closeAvSharedMemory() {
+ native_handle_close(mAvSharedHandle);
+ native_handle_delete(mAvSharedHandle);
+ mAvSharedMemSize = 0;
+}
} // namespace android
diff --git a/media/jni/tuner/FilterClient.h b/media/jni/tuner/FilterClient.h
index 7c85125c4c75..f5539e0cc54a 100644
--- a/media/jni/tuner/FilterClient.h
+++ b/media/jni/tuner/FilterClient.h
@@ -20,6 +20,8 @@
#include <aidl/android/media/tv/tuner/ITunerFilter.h>
#include <aidl/android/media/tv/tuner/BnTunerFilterCallback.h>
#include <aidl/android/media/tv/tuner/TunerFilterEvent.h>
+#include <aidl/android/media/tv/tuner/TunerFilterSettings.h>
+#include <aidlcommonsupport/NativeHandle.h>
#include <android/hardware/tv/tuner/1.1/IFilter.h>
#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
#include <android/hardware/tv/tuner/1.1/types.h>
@@ -31,7 +33,9 @@
using Status = ::ndk::ScopedAStatus;
using ::aidl::android::media::tv::tuner::BnTunerFilterCallback;
using ::aidl::android::media::tv::tuner::ITunerFilter;
+using ::aidl::android::media::tv::tuner::TunerFilterConfiguration;
using ::aidl::android::media::tv::tuner::TunerFilterEvent;
+using ::aidl::android::media::tv::tuner::TunerFilterSettings;
using ::android::hardware::EventFlag;
using ::android::hardware::MessageQueue;
@@ -61,11 +65,13 @@ class TunerFilterCallback : public BnTunerFilterCallback {
public:
TunerFilterCallback(sp<FilterClientCallback> filterClientCallback);
- // TODO: complete TunerFilterCallback
Status onFilterStatus(int status);
- Status onFilterEvent(vector<TunerFilterEvent>* filterEvent);
+ Status onFilterEvent(const vector<TunerFilterEvent>& filterEvents);
private:
+ void getHidlFilterEvent(const vector<TunerFilterEvent>& filterEvents,
+ DemuxFilterEvent& event, DemuxFilterEventExt& eventExt);
+
sp<FilterClientCallback> mFilterClientCallback;
};
@@ -174,10 +180,12 @@ public:
Result close();
private:
+ TunerFilterConfiguration getAidlFilterSettings(DemuxFilterSettings configure);
Result getFilterMq();
int copyData(uint8_t* buffer, int size);
void checkIsMediaFilter(DemuxFilterType type);
void handleAvShareMemory();
+ void closeAvSharedMemory();
/**
* An AIDL Tuner Filter Singleton assigned at the first time when the Tuner Client
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index ef8f57f69f31..0540aac3672d 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -21,8 +21,8 @@
#include "FrontendClient.h"
+using ::aidl::android::media::tv::tuner::TunerFrontendDvbtSettings;
using ::aidl::android::media::tv::tuner::TunerFrontendScanAtsc3PlpInfo;
-using ::aidl::android::media::tv::tuner::TunerFrontendSettings;
using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
using ::android::hardware::tv::tuner::V1_0::FrontendAnalogType;
@@ -86,10 +86,9 @@ void FrontendClient::setHidlFrontend(sp<IFrontend> frontend) {
Result FrontendClient::tune(const FrontendSettings& settings,
const FrontendSettingsExt1_1& settingsExt1_1) {
if (mTunerFrontend != NULL) {
- // TODO: parse hidl settings to aidl settings
// TODO: aidl frontend settings to include Tuner HAL 1.1 settings
- TunerFrontendSettings settings;
- Status s = mTunerFrontend->tune(settings);
+ TunerFrontendSettings tunerFeSettings = getAidlFrontendSettings(settings, settingsExt1_1);
+ Status s = mTunerFrontend->tune(tunerFeSettings);
return ClientHelper::getServiceSpecificErrorCode(s);
}
@@ -124,10 +123,9 @@ Result FrontendClient::stopTune() {
Result FrontendClient::scan(const FrontendSettings& settings, FrontendScanType type,
const FrontendSettingsExt1_1& settingsExt1_1) {
if (mTunerFrontend != NULL) {
- // TODO: parse hidl settings to aidl settings
// TODO: aidl frontend settings to include Tuner HAL 1.1 settings
- TunerFrontendSettings settings;
- Status s = mTunerFrontend->scan(settings, (int)type);
+ TunerFrontendSettings tunerFeSettings = getAidlFrontendSettings(settings, settingsExt1_1);
+ Status s = mTunerFrontend->scan(tunerFeSettings, (int)type);
return ClientHelper::getServiceSpecificErrorCode(s);
}
@@ -279,7 +277,6 @@ Result FrontendClient::unlinkCiCamToFrontend(int ciCamId) {
Result FrontendClient::close() {
if (mTunerFrontend != NULL) {
- // TODO: handle error message.
Status s = mTunerFrontend->close();
return ClientHelper::getServiceSpecificErrorCode(s);
}
@@ -304,6 +301,61 @@ int FrontendClient::getId() {
return mId;
}
+TunerFrontendSettings FrontendClient::getAidlFrontendSettings(const FrontendSettings& settings,
+ const FrontendSettingsExt1_1& /*settingsExt1_1*/) {
+ // TODO: complete hidl to aidl frontend settings conversion
+ TunerFrontendSettings s;
+ switch (settings.getDiscriminator()) {
+ case FrontendSettings::hidl_discriminator::analog: {
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::atsc: {
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::atsc3: {
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::dvbs: {
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::dvbc: {
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::dvbt: {
+ TunerFrontendDvbtSettings dvbtSettings{
+ .frequency = (int)settings.dvbt().frequency,
+ .transmissionMode = (int)settings.dvbt().transmissionMode,
+ .bandwidth = (int)settings.dvbt().bandwidth,
+ .constellation = (int)settings.dvbt().constellation,
+ .hierarchy = (int)settings.dvbt().hierarchy,
+ .hpCodeRate = (int)settings.dvbt().hpCoderate,
+ .lpCodeRate = (int)settings.dvbt().lpCoderate,
+ .guardInterval = (int)settings.dvbt().guardInterval,
+ .isHighPriority = settings.dvbt().isHighPriority,
+ .standard = (int)settings.dvbt().standard,
+ .isMiso = settings.dvbt().isMiso,
+ .plpMode = (int)settings.dvbt().plpMode,
+ .plpId = (int)settings.dvbt().plpId,
+ .plpGroupId = (int)settings.dvbt().plpGroupId,
+ };
+ s.set<TunerFrontendSettings::dvbt>(dvbtSettings);
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::isdbs: {
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::isdbs3: {
+ break;
+ }
+ case FrontendSettings::hidl_discriminator::isdbt: {
+ break;
+ }
+ default:
+ break;
+ }
+ return s;
+}
+
/////////////// TunerFrontendCallback ///////////////////////
TunerFrontendCallback::TunerFrontendCallback(sp<FrontendClientCallback> frontendClientCallback)
diff --git a/media/jni/tuner/FrontendClient.h b/media/jni/tuner/FrontendClient.h
index 03ebb8704ef7..17fd583cbaae 100644
--- a/media/jni/tuner/FrontendClient.h
+++ b/media/jni/tuner/FrontendClient.h
@@ -32,6 +32,7 @@ using Status = ::ndk::ScopedAStatus;
using ::aidl::android::media::tv::tuner::BnTunerFrontendCallback;
using ::aidl::android::media::tv::tuner::ITunerFrontend;
using ::aidl::android::media::tv::tuner::TunerFrontendScanMessage;
+using ::aidl::android::media::tv::tuner::TunerFrontendSettings;
using ::android::hardware::Return;
using ::android::hardware::Void;
@@ -171,6 +172,9 @@ public:
int getId();
private:
+ TunerFrontendSettings getAidlFrontendSettings(const FrontendSettings& settings,
+ const FrontendSettingsExt1_1& settingsExt1_1);
+
/**
* An AIDL Tuner Frontend Singleton assigned at the first time when the Tuner Client
* opens a frontend cient. Default null when the service does not exist.
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index 4498f54b71cc..14393a1081c6 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -235,7 +235,8 @@ sp<DescramblerClient> TunerClient::openDescrambler(int /*descramblerHandle*/) {
}
}
- return NULL;}
+ return NULL;
+}
sp<LnbClient> TunerClient::openLnb(int lnbHandle) {
if (mTunerService != NULL) {
diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h
index 0f930b5443e4..742db34b74a7 100644
--- a/media/native/midi/include/amidi/AMidi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -61,8 +61,6 @@ enum {
AMIDI_DEVICE_TYPE_BLUETOOTH = 3 /* A MIDI device connected via BlueTooth */
};
-#if __ANDROID_API__ >= 29
-
/*
* Device API
*/
@@ -249,8 +247,6 @@ media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPor
*/
void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
-#endif /* __ANDROID_API__ >= 29 */
-
#ifdef __cplusplus
}
#endif
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 6d7e86f64944..34da30555fb3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -108,7 +108,7 @@ public class BatterySaverUtils {
* - If it's the first time and needFirstTimeWarning, show the first time dialog.
* - If it's 4th time through 8th time, show the schedule suggestion notification.
*
- * @param enable true to disable battery saver.
+ * @param enable true to enable battery saver.
*
* @return true if the request succeeded.
*/
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 266bfe0a22b5..6568bffddecc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -846,8 +846,8 @@ class DatabaseHelper extends SQLiteOpenHelper {
try {
stmt = db.compileStatement("INSERT INTO system(name,value)"
+ " VALUES(?,?);");
- loadBooleanSetting(stmt, Settings.System.USER_ROTATION,
- R.integer.def_user_rotation); // should be zero degrees
+ loadIntegerSetting(stmt, Settings.System.USER_ROTATION,
+ R.integer.def_user_rotation);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
@@ -2265,6 +2265,8 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
R.bool.def_accelerometer_rotation);
+ loadIntegerSetting(stmt, Settings.System.USER_ROTATION, R.integer.def_user_rotation);
+
loadDefaultHapticSettings(stmt);
loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7eab559cb9b9..1af7781dff96 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -304,9 +304,6 @@
<uses-permission android:name="android.permission.RESTART_WIFI_SUBSYSTEM" />
<!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
- <uses-permission android:name="android.permission.NETWORK_AIRPLANE_MODE" />
-
- <!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
<uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL" />
<!-- Permission needed to use wifi usability API's for CtsNetTestCases -->
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
index 796123db7c79..04e645bd0a32 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
@@ -32,9 +32,8 @@
<com.android.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- androidprv:layout_maxHeight="@dimen/keyguard_security_max_height"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:padding="0dp"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index dc77bd356e55..70f495c1245b 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -46,7 +46,6 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
- android:layout_weight="1"
android:layoutDirection="ltr"
>
<include layout="@layout/keyguard_esim_area"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 9df1230d7656..7ba906986fa3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -192,19 +192,6 @@ public class RemoteTransitionCompat implements Parcelable {
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
-
- @DataClass.Generated.Member
- /* package-private */ RemoteTransitionCompat(
- @NonNull IRemoteTransition transition,
- @Nullable TransitionFilter filter) {
- this.mTransition = transition;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mTransition);
- this.mFilter = filter;
-
- // onConstructed(); // You can define this method to get a callback
- }
-
@DataClass.Generated.Member
public @NonNull IRemoteTransition getTransition() {
return mTransition;
@@ -308,9 +295,8 @@ public class RemoteTransitionCompat implements Parcelable {
if ((mBuilderFieldsSet & 0x2) == 0) {
mFilter = null;
}
- RemoteTransitionCompat o = new RemoteTransitionCompat(
- mTransition,
- mFilter);
+ RemoteTransitionCompat o = new RemoteTransitionCompat(mTransition);
+ o.mFilter = this.mFilter;
return o;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index fbabaa489d74..70021b6f3d45 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -114,13 +114,10 @@ public class SyncRtSurfaceTransactionApplierCompat {
for (int i = params.length - 1; i >= 0; i--) {
SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
params[i];
+ t.deferTransactionUntil(surfaceParams.surface, mBarrierSurfaceControl, frame);
surfaceParams.applyTo(t);
}
- if (mTargetViewRootImpl != null) {
- mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
- } else {
- t.apply();
- }
+ t.apply();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
.sendToTarget();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index 89c60f1d3f06..4a28d56a41e1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -56,12 +56,4 @@ public class ViewRootImplCompat {
});
}
}
-
- public void mergeWithNextTransaction(SurfaceControl.Transaction t, long frame) {
- if (mViewRoot != null) {
- mViewRoot.mergeWithNextTransaction(t, frame);
- } else {
- t.apply();
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index a40dc7abf063..85e9ca05d428 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import android.app.Presentation;
import android.content.Context;
@@ -116,6 +117,14 @@ public class KeyguardDisplayManager {
if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on a private display");
return false;
}
+ if (mTmpDisplayInfo.displayGroupId != DEFAULT_DISPLAY_GROUP) {
+ if (DEBUG) {
+ Log.i(TAG,
+ "Do not show KeyguardPresentation on a non-default group display");
+ }
+ return false;
+ }
+
return true;
}
/**
@@ -130,8 +139,7 @@ public class KeyguardDisplayManager {
final int displayId = display.getDisplayId();
Presentation presentation = mPresentations.get(displayId);
if (presentation == null) {
- final Presentation newPresentation = new KeyguardPresentation(mContext, display,
- mKeyguardStatusViewComponentFactory);
+ final Presentation newPresentation = createPresentation(display);
newPresentation.setOnDismissListener(dialog -> {
if (newPresentation.equals(mPresentations.get(displayId))) {
mPresentations.remove(displayId);
@@ -152,6 +160,10 @@ public class KeyguardDisplayManager {
return false;
}
+ KeyguardPresentation createPresentation(Display display) {
+ return new KeyguardPresentation(mContext, display, mKeyguardStatusViewComponentFactory);
+ }
+
/**
* @param displayId The id of the display to hide the presentation off.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
index 93a8df41c673..cd3d6a84a352 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
@@ -26,8 +26,7 @@ public class AppOpItem {
private String mPackageName;
private long mTimeStarted;
private StringBuilder mState;
- // This is only used for items with mCode == AppOpsManager.OP_RECORD_AUDIO
- private boolean mSilenced;
+ private boolean mIsDisabled;
public AppOpItem(int code, int uid, String packageName, long timeStarted) {
this.mCode = code;
@@ -58,16 +57,16 @@ public class AppOpItem {
return mTimeStarted;
}
- public void setSilenced(boolean silenced) {
- mSilenced = silenced;
+ public void setDisabled(boolean misDisabled) {
+ this.mIsDisabled = misDisabled;
}
- public boolean isSilenced() {
- return mSilenced;
+ public boolean isDisabled() {
+ return mIsDisabled;
}
@Override
public String toString() {
- return mState.append(mSilenced).append(")").toString();
+ return mState.append(mIsDisabled).append(")").toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 1036c9916c8b..d8ca63960b30 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.appops;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
import android.Manifest;
@@ -45,6 +47,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.util.Assert;
import java.io.FileDescriptor;
@@ -64,7 +67,8 @@ import javax.inject.Inject;
@SysUISingleton
public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController,
AppOpsManager.OnOpActiveChangedInternalListener,
- AppOpsManager.OnOpNotedListener, Dumpable {
+ AppOpsManager.OnOpNotedListener, IndividualSensorPrivacyController.Callback,
+ Dumpable {
// This is the minimum time that we will keep AppOps that are noted on record. If multiple
// occurrences of the same (op, package, uid) happen in a shorter interval, they will not be
@@ -77,8 +81,8 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
private final AppOpsManager mAppOps;
private final AudioManager mAudioManager;
private final LocationManager mLocationManager;
- // TODO ntmyren: remove t
private final PackageManager mPackageManager;
+ private final IndividualSensorPrivacyController mSensorPrivacyController;
// mLocationProviderPackages are cached and updated only occasionally
private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
@@ -91,6 +95,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
private final PermissionFlagsCache mFlagsCache;
private boolean mListening;
private boolean mMicMuted;
+ private boolean mCameraDisabled;
@GuardedBy("mActiveItems")
private final List<AppOpItem> mActiveItems = new ArrayList<>();
@@ -118,6 +123,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
DumpManager dumpManager,
PermissionFlagsCache cache,
AudioManager audioManager,
+ IndividualSensorPrivacyController sensorPrivacyController,
BroadcastDispatcher dispatcher
) {
mDispatcher = dispatcher;
@@ -129,7 +135,10 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
mCallbacksByCode.put(OPS[i], new ArraySet<>());
}
mAudioManager = audioManager;
- mMicMuted = audioManager.isMicrophoneMute();
+ mSensorPrivacyController = sensorPrivacyController;
+ mMicMuted = audioManager.isMicrophoneMute()
+ || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
mLocationManager = context.getSystemService(LocationManager.class);
mPackageManager = context.getPackageManager();
dumpManager.registerDumpable(TAG, this);
@@ -147,6 +156,12 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
mAppOps.startWatchingActive(OPS, this);
mAppOps.startWatchingNoted(OPS, this);
mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
+ mSensorPrivacyController.addCallback(this);
+
+ mMicMuted = mAudioManager.isMicrophoneMute()
+ || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+
mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
mAudioManager.getActiveRecordingConfigurations()));
mDispatcher.registerReceiverWithHandler(this,
@@ -156,6 +171,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
mAppOps.stopWatchingActive(this);
mAppOps.stopWatchingNoted(this);
mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback);
+ mSensorPrivacyController.removeCallback(this);
mBGHandler.removeCallbacksAndMessages(null); // null removes all
mDispatcher.unregisterReceiver(this);
@@ -235,11 +251,13 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
if (item == null && active) {
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
if (code == AppOpsManager.OP_RECORD_AUDIO) {
- item.setSilenced(isAnyRecordingPausedLocked(uid));
+ item.setDisabled(isAnyRecordingPausedLocked(uid));
+ } else if (code == AppOpsManager.OP_CAMERA) {
+ item.setDisabled(mCameraDisabled);
}
mActiveItems.add(item);
if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
- return !item.isSilenced();
+ return !item.isDisabled();
} else if (item != null && !active) {
mActiveItems.remove(item);
if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
@@ -409,7 +427,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
AppOpItem item = mActiveItems.get(i);
if ((userId == UserHandle.USER_ALL
|| UserHandle.getUserId(item.getUid()) == userId)
- && isUserVisible(item) && !item.isSilenced()) {
+ && isUserVisible(item) && !item.isDisabled()) {
list.add(item);
}
}
@@ -512,22 +530,27 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
return false;
}
- private void updateRecordingPausedStatus() {
+ private void updateSensorDisabledStatus() {
synchronized (mActiveItems) {
int size = mActiveItems.size();
for (int i = 0; i < size; i++) {
AppOpItem item = mActiveItems.get(i);
+
+ boolean paused = false;
if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) {
- boolean paused = isAnyRecordingPausedLocked(item.getUid());
- if (item.isSilenced() != paused) {
- item.setSilenced(paused);
- notifySuscribers(
- item.getCode(),
- item.getUid(),
- item.getPackageName(),
- !item.isSilenced()
- );
- }
+ paused = isAnyRecordingPausedLocked(item.getUid());
+ } else if (item.getCode() == AppOpsManager.OP_CAMERA) {
+ paused = mCameraDisabled;
+ }
+
+ if (item.isDisabled() != paused) {
+ item.setDisabled(paused);
+ notifySuscribers(
+ item.getCode(),
+ item.getUid(),
+ item.getPackageName(),
+ !item.isDisabled()
+ );
}
}
}
@@ -552,14 +575,27 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
recordings.add(recording);
}
}
- updateRecordingPausedStatus();
+ updateSensorDisabledStatus();
}
};
@Override
public void onReceive(Context context, Intent intent) {
- mMicMuted = mAudioManager.isMicrophoneMute();
- updateRecordingPausedStatus();
+ mMicMuted = mAudioManager.isMicrophoneMute()
+ || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ updateSensorDisabledStatus();
+ }
+
+ @Override
+ public void onSensorBlockedChanged(int sensor, boolean blocked) {
+ mBGHandler.post(() -> {
+ if (sensor == INDIVIDUAL_SENSOR_CAMERA) {
+ mCameraDisabled = blocked;
+ } else if (sensor == INDIVIDUAL_SENSOR_MICROPHONE) {
+ mMicMuted = mAudioManager.isMicrophoneMute() || blocked;
+ }
+ updateSensorDisabledStatus();
+ });
}
protected class H extends Handler {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index c2c67903da86..9be3566e1f63 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -23,7 +23,6 @@ import android.content.Intent;
import android.net.Uri;
import android.os.UserHandle;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
@@ -59,7 +58,6 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
private final Executor mBgExecutor;
private final ImageExporter mImageExporter;
private final ImageTileSet mImageTileSet;
- private final LayoutInflater mLayoutInflater;
private ZonedDateTime mCaptureTime;
private UUID mRequestId;
@@ -81,7 +79,6 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
mBgExecutor = bgExecutor;
mImageExporter = exporter;
mImageTileSet = new ImageTileSet();
- mLayoutInflater = mContext.getSystemService(LayoutInflater.class);
}
/**
@@ -114,7 +111,7 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
mEdit.setOnClickListener(this::onClicked);
mShare.setOnClickListener(this::onClicked);
- mPreview.setImageDrawable(mImageTileSet.getDrawable());
+ //mPreview.setImageDrawable(mImageTileSet.getDrawable());
mConnection.start(this::startCapture);
}
@@ -242,6 +239,7 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
if (mImageTileSet.isEmpty()) {
session.end(mCallback::onFinish);
} else {
+ mPreview.setImageDrawable(mImageTileSet.getDrawable());
mExportFuture = mImageExporter.export(
mBgExecutor, mRequestId, mImageTileSet.toBitmap(), mCaptureTime);
// The user chose an action already, link it to the result
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 d4a2b4157338..b20c45780183 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2331,11 +2331,11 @@ public class StatusBar extends SystemUI implements DemoMode,
&& mStatusBarWindowState != state) {
mStatusBarWindowState = state;
if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
- if (!showing && mState == StatusBarState.SHADE) {
- mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
- 1.0f /* speedUpFactor */);
- }
if (mStatusBarView != null) {
+ if (!showing && mState == StatusBarState.SHADE) {
+ mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
+ 1.0f /* speedUpFactor */);
+ }
mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
updateHideIconsForBouncer(false /* animate */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
index 231fe08e6a99..32d15ed41648 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.policy;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManager.IndividualSensor;
@@ -30,7 +30,8 @@ import java.util.Set;
public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
- private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
+ private static final int[] SENSORS = new int[] {INDIVIDUAL_SENSOR_CAMERA,
+ INDIVIDUAL_SENSOR_MICROPHONE};
private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
private final SparseBooleanArray mState = new SparseBooleanArray();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
new file mode 100644
index 000000000000..826be2ba0d83
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 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.keyguard;
+
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.NavigationBarController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class KeyguardDisplayManagerTest extends SysuiTestCase {
+
+ @Mock
+ private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+
+ @Mock
+ private DisplayManager mDisplayManager;
+
+ @Mock
+ private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation;
+
+ private Executor mBackgroundExecutor = Runnable::run;
+ private KeyguardDisplayManager mManager;
+
+ // The default and secondary displays are both in the default group
+ private Display mDefaultDisplay;
+ private Display mSecondaryDisplay;
+
+ // This display is in a different group from the default and secondary displays.
+ private Display mDifferentGroupDisplay;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
+ mDependency.injectMockDependency(NavigationBarController.class);
+ mManager = spy(new KeyguardDisplayManager(mContext, mKeyguardStatusViewComponentFactory,
+ mBackgroundExecutor));
+ doReturn(mKeyguardPresentation).when(mManager).createPresentation(any());
+
+ mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
+ new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
+ mSecondaryDisplay = new Display(DisplayManagerGlobal.getInstance(),
+ Display.DEFAULT_DISPLAY + 1,
+ new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
+
+ DisplayInfo differentGroupInfo = new DisplayInfo();
+ differentGroupInfo.displayId = Display.DEFAULT_DISPLAY + 2;
+ differentGroupInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ mDifferentGroupDisplay = new Display(DisplayManagerGlobal.getInstance(),
+ Display.DEFAULT_DISPLAY,
+ differentGroupInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
+ }
+
+ @Test
+ public void testShow_defaultDisplayOnly() {
+ when(mDisplayManager.getDisplays()).thenReturn(new Display[]{mDefaultDisplay});
+ mManager.show();
+ verify(mManager, never()).createPresentation(any());
+ }
+
+ @Test
+ public void testShow_includeSecondaryDisplay() {
+ when(mDisplayManager.getDisplays()).thenReturn(
+ new Display[]{mDefaultDisplay, mSecondaryDisplay});
+ mManager.show();
+ verify(mManager, times(1)).createPresentation(eq(mSecondaryDisplay));
+ }
+
+ @Test
+ public void testShow_includeNonDefaultGroupDisplay() {
+ when(mDisplayManager.getDisplays()).thenReturn(
+ new Display[]{mDefaultDisplay, mDifferentGroupDisplay});
+
+ mManager.show();
+ verify(mManager, never()).createPresentation(any());
+ }
+
+ @Test
+ public void testShow_includeSecondaryAndNonDefaultGroupDisplays() {
+ when(mDisplayManager.getDisplays()).thenReturn(
+ new Display[]{mDefaultDisplay, mSecondaryDisplay, mDifferentGroupDisplay});
+
+ mManager.show();
+ verify(mManager, times(1)).createPresentation(eq(mSecondaryDisplay));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 02143a750cae..bc322f7f18fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -16,6 +16,9 @@
package com.android.systemui.appops;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
@@ -49,6 +52,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import org.junit.Before;
import org.junit.Test;
@@ -81,6 +85,8 @@ public class AppOpsControllerTest extends SysuiTestCase {
private PermissionFlagsCache mFlagsCache;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private IndividualSensorPrivacyController mSensorPrivacyController;
@Mock(stubOnly = true)
private AudioManager mAudioManager;
@Mock()
@@ -118,12 +124,18 @@ public class AppOpsControllerTest extends SysuiTestCase {
when(mAudioManager.getActiveRecordingConfigurations())
.thenReturn(List.of(mPausedMockRecording));
+ when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ .thenReturn(false);
+ when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ .thenReturn(false);
+
mController = new AppOpsControllerImpl(
mContext,
mTestableLooper.getLooper(),
mDumpManager,
mFlagsCache,
mAudioManager,
+ mSensorPrivacyController,
mDispatcher
);
}
@@ -133,6 +145,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.setListening(true);
verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsControllerImpl.OPS, mController);
verify(mDispatcher, times(1)).registerReceiverWithHandler(eq(mController), any(), any());
+ verify(mSensorPrivacyController, times(1)).addCallback(mController);
}
@Test
@@ -140,6 +153,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.setListening(false);
verify(mAppOpsManager, times(1)).stopWatchingActive(mController);
verify(mDispatcher, times(1)).unregisterReceiver(mController);
+ verify(mSensorPrivacyController, times(1)).removeCallback(mController);
}
@Test
@@ -476,6 +490,71 @@ public class AppOpsControllerTest extends SysuiTestCase {
AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
}
+ @Test
+ public void testAudioFilteredWhenMicDisabled() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA},
+ mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ List<AppOpItem> list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
+ assertFalse(list.get(0).isDisabled());
+
+ // Add a camera op, and disable the microphone. The camera op should be the only op returned
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, true);
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode());
+
+
+ // Re enable the microphone, and verify the op returns
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, false);
+ mTestableLooper.processAllMessages();
+
+ list = mController.getActiveAppOps();
+ assertEquals(2, list.size());
+ int micIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 1 : 0;
+ assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(micIdx).getCode());
+ }
+
+ @Test
+ public void testCameraFilteredWhenCameraDisabled() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA},
+ mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ List<AppOpItem> list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode());
+ assertFalse(list.get(0).isDisabled());
+
+ // Add an audio op, and disable the camera. The audio op should be the only op returned
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, true);
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
+
+ // Re enable the camera, and verify the op returns
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, false);
+ mTestableLooper.processAllMessages();
+
+ list = mController.getActiveAppOps();
+ assertEquals(2, list.size());
+ int cameraIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 0 : 1;
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(cameraIdx).getCode());
+ }
+
private class TestHandler extends AppOpsControllerImpl.H {
TestHandler(Looper looper) {
mController.super(looper);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 9aa0aed06892..ea1473ea3db7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -166,8 +166,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// their capabilities are ready.
private static final int WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS = 1000;
- static final String FUNCTION_REGISTER_SYSTEM_ACTION = "registerSystemAction";
- static final String FUNCTION_UNREGISTER_SYSTEM_ACTION = "unregisterSystemAction";
private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
"registerUiTestAutomationService";
@@ -748,9 +746,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
@Override
public void registerSystemAction(RemoteAction action, int actionId) {
- mSecurityPolicy.enforceCallerIsRecentsOrHasPermission(
- Manifest.permission.MANAGE_ACCESSIBILITY,
- FUNCTION_REGISTER_SYSTEM_ACTION);
+ mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
getSystemActionPerformer().registerSystemAction(actionId, action);
}
@@ -761,9 +757,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
@Override
public void unregisterSystemAction(int actionId) {
- mSecurityPolicy.enforceCallerIsRecentsOrHasPermission(
- Manifest.permission.MANAGE_ACCESSIBILITY,
- FUNCTION_UNREGISTER_SYSTEM_ACTION);
+ mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
getSystemActionPerformer().unregisterSystemAction(actionId);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index d7664312e2e6..bef6d3e950c1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -38,8 +38,6 @@ import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.util.ArrayUtils;
-import com.android.server.LocalServices;
-import com.android.server.wm.ActivityTaskManagerInternal;
import libcore.util.EmptyArray;
@@ -88,7 +86,6 @@ public class AccessibilitySecurityPolicy {
private final AccessibilityUserManager mAccessibilityUserManager;
private AccessibilityWindowManager mAccessibilityWindowManager;
- private final ActivityTaskManagerInternal mAtmInternal;
/**
* Constructor for AccessibilityManagerService.
@@ -100,7 +97,6 @@ public class AccessibilitySecurityPolicy {
mPackageManager = mContext.getPackageManager();
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
}
/**
@@ -572,13 +568,4 @@ public class AccessibilitySecurityPolicy {
+ permission);
}
}
-
- /**
- * Enforcing permission check to IPC caller or grant it if it's recents.
- *
- * @param permission The permission to check
- */
- public void enforceCallerIsRecentsOrHasPermission(@NonNull String permission, String func) {
- mAtmInternal.enforceCallerIsRecentsOrHasPermission(permission, func);
- }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d129b9c074a9..554edc6d74bd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -132,8 +132,8 @@ import android.net.SocketKeepalive;
import android.net.TetheringManager;
import android.net.UidRange;
import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
-import android.net.VpnInfo;
import android.net.VpnManager;
import android.net.VpnService;
import android.net.metrics.INetdEventListener;
@@ -4854,28 +4854,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
*
* <p>Must be called on the handler thread.
*/
- private VpnInfo[] getAllVpnInfo() {
+ private UnderlyingNetworkInfo[] getAllVpnInfo() {
ensureRunningOnConnectivityServiceThread();
synchronized (mVpns) {
if (mLockdownEnabled) {
- return new VpnInfo[0];
+ return new UnderlyingNetworkInfo[0];
}
}
- List<VpnInfo> infoList = new ArrayList<>();
+ List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- VpnInfo info = createVpnInfo(nai);
+ UnderlyingNetworkInfo info = createVpnInfo(nai);
if (info != null) {
infoList.add(info);
}
}
- return infoList.toArray(new VpnInfo[infoList.size()]);
+ return infoList.toArray(new UnderlyingNetworkInfo[infoList.size()]);
}
/**
* @return VPN information for accounting, or null if we can't retrieve all required
* information, e.g underlying ifaces.
*/
- private VpnInfo createVpnInfo(NetworkAgentInfo nai) {
+ private UnderlyingNetworkInfo createVpnInfo(NetworkAgentInfo nai) {
if (!nai.isVPN()) return null;
Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
@@ -4907,11 +4907,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Must be non-null or NetworkStatsService will crash.
// Cannot happen in production code because Vpn only registers the NetworkAgent after the
// tun or ipsec interface is created.
+ // TODO: Remove this check.
if (nai.linkProperties.getInterfaceName() == null) return null;
- return new VpnInfo(nai.networkCapabilities.getOwnerUid(),
- nai.linkProperties.getInterfaceName(),
- interfaces.toArray(new String[0]));
+ return new UnderlyingNetworkInfo(nai.networkCapabilities.getOwnerUid(),
+ nai.linkProperties.getInterfaceName(), interfaces);
}
/**
@@ -5707,6 +5707,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
enforceAccessPermission();
break;
+ case BACKGROUND_REQUEST:
+ enforceNetworkStackOrSettingsPermission();
+ // Fall-through since other checks are the same with normal requests.
case REQUEST:
networkCapabilities = new NetworkCapabilities(networkCapabilities);
enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
@@ -7998,10 +8001,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
activeIface = activeLinkProperties.getInterfaceName();
}
- final VpnInfo[] vpnInfos = getAllVpnInfo();
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
try {
- mStatsService.forceUpdateIfaces(
- getDefaultNetworks(), getAllNetworkState(), activeIface, vpnInfos);
+ mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
+ underlyingNetworkInfos);
} catch (Exception ignored) {
}
}
@@ -8261,6 +8264,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return getVpnIfOwner(mDeps.getCallingUid());
}
+ // TODO: stop calling into Vpn.java and get this information from data in this class.
@GuardedBy("mVpns")
private Vpn getVpnIfOwner(int uid) {
final int user = UserHandle.getUserId(uid);
@@ -8269,7 +8273,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (vpn == null) {
return null;
} else {
- final VpnInfo info = vpn.getVpnInfo();
+ final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
return (info == null || info.ownerUid != uid) ? null : vpn;
}
}
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 76db0192cb00..8562b0d9cb82 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -25,9 +25,12 @@ import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.vcn.IVcnManagementService;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -527,7 +530,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
requireNonNull(listener, "listener was null");
- mContext.enforceCallingPermission(
+ mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.NETWORK_FACTORY,
"Must have permission NETWORK_FACTORY to register a policy listener");
@@ -561,4 +564,27 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
}
}
+
+ /**
+ * Gets the UnderlyingNetworkPolicy as determined by the provided NetworkCapabilities and
+ * LinkProperties.
+ */
+ @NonNull
+ @Override
+ public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties) {
+ requireNonNull(networkCapabilities, "networkCapabilities was null");
+ requireNonNull(linkProperties, "linkProperties was null");
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying"
+ + " Network policies");
+
+ // TODO(b/175914059): implement policy generation once VcnManagementService is able to
+ // determine policies
+
+ return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
+ }
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index efe82df628d2..d63a6c3a0a6f 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -31,6 +31,7 @@ import android.os.IPowerManager;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceDebugInfo;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -136,6 +137,11 @@ public class Watchdog {
"android.system.suspend@1.0::ISystemSuspend"
);
+ public static final String[] AIDL_INTERFACE_PREFIXES_OF_INTEREST = new String[] {
+ "android.hardware.light.ILights/",
+ "android.hardware.power.stats.IPowerStats/",
+ };
+
private static Watchdog sWatchdog;
private final Thread mThread;
@@ -527,12 +533,11 @@ public class Watchdog {
return builder.toString();
}
- private static ArrayList<Integer> getInterestingHalPids() {
+ private static void addInterestingHidlPids(HashSet<Integer> pids) {
try {
IServiceManager serviceManager = IServiceManager.getService();
ArrayList<IServiceManager.InstanceDebugInfo> dump =
serviceManager.debugDump();
- HashSet<Integer> pids = new HashSet<>();
for (IServiceManager.InstanceDebugInfo info : dump) {
if (info.pid == IServiceManager.PidConstant.NO_PID) {
continue;
@@ -544,24 +549,37 @@ public class Watchdog {
pids.add(info.pid);
}
- return new ArrayList<Integer>(pids);
} catch (RemoteException e) {
- return new ArrayList<Integer>();
+ Log.w(TAG, e);
+ }
+ }
+
+ private static void addInterestingAidlPids(HashSet<Integer> pids) {
+ ServiceDebugInfo[] infos = ServiceManager.getServiceDebugInfo();
+ if (infos == null) return;
+
+ for (ServiceDebugInfo info : infos) {
+ for (String prefix : AIDL_INTERFACE_PREFIXES_OF_INTEREST) {
+ if (info.name.startsWith(prefix)) {
+ pids.add(info.debugPid);
+ }
+ }
}
}
static ArrayList<Integer> getInterestingNativePids() {
- ArrayList<Integer> pids = getInterestingHalPids();
+ HashSet<Integer> pids = new HashSet<>();
+ addInterestingAidlPids(pids);
+ addInterestingHidlPids(pids);
int[] nativePids = Process.getPidsForCommands(NATIVE_STACKS_OF_INTEREST);
if (nativePids != null) {
- pids.ensureCapacity(pids.size() + nativePids.length);
for (int i : nativePids) {
pids.add(i);
}
}
- return pids;
+ return new ArrayList<Integer>(pids);
}
private void run() {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e476ca908b5d..02613cfe0771 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -900,7 +900,7 @@ public final class ActiveServices {
String callingPackage, @Nullable String callingFeatureId, int callingUid,
Intent service, boolean callerFg, final int userId,
final boolean isBinding, final IServiceConnection connection) {
- if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ if (mAm.getPackageManagerInternal().isPermissionsReviewRequired(
r.packageName, r.userId)) {
// Show a permission review UI only for starting/binding from a foreground app
@@ -932,7 +932,7 @@ public final class ActiveServices {
// binding request is still valid, so hook them up. We
// proceed only if the caller cleared the review requirement
// otherwise we unbind because the user didn't approve.
- if (!mAm.getPackageManagerInternalLocked()
+ if (!mAm.getPackageManagerInternal()
.isPermissionsReviewRequired(r.packageName,
r.userId)) {
try {
@@ -941,9 +941,14 @@ public final class ActiveServices {
callerFg,
false /* whileRestarting */,
false /* permissionsReviewRequired */,
- false /* packageFrozen */);
+ false /* packageFrozen */,
+ true /* enqueueOomAdj */);
} catch (RemoteException e) {
/* ignore - local call */
+ } finally {
+ /* Will be a no-op if nothing pending */
+ mAm.updateOomAdjPendingTargetsLocked(
+ OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
} else {
unbindServiceLocked(connection);
@@ -994,7 +999,7 @@ public final class ActiveServices {
int callingUid, int callingPid, boolean fgRequired, boolean callerFg, int userId,
boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken,
boolean isBinding, IServiceConnection connection) {
- final PackageManagerInternal pm = mAm.getPackageManagerInternalLocked();
+ final PackageManagerInternal pm = mAm.getPackageManagerInternal();
final boolean frozen = pm.isPackageFrozen(s.packageName, callingUid, s.userId);
if (!frozen) {
// Not frozen, it's okay to go
@@ -1025,9 +1030,14 @@ public final class ActiveServices {
bringUpServiceLocked(s, serviceIntent.getFlags(), callerFg,
false /* whileRestarting */,
false /* permissionsReviewRequired */,
- false /* packageFrozen */);
+ false /* packageFrozen */,
+ true /* enqueueOomAdj */);
} catch (TransactionTooLargeException e) {
/* ignore - local call */
+ } finally {
+ /* Will be a no-op if nothing pending */
+ mAm.updateOomAdjPendingTargetsLocked(
+ OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
} else { // Starting a service
try {
@@ -1091,7 +1101,13 @@ public final class ActiveServices {
FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName,
serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START);
mAm.mBatteryStatsService.noteServiceStartRunning(uid, packageName, serviceName);
- String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false, false);
+ String error = bringUpServiceLocked(r, service.getFlags(), callerFg,
+ false /* whileRestarting */,
+ false /* permissionsReviewRequired */,
+ false /* packageFrozen */,
+ true /* enqueueOomAdj */);
+ /* Will be a no-op if nothing pending */
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
if (error != null) {
return new ComponentName("!!", error);
}
@@ -1117,7 +1133,7 @@ public final class ActiveServices {
return r.name;
}
- private void stopServiceLocked(ServiceRecord service) {
+ private void stopServiceLocked(ServiceRecord service, boolean enqueueOomAdj) {
if (service.delayed) {
// If service isn't actually running, but is being held in the
// delayed list, then we need to keep it started but note that it
@@ -1140,7 +1156,7 @@ public final class ActiveServices {
}
service.callStart = false;
- bringDownServiceIfNeededLocked(service, false, false);
+ bringDownServiceIfNeededLocked(service, false, false, enqueueOomAdj);
}
int stopServiceLocked(IApplicationThread caller, Intent service,
@@ -1163,7 +1179,7 @@ public final class ActiveServices {
if (r.record != null) {
final long origId = Binder.clearCallingIdentity();
try {
- stopServiceLocked(r.record);
+ stopServiceLocked(r.record, false);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -1213,11 +1229,15 @@ public final class ActiveServices {
}
}
if (stopping != null) {
- for (int i=stopping.size()-1; i>=0; i--) {
+ final int size = stopping.size();
+ for (int i = size - 1; i >= 0; i--) {
ServiceRecord service = stopping.get(i);
service.delayed = false;
services.ensureNotStartingBackgroundLocked(service);
- stopServiceLocked(service);
+ stopServiceLocked(service, true);
+ }
+ if (size > 0) {
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
}
}
}
@@ -1226,7 +1246,7 @@ public final class ActiveServices {
void killMisbehavingService(ServiceRecord r,
int appUid, int appPid, String localPackageName) {
synchronized (mAm) {
- stopServiceLocked(r);
+ stopServiceLocked(r, false);
mAm.crashApplication(appUid, appPid, localPackageName, -1,
"Bad notification for startForeground", true /*force*/);
}
@@ -1301,7 +1321,7 @@ public final class ActiveServices {
}
r.callStart = false;
final long origId = Binder.clearCallingIdentity();
- bringDownServiceIfNeededLocked(r, false, false);
+ bringDownServiceIfNeededLocked(r, false, false, false);
Binder.restoreCallingIdentity(origId);
return true;
}
@@ -2229,12 +2249,12 @@ public final class ActiveServices {
mAm.updateProcessForegroundLocked(proc, anyForeground, fgServiceTypes, oomAdj);
}
- private void updateWhitelistManagerLocked(ProcessRecord proc) {
- proc.whitelistManager = false;
+ private void updateAllowlistManagerLocked(ProcessRecord proc) {
+ proc.mAllowlistManager = false;
for (int i = proc.numberOfRunningServices() - 1; i >= 0; i--) {
ServiceRecord sr = proc.getRunningServiceAt(i);
if (sr.whitelistManager) {
- proc.whitelistManager = true;
+ proc.mAllowlistManager = true;
break;
}
}
@@ -2475,10 +2495,13 @@ public final class ActiveServices {
}
clist.add(c);
+ boolean needOomAdj = false;
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
+ needOomAdj = true;
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
- permissionsReviewRequired, packageFrozen) != null) {
+ permissionsReviewRequired, packageFrozen, true) != null) {
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
return 0;
}
}
@@ -2489,7 +2512,7 @@ public final class ActiveServices {
s.app.treatLikeActivity = true;
}
if (s.whitelistManager) {
- s.app.whitelistManager = true;
+ s.app.mAllowlistManager = true;
}
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app,
@@ -2497,7 +2520,11 @@ public final class ActiveServices {
|| (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP
&& (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
b.client);
- mAm.updateOomAdjLocked(s.app, OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
+ needOomAdj = true;
+ mAm.enqueueOomAdjTargetLocked(s.app);
+ }
+ if (needOomAdj) {
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
@@ -2591,7 +2618,7 @@ public final class ActiveServices {
}
}
- serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
+ serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2647,7 +2674,7 @@ public final class ActiveServices {
try {
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
- removeConnectionLocked(r, null, null);
+ removeConnectionLocked(r, null, null, true);
if (clist.size() > 0 && clist.get(0) == r) {
// In case it didn't get removed above, do it now.
Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
@@ -2656,8 +2683,8 @@ public final class ActiveServices {
final ProcessRecord app = r.binding.service.app;
if (app != null) {
- if (app.whitelistManager) {
- updateWhitelistManagerLocked(app);
+ if (app.mAllowlistManager) {
+ updateAllowlistManagerLocked(app);
}
// This could have made the service less important.
if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -2716,7 +2743,7 @@ public final class ActiveServices {
}
}
- serviceDoneExecutingLocked(r, inDestroying, false);
+ serviceDoneExecutingLocked(r, inDestroying, false, false);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2803,7 +2830,7 @@ public final class ActiveServices {
flags |= PackageManager.MATCH_INSTANT;
}
// TODO: come back and remove this assumption to triage all services
- ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
+ ResolveInfo rInfo = mAm.getPackageManagerInternal().resolveService(service,
resolvedType, flags, userId, callingUid);
ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
@@ -2876,7 +2903,7 @@ public final class ActiveServices {
final long token = Binder.clearCallingIdentity();
try {
ResolveInfo rInfoForUserId0 =
- mAm.getPackageManagerInternalLocked().resolveService(service,
+ mAm.getPackageManagerInternal().resolveService(service,
resolvedType, flags, userId, callingUid);
if (rInfoForUserId0 == null) {
Slog.w(TAG_SERVICE,
@@ -3055,13 +3082,13 @@ public final class ActiveServices {
// Keep the executeNesting count accurate.
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
final boolean inDestroying = mDestroyingServices.contains(r);
- serviceDoneExecutingLocked(r, inDestroying, inDestroying);
+ serviceDoneExecutingLocked(r, inDestroying, inDestroying, false);
throw e;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
- serviceDoneExecutingLocked(r, inDestroying, inDestroying);
+ serviceDoneExecutingLocked(r, inDestroying, inDestroying, false);
return false;
}
}
@@ -3217,9 +3244,12 @@ public final class ActiveServices {
}
try {
bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false,
- false);
+ false, true);
} catch (TransactionTooLargeException e) {
// Ignore, it's been logged and nothing upstack cares.
+ } finally {
+ /* Will be a no-op if nothing pending */
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
}
@@ -3262,7 +3292,8 @@ public final class ActiveServices {
}
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
- boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen)
+ boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
+ boolean enqueueOomAdj)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
@@ -3299,7 +3330,7 @@ public final class ActiveServices {
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": user " + r.userId + " is stopped";
Slog.w(TAG, msg);
- bringDownServiceLocked(r);
+ bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
@@ -3325,7 +3356,7 @@ public final class ActiveServices {
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
- realStartServiceLocked(r, app, execInFg);
+ realStartServiceLocked(r, app, execInFg, enqueueOomAdj);
return null;
} catch (TransactionTooLargeException e) {
throw e;
@@ -3366,7 +3397,7 @@ public final class ActiveServices {
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
- bringDownServiceLocked(r);
+ bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
if (isolated) {
@@ -3379,7 +3410,7 @@ public final class ActiveServices {
Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
+ " for fg-service launch");
}
- mAm.tempWhitelistUidLocked(r.appInfo.uid,
+ mAm.tempAllowlistUidLocked(r.appInfo.uid,
SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch",
BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
}
@@ -3394,7 +3425,7 @@ public final class ActiveServices {
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (in bring up): " + r);
- stopServiceLocked(r);
+ stopServiceLocked(r, enqueueOomAdj);
}
}
@@ -3417,7 +3448,7 @@ public final class ActiveServices {
* from bindService() as well.
*/
private final void realStartServiceLocked(ServiceRecord r,
- ProcessRecord app, boolean execInFg) throws RemoteException {
+ ProcessRecord app, boolean execInFg, boolean enqueueOomAdj) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
@@ -3431,7 +3462,11 @@ public final class ActiveServices {
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
- mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
+ if (enqueueOomAdj) {
+ mAm.enqueueOomAdjTargetLocked(app);
+ } else {
+ mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
+ }
boolean created = false;
try {
@@ -3466,7 +3501,7 @@ public final class ActiveServices {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
- serviceDoneExecutingLocked(r, inDestroying, inDestroying);
+ serviceDoneExecutingLocked(r, inDestroying, inDestroying, false);
// Cleanup.
if (newService) {
@@ -3482,7 +3517,7 @@ public final class ActiveServices {
}
if (r.whitelistManager) {
- app.whitelistManager = true;
+ app.mAllowlistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
@@ -3515,7 +3550,7 @@ public final class ActiveServices {
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " + r);
- stopServiceLocked(r);
+ stopServiceLocked(r, enqueueOomAdj);
}
}
}
@@ -3603,9 +3638,11 @@ public final class ActiveServices {
if (caughtException != null) {
// Keep nesting count correct
final boolean inDestroying = mDestroyingServices.contains(r);
- for (int i = 0; i < args.size(); i++) {
- serviceDoneExecutingLocked(r, inDestroying, inDestroying);
+ for (int i = 0, size = args.size(); i < size; i++) {
+ serviceDoneExecutingLocked(r, inDestroying, inDestroying, true);
}
+ /* Will be a no-op if nothing pending */
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
if (caughtException instanceof TransactionTooLargeException) {
throw (TransactionTooLargeException)caughtException;
}
@@ -3631,7 +3668,7 @@ public final class ActiveServices {
}
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
- boolean hasConn) {
+ boolean hasConn, boolean enqueueOomAdj) {
//Slog.i(TAG, "Bring down service:");
//r.dump(" ");
@@ -3644,10 +3681,10 @@ public final class ActiveServices {
return;
}
- bringDownServiceLocked(r);
+ bringDownServiceLocked(r, enqueueOomAdj);
}
- private final void bringDownServiceLocked(ServiceRecord r) {
+ private void bringDownServiceLocked(ServiceRecord r, boolean enqueueOomAdj) {
//Slog.i(TAG, "Bring down service:");
//r.dump(" ");
@@ -3672,9 +3709,9 @@ public final class ActiveServices {
}
}
+ boolean needOomAdj = false;
// Tell the service that it has been unbound.
if (r.app != null && r.app.thread != null) {
- boolean needOomAdj = false;
for (int i = r.bindings.size() - 1; i >= 0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr
@@ -3691,15 +3728,11 @@ public final class ActiveServices {
Slog.w(TAG, "Exception when unbinding service "
+ r.shortInstanceName, e);
needOomAdj = false;
- serviceProcessGoneLocked(r);
+ serviceProcessGoneLocked(r, enqueueOomAdj);
break;
}
}
}
- if (needOomAdj) {
- mAm.updateOomAdjLocked(r.app, true,
- OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
- }
}
// Check to see if the service had been started as foreground, but being
@@ -3801,7 +3834,7 @@ public final class ActiveServices {
r.app.stopService(r);
r.app.updateBoundClientUids();
if (r.whitelistManager) {
- updateWhitelistManagerLocked(r.app);
+ updateAllowlistManagerLocked(r.app);
}
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
@@ -3815,7 +3848,7 @@ public final class ActiveServices {
} catch (Exception e) {
Slog.w(TAG, "Exception when destroying service "
+ r.shortInstanceName, e);
- serviceProcessGoneLocked(r);
+ serviceProcessGoneLocked(r, enqueueOomAdj);
}
} else {
if (DEBUG_SERVICE) Slog.v(
@@ -3826,6 +3859,13 @@ public final class ActiveServices {
TAG_SERVICE, "Removed service that is not running: " + r);
}
+ if (needOomAdj) {
+ if (enqueueOomAdj) {
+ mAm.enqueueOomAdjTargetLocked(r.app);
+ } else {
+ mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ }
+ }
if (r.bindings.size() > 0) {
r.bindings.clear();
}
@@ -3849,7 +3889,7 @@ public final class ActiveServices {
}
void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
- ActivityServiceConnectionsHolder skipAct) {
+ ActivityServiceConnectionsHolder skipAct, boolean enqueueOomAdj) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
@@ -3875,7 +3915,7 @@ public final class ActiveServices {
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
s.updateWhitelistManager();
if (!s.whitelistManager && s.app != null) {
- updateWhitelistManagerLocked(s.app);
+ updateAllowlistManagerLocked(s.app);
}
}
// And do the same for bg activity starts ability.
@@ -3918,8 +3958,12 @@ public final class ActiveServices {
// it to go down there and we want it to start out near the top.
mAm.updateLruProcessLocked(s.app, false, null);
}
- mAm.updateOomAdjLocked(s.app, true,
- OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ if (enqueueOomAdj) {
+ mAm.enqueueOomAdjTargetLocked(s.app);
+ } else {
+ mAm.updateOomAdjLocked(s.app, true,
+ OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ }
b.intent.hasBound = false;
// Assume the client doesn't want to know about a rebind;
// we will deal with that later if it asks for one.
@@ -3927,7 +3971,7 @@ public final class ActiveServices {
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service " + s.shortInstanceName, e);
- serviceProcessGoneLocked(s);
+ serviceProcessGoneLocked(s, enqueueOomAdj);
}
}
@@ -3946,12 +3990,13 @@ public final class ActiveServices {
SystemClock.uptimeMillis());
}
}
- bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
+ bringDownServiceIfNeededLocked(s, true, hasAutoCreate, enqueueOomAdj);
}
}
}
- void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
+ void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res,
+ boolean enqueueOomAdj) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
@@ -4024,7 +4069,7 @@ public final class ActiveServices {
}
}
final long origId = Binder.clearCallingIdentity();
- serviceDoneExecutingLocked(r, inDestroying, inDestroying);
+ serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj);
Binder.restoreCallingIdentity(origId);
} else {
Slog.w(TAG, "Done executing unknown service from pid "
@@ -4032,7 +4077,7 @@ public final class ActiveServices {
}
}
- private void serviceProcessGoneLocked(ServiceRecord r) {
+ private void serviceProcessGoneLocked(ServiceRecord r, boolean enqueueOomAdj) {
if (r.tracker != null) {
int memFactor = mAm.mProcessStats.getMemFactorLocked();
long now = SystemClock.uptimeMillis();
@@ -4041,11 +4086,11 @@ public final class ActiveServices {
r.tracker.setBound(false, memFactor, now);
r.tracker.setStarted(false, memFactor, now);
}
- serviceDoneExecutingLocked(r, true, true);
+ serviceDoneExecutingLocked(r, true, true, enqueueOomAdj);
}
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
- boolean finishing) {
+ boolean finishing, boolean enqueueOomAdj) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r
+ ": nesting=" + r.executeNesting
+ ", inDestroying=" + inDestroying + ", app=" + r.app);
@@ -4077,7 +4122,11 @@ public final class ActiveServices {
mDestroyingServices.remove(r);
r.bindings.clear();
}
- mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ if (enqueueOomAdj) {
+ mAm.enqueueOomAdjTargetLocked(r.app);
+ } else {
+ mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ }
}
r.executeFg = false;
if (r.tracker != null) {
@@ -4095,7 +4144,7 @@ public final class ActiveServices {
r.app.stopService(r);
r.app.updateBoundClientUids();
if (r.whitelistManager) {
- updateWhitelistManagerLocked(r.app);
+ updateAllowlistManagerLocked(r.app);
}
}
r.setProcess(null);
@@ -4121,15 +4170,17 @@ public final class ActiveServices {
i--;
proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
mAm.mProcessStats);
- realStartServiceLocked(sr, proc, sr.createdFromFg);
+ realStartServiceLocked(sr, proc, sr.createdFromFg, true);
didSomething = true;
if (!isServiceNeededLocked(sr, false, false)) {
// We were waiting for this service to start, but it is actually no
// longer needed. This could happen because bringDownServiceIfNeeded
// won't bring down a service that is pending... so now the pending
// is done, so let's drop it.
- bringDownServiceLocked(sr);
+ bringDownServiceLocked(sr, true);
}
+ /* Will be a no-op if nothing pending */
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting service "
@@ -4157,7 +4208,8 @@ public final class ActiveServices {
}
void processStartTimedOutLocked(ProcessRecord proc) {
- for (int i=0; i<mPendingServices.size(); i++) {
+ boolean needOomAdj = false;
+ for (int i = 0, size = mPendingServices.size(); i < size; i++) {
ServiceRecord sr = mPendingServices.get(i);
if ((proc.uid == sr.appInfo.uid
&& proc.processName.equals(sr.processName))
@@ -4166,9 +4218,13 @@ public final class ActiveServices {
sr.isolatedProc = null;
mPendingServices.remove(i);
i--;
- bringDownServiceLocked(sr);
+ needOomAdj = true;
+ bringDownServiceLocked(sr, true);
}
}
+ if (needOomAdj) {
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ }
}
private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses,
@@ -4191,7 +4247,7 @@ public final class ActiveServices {
service.app.stopService(service);
service.app.updateBoundClientUids();
if (service.whitelistManager) {
- updateWhitelistManagerLocked(service.app);
+ updateAllowlistManagerLocked(service.app);
}
}
service.setProcess(null);
@@ -4237,8 +4293,12 @@ public final class ActiveServices {
}
if (mTmpCollectionResults != null) {
- for (int i = mTmpCollectionResults.size() - 1; i >= 0; i--) {
- bringDownServiceLocked(mTmpCollectionResults.get(i));
+ final int size = mTmpCollectionResults.size();
+ for (int i = size - 1; i >= 0; i--) {
+ bringDownServiceLocked(mTmpCollectionResults.get(i), true);
+ }
+ if (size > 0) {
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
}
mTmpCollectionResults.clear();
}
@@ -4279,12 +4339,14 @@ public final class ActiveServices {
}
// Take care of any running services associated with the app.
+ boolean needOomAdj = false;
for (int i = services.size() - 1; i >= 0; i--) {
ServiceRecord sr = services.get(i);
if (sr.startRequested) {
if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) {
Slog.i(TAG, "Stopping service " + sr.shortInstanceName + ": remove task");
- stopServiceLocked(sr);
+ needOomAdj = true;
+ stopServiceLocked(sr, true);
} else {
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
sr.getLastStartId(), baseIntent, null, 0));
@@ -4300,6 +4362,9 @@ public final class ActiveServices {
}
}
}
+ if (needOomAdj) {
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ }
}
final void killServicesLocked(ProcessRecord app, boolean allowRestart) {
@@ -4333,12 +4398,12 @@ public final class ActiveServices {
// Clean up any connections this application has to other services.
for (int i = app.connections.size() - 1; i >= 0; i--) {
ConnectionRecord r = app.connections.valueAt(i);
- removeConnectionLocked(r, app, null);
+ removeConnectionLocked(r, app, null, true);
}
updateServiceConnectionActivitiesLocked(app);
app.connections.clear();
- app.whitelistManager = false;
+ app.mAllowlistManager = false;
// Clear app state from services.
for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
@@ -4435,10 +4500,10 @@ public final class ActiveServices {
+ " times, stopping: " + sr);
EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
sr.userId, sr.crashCount, sr.shortInstanceName, app.pid);
- bringDownServiceLocked(sr);
+ bringDownServiceLocked(sr, true);
} else if (!allowRestart
|| !mAm.mUserController.isUserRunning(sr.userId, 0)) {
- bringDownServiceLocked(sr);
+ bringDownServiceLocked(sr, true);
} else {
final boolean scheduled = scheduleServiceRestartLocked(sr, true /* allowCancel */);
@@ -4446,7 +4511,7 @@ public final class ActiveServices {
// extreme case of so many attempts to deliver a command
// that it failed we also will stop it here.
if (!scheduled) {
- bringDownServiceLocked(sr);
+ bringDownServiceLocked(sr, true);
} else if (sr.canStopIfKilled(false /* isStartCanceled */)) {
// Update to stopped state because the explicit start is gone. The service is
// scheduled to restart for other reason (e.g. connections) so we don't bring
@@ -4460,6 +4525,8 @@ public final class ActiveServices {
}
}
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+
if (!allowRestart) {
app.stopAllServices();
app.clearBoundClientUids();
@@ -4684,7 +4751,7 @@ public final class ActiveServices {
Slog.i(TAG, "Service foreground-required timeout for " + r);
}
r.fgWaiting = false;
- stopServiceLocked(r);
+ stopServiceLocked(r, false);
}
if (app != null) {
@@ -5490,7 +5557,7 @@ public final class ActiveServices {
}
if (ret == FGS_FEATURE_DENIED) {
- if (mAm.isWhitelistedForFgsStartLocked(callingUid)) {
+ if (mAm.isAllowlistedForFgsStartLocked(callingUid)) {
// uid is on DeviceIdleController's user/system allowlist
// or AMS's FgsStartTempAllowList.
ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
@@ -5593,7 +5660,7 @@ public final class ActiveServices {
case FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION:
return "ALLOWED_BY_BACKGROUND_FGS_PERMISSION";
case FGS_FEATURE_ALLOWED_BY_ALLOWLIST:
- return "ALLOWED_BY_WHITELIST";
+ return "ALLOWED_BY_ALLOWLIST";
case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
return "ALLOWED_BY_DEVICE_OWNER";
case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 05f2fa096e4d..f63b994307b0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -99,7 +99,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
@@ -251,7 +250,6 @@ import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteCallback;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -278,7 +276,6 @@ import android.text.format.DateUtils;
import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.DebugUtils;
import android.util.EventLog;
import android.util.IntArray;
import android.util.Log;
@@ -395,6 +392,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@@ -535,16 +533,16 @@ public class ActivityManagerService extends IActivityManager.Stub
public OomAdjProfiler mOomAdjProfiler = new OomAdjProfiler();
// Whether we should use SCHED_FIFO for UI and RenderThreads.
- boolean mUseFifoUiScheduling = false;
+ final boolean mUseFifoUiScheduling;
// Use an offload queue for long broadcasts, e.g. BOOT_COMPLETED.
// For simplicity, since we statically declare the size of the array of BroadcastQueues,
// we still create this new offload queue, but never ever put anything on it.
- boolean mEnableOffloadQueue;
+ final boolean mEnableOffloadQueue;
- BroadcastQueue mFgBroadcastQueue;
- BroadcastQueue mBgBroadcastQueue;
- BroadcastQueue mOffloadBroadcastQueue;
+ final BroadcastQueue mFgBroadcastQueue;
+ final BroadcastQueue mBgBroadcastQueue;
+ final BroadcastQueue mOffloadBroadcastQueue;
// Convenient for easy iteration over the queues. Foreground is first
// so that dispatch of foreground broadcasts gets precedence.
final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[3];
@@ -662,9 +660,9 @@ public class ActivityManagerService extends IActivityManager.Stub
final ProcessStatsService mProcessStats;
/**
- * Non-persistent appId whitelist for background restrictions
+ * Non-persistent appId allowlist for background restrictions
*/
- int[] mBackgroundAppIdWhitelist = new int[] {
+ int[] mBackgroundAppIdAllowlist = new int[] {
BLUETOOTH_UID
};
@@ -881,11 +879,6 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
final ArrayList<ProcessRecord> mPersistentStartingProcesses = new ArrayList<ProcessRecord>();
- /**
- * List of processes that should gc as soon as things are idle.
- */
- final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
-
private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
new ActivityMetricsLaunchObserver() {
@Override
@@ -915,7 +908,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
};
- private boolean mBinderTransactionTrackingEnabled = false;
+ private volatile boolean mBinderTransactionTrackingEnabled = false;
/**
* Fingerprints (hashCode()) of stack traces that we've
@@ -923,6 +916,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* something (rogue user app) forces this over
* MAX_DUP_SUPPRESSED_STACKS entries, the contents are cleared.
*/
+ @GuardedBy("mAlreadyLoggedViolatedStacks")
private final HashSet<Integer> mAlreadyLoggedViolatedStacks = new HashSet<Integer>();
private static final int MAX_DUP_SUPPRESSED_STACKS = 5000;
@@ -1062,7 +1056,7 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* Information about component usage
*/
- UsageStatsManagerInternal mUsageStatsService;
+ volatile UsageStatsManagerInternal mUsageStatsService;
/**
* Access to DeviceIdleController service.
@@ -1072,29 +1066,29 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* Power-save whitelisted app-ids (not including except-idle-whitelisted ones).
*/
- int[] mDeviceIdleWhitelist = new int[0];
+ int[] mDeviceIdleAllowlist = new int[0];
/**
* Power-save whitelisted app-ids (including except-idle-whitelisted ones).
*/
- int[] mDeviceIdleExceptIdleWhitelist = new int[0];
+ int[] mDeviceIdleExceptIdleAllowlist = new int[0];
/**
* Set of app ids that are temporarily allowed to escape bg check due to high-pri message
*/
- int[] mDeviceIdleTempWhitelist = new int[0];
+ int[] mDeviceIdleTempAllowlist = new int[0];
- static final class PendingTempWhitelist {
+ static final class PendingTempAllowlist {
final int targetUid;
final long duration;
final String tag;
final int type;
- PendingTempWhitelist(int _targetUid, long _duration, String _tag, int _type) {
- targetUid = _targetUid;
- duration = _duration;
- tag = _tag;
- type = _type;
+ PendingTempAllowlist(int targetUid, long duration, String tag, int type) {
+ this.targetUid = targetUid;
+ this.duration = duration;
+ this.tag = tag;
+ this.type = type;
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
@@ -1107,7 +1101,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- final PendingTempWhitelists mPendingTempWhitelist = new PendingTempWhitelists(this);
+ final PendingTempAllowlists mPendingTempAllowlist = new PendingTempAllowlists(this);
/**
* The temp-allowlist that is allowed to start FGS from background.
@@ -1162,7 +1156,7 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* State of external calls telling us if the device is awake or asleep.
*/
- int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ AtomicInteger mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
/**
* The uptime of the last time we performed idle maintenance.
@@ -1172,10 +1166,18 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* For reporting to battery stats the current top application.
*/
+ @GuardedBy("mCurResumedAppLock")
private String mCurResumedPackage = null;
+
+ @GuardedBy("mCurResumedAppLock")
private int mCurResumedUid = -1;
/**
+ * Dedicated lock for {@link #mCurResumedPackage} and {@link #mCurResumedUid}.
+ */
+ private final Object mCurResumedAppLock = new Object();
+
+ /**
* For reporting to battery stats the apps currently running foreground
* service. The ProcessMap is package/uid tuples; each of these contain
* an array of the currently foreground processes.
@@ -1213,16 +1215,17 @@ public class ActivityManagerService extends IActivityManager.Stub
int foregroundServiceTypes;
}
- // TODO: Move below 4 members and code to ProcessList
- final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
- ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
-
- final ArrayList<ProcessChangeItem> mPendingProcessChanges = new ArrayList<>();
- final ArrayList<ProcessChangeItem> mAvailProcessChanges = new ArrayList<>();
-
+ @GuardedBy("mOomAdjObserverLock")
OomAdjObserver mCurOomAdjObserver;
+
+ @GuardedBy("mOomAdjObserverLock")
int mCurOomAdjUid;
+ /**
+ * Dedicated lock for {@link #mCurOomAdjObserver} and {@link #mCurOomAdjUid}.
+ */
+ final Object mOomAdjObserverLock = new Object();
+
interface OomAdjObserver {
void onOomAdjMessage(String msg);
}
@@ -1301,7 +1304,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int IDLE_UIDS_MSG = 58;
static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
- static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
+ static final int PUSH_TEMP_ALLOWLIST_UI_MSG = 68;
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
static final int KILL_APP_ZYGOTE_MSG = 71;
@@ -1312,13 +1315,11 @@ public class ActivityManagerService extends IActivityManager.Stub
static final String SERVICE_RECORD_KEY = "servicerecord";
- long mLastMemUsageReportTime = 0;
-
/**
* Flag whether the current user is a "monkey", i.e. whether
* the UI is driven by a UI automation tool.
*/
- private boolean mUserIsMonkey;
+ private volatile boolean mUserIsMonkey;
@VisibleForTesting
public final ServiceThread mHandlerThread;
@@ -1351,7 +1352,7 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* Used to notify activity lifecycle events.
*/
- @Nullable ContentCaptureManagerInternal mContentCaptureService;
+ @Nullable volatile ContentCaptureManagerInternal mContentCaptureService;
/*
* The default duration for the binder heavy hitter auto sampler
@@ -1438,7 +1439,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
} break;
case DISPATCH_PROCESSES_CHANGED_UI_MSG: {
- dispatchProcessesChanged();
+ mProcessList.dispatchProcessesChanged();
break;
}
case DISPATCH_PROCESS_DIED_UI_MSG: {
@@ -1447,14 +1448,14 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final int pid = msg.arg1;
final int uid = msg.arg2;
- dispatchProcessDied(pid, uid);
+ mProcessList.dispatchProcessDied(pid, uid);
break;
}
case DISPATCH_OOM_ADJ_OBSERVER_MSG: {
dispatchOomAdjObserver((String) msg.obj);
} break;
- case PUSH_TEMP_WHITELIST_UI_MSG: {
- pushTempWhitelist();
+ case PUSH_TEMP_ALLOWLIST_UI_MSG: {
+ pushTempAllowlist();
} break;
}
}
@@ -1470,18 +1471,18 @@ public class ActivityManagerService extends IActivityManager.Stub
switch (msg.what) {
case GC_BACKGROUND_PROCESSES_MSG: {
synchronized (ActivityManagerService.this) {
- performAppGcsIfAppropriateLocked();
+ mAppProfiler.performAppGcsIfAppropriateLocked();
}
} break;
case SERVICE_TIMEOUT_MSG: {
- mServices.serviceTimeout((ProcessRecord)msg.obj);
+ mServices.serviceTimeout((ProcessRecord) msg.obj);
} break;
case SERVICE_FOREGROUND_TIMEOUT_MSG: {
- mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
+ mServices.serviceForegroundTimeout((ServiceRecord) msg.obj);
} break;
case SERVICE_FOREGROUND_CRASH_MSG: {
- mServices.serviceForegroundCrash(
- (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));
+ mServices.serviceForegroundCrash((ProcessRecord) msg.obj,
+ msg.getData().getCharSequence(SERVICE_RECORD_KEY));
} break;
case UPDATE_TIME_ZONE: {
synchronized (ActivityManagerService.this) {
@@ -1491,7 +1492,8 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
r.thread.updateTimeZone();
} catch (RemoteException ex) {
- Slog.w(TAG, "Failed to update time zone for: " + r.info.processName);
+ Slog.w(TAG, "Failed to update time zone for: "
+ + r.info.processName);
}
}
}
@@ -1506,13 +1508,13 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.setAllHttpProxy();
} break;
case PROC_START_TIMEOUT_MSG: {
- ProcessRecord app = (ProcessRecord)msg.obj;
+ ProcessRecord app = (ProcessRecord) msg.obj;
synchronized (ActivityManagerService.this) {
processStartTimedOutLocked(app);
}
} break;
case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
- ProcessRecord app = (ProcessRecord)msg.obj;
+ ProcessRecord app = (ProcessRecord) msg.obj;
synchronized (ActivityManagerService.this) {
mCpHelper.processContentProviderPublishTimedOutLocked(app);
}
@@ -1521,13 +1523,14 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (ActivityManagerService.this) {
final int appId = msg.arg1;
final int userId = msg.arg2;
- Bundle bundle = (Bundle)msg.obj;
+ Bundle bundle = (Bundle) msg.obj;
String pkg = bundle.getString("pkg");
String reason = bundle.getString("reason");
forceStopPackageLocked(pkg, appId, false, false, true, false,
false, userId, reason);
}
} break;
+
case KILL_APP_ZYGOTE_MSG: {
synchronized (ActivityManagerService.this) {
final AppZygote appZygote = (AppZygote) msg.obj;
@@ -1541,10 +1544,10 @@ public class ActivityManagerService extends IActivityManager.Stub
sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
} break;
case REPORT_MEM_USAGE_MSG: {
- final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
+ final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>) msg.obj;
Thread thread = new Thread() {
@Override public void run() {
- reportMemUsage(memInfos);
+ mAppProfiler.reportMemUsage(memInfos);
}
};
thread.start();
@@ -1680,7 +1683,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
+ /**
+ * @param usageStatsManager shouldn't be null
+ */
+ public void setUsageStatsManager(@NonNull UsageStatsManagerInternal usageStatsManager) {
mUsageStatsService = usageStatsManager;
mActivityTaskManager.setUsageStatsManager(usageStatsManager);
}
@@ -2034,6 +2040,9 @@ public class ActivityManagerService extends IActivityManager.Stub
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mInternal = new LocalService();
mPendingStartActivityUids = new PendingStartActivityUids(mContext);
+ mUseFifoUiScheduling = false;
+ mEnableOffloadQueue = false;
+ mFgBroadcastQueue = mBgBroadcastQueue = mOffloadBroadcastQueue = null;
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -2128,9 +2137,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mPendingIntentController = new PendingIntentController(
mHandlerThread.getLooper(), mUserController, mConstants);
- if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) {
- mUseFifoUiScheduling = true;
- }
+ mUseFifoUiScheduling = SystemProperties.getInt("sys.use_fifo_ui", 0) != 0;
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
@@ -2244,7 +2251,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ArrayMap<String, ArraySet<String>> allowedAssociations =
SystemConfig.getInstance().getAllowedAssociations();
mAllowedAssociations = new ArrayMap<>(allowedAssociations.size());
- PackageManagerInternal pm = getPackageManagerInternalLocked();
+ PackageManagerInternal pm = getPackageManagerInternal();
for (int i = 0; i < allowedAssociations.size(); i++) {
final String pkg = allowedAssociations.keyAt(i);
final ArraySet<String> asc = allowedAssociations.valueAt(i);
@@ -2323,8 +2330,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- void updateCpuStatsLocked() {
- mAppProfiler.updateCpuStatsLocked();
+ void updateCpuStats() {
+ mAppProfiler.updateCpuStats();
}
void updateCpuStatsNow() {
@@ -2457,9 +2464,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void notifyPackageUse(String packageName, int reason) {
- synchronized(this) {
- getPackageManagerInternalLocked().notifyPackageUse(packageName, reason);
- }
+ getPackageManagerInternal().notifyPackageUse(packageName, reason);
}
boolean startIsolatedProcess(String entryPoint, String[] entryPointArgs,
@@ -2538,10 +2543,11 @@ public class ActivityManagerService extends IActivityManager.Stub
if (mUsageStatsService != null) {
mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(), taskRoot);
}
- if (mContentCaptureService != null && (event == Event.ACTIVITY_PAUSED
+ final ContentCaptureManagerInternal contentCaptureService = mContentCaptureService;
+ if (contentCaptureService != null && (event == Event.ACTIVITY_PAUSED
|| event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED
|| event == Event.ACTIVITY_DESTROYED)) {
- mContentCaptureService.notifyActivityEvent(userId, activity, event);
+ contentCaptureService.notifyActivityEvent(userId, activity, event);
}
}
@@ -2616,8 +2622,8 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i=mProcessList.mLruProcesses.size()-1; i>=0; i--) {
final ProcessRecord proc = mProcessList.mLruProcesses.get(i);
if (procState > proc.setProcState) {
- if (proc.pkgList.containsKey(packageName) ||
- (proc.pkgDeps != null && proc.pkgDeps.contains(packageName))) {
+ if (proc.getPkgList().containsKey(packageName)
+ || (proc.pkgDeps != null && proc.pkgDeps.contains(packageName))) {
procState = proc.setProcState;
}
}
@@ -2640,7 +2646,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (app.thread == null) {
throw new IllegalArgumentException("Process has no app thread");
}
- if (app.trimMemoryLevel >= level) {
+ if (app.mProfile.getTrimMemoryLevel() >= level) {
throw new IllegalArgumentException(
"Unable to set a higher trim level than current level");
}
@@ -2650,119 +2656,14 @@ public class ActivityManagerService extends IActivityManager.Stub
+ "on a foreground process");
}
app.thread.scheduleTrimMemory(level);
- app.trimMemoryLevel = level;
+ app.mProfile.setTrimMemoryLevel(level);
return true;
}
}
- private void dispatchProcessesChanged() {
- int N;
- synchronized (this) {
- N = mPendingProcessChanges.size();
- if (mActiveProcessChanges.length < N) {
- mActiveProcessChanges = new ProcessChangeItem[N];
- }
- mPendingProcessChanges.toArray(mActiveProcessChanges);
- mPendingProcessChanges.clear();
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "*** Delivering " + N + " process changes");
- }
-
- int i = mProcessObservers.beginBroadcast();
- while (i > 0) {
- i--;
- final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
- if (observer != null) {
- try {
- for (int j=0; j<N; j++) {
- ProcessChangeItem item = mActiveProcessChanges[j];
- if ((item.changes&ProcessChangeItem.CHANGE_ACTIVITIES) != 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "ACTIVITIES CHANGED pid=" + item.pid + " uid="
- + item.uid + ": " + item.foregroundActivities);
- observer.onForegroundActivitiesChanged(item.pid, item.uid,
- item.foregroundActivities);
- }
- if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid="
- + item.uid + ": " + item.foregroundServiceTypes);
- observer.onForegroundServicesChanged(item.pid, item.uid,
- item.foregroundServiceTypes);
- }
- }
- } catch (RemoteException e) {
- }
- }
- }
- mProcessObservers.finishBroadcast();
-
- synchronized (this) {
- for (int j=0; j<N; j++) {
- mAvailProcessChanges.add(mActiveProcessChanges[j]);
- }
- }
- }
-
- @GuardedBy("this")
- ProcessChangeItem enqueueProcessChangeItemLocked(int pid, int uid) {
- int i = mPendingProcessChanges.size()-1;
- ActivityManagerService.ProcessChangeItem item = null;
- while (i >= 0) {
- item = mPendingProcessChanges.get(i);
- if (item.pid == pid) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Re-using existing item: " + item);
- break;
- }
- i--;
- }
-
- if (i < 0) {
- // No existing item in pending changes; need a new one.
- final int NA = mAvailProcessChanges.size();
- if (NA > 0) {
- item = mAvailProcessChanges.remove(NA-1);
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Retrieving available item: " + item);
- } else {
- item = new ActivityManagerService.ProcessChangeItem();
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Allocating new item: " + item);
- }
- item.changes = 0;
- item.pid = pid;
- item.uid = uid;
- if (mPendingProcessChanges.size() == 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "*** Enqueueing dispatch processes changed!");
- mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
- .sendToTarget();
- }
- mPendingProcessChanges.add(item);
- }
-
- return item;
- }
-
- private void dispatchProcessDied(int pid, int uid) {
- int i = mProcessObservers.beginBroadcast();
- while (i > 0) {
- i--;
- final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
- if (observer != null) {
- try {
- observer.onProcessDied(pid, uid);
- } catch (RemoteException e) {
- }
- }
- }
- mProcessObservers.finishBroadcast();
- }
-
void dispatchOomAdjObserver(String msg) {
OomAdjObserver observer;
- synchronized (this) {
+ synchronized (mOomAdjObserverLock) {
observer = mCurOomAdjObserver;
}
@@ -2772,32 +2673,26 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void setOomAdjObserver(int uid, OomAdjObserver observer) {
- synchronized (this) {
+ synchronized (mOomAdjObserverLock) {
mCurOomAdjUid = uid;
mCurOomAdjObserver = observer;
}
}
void clearOomAdjObserver() {
- synchronized (this) {
+ synchronized (mOomAdjObserverLock) {
mCurOomAdjUid = -1;
mCurOomAdjObserver = null;
}
}
- void reportOomAdjMessageLocked(String tag, String msg) {
- Slog.d(tag, msg);
- if (mCurOomAdjObserver != null) {
- mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
- }
- }
-
void reportUidInfoMessageLocked(String tag, String msg, int uid) {
Slog.i(TAG, msg);
- if (mCurOomAdjObserver != null && uid == mCurOomAdjUid) {
- mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
+ synchronized (mOomAdjObserverLock) {
+ if (mCurOomAdjObserver != null && uid == mCurOomAdjUid) {
+ mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
+ }
}
-
}
/**
@@ -2969,57 +2864,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return null;
}
- final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
- // If there are no longer any background processes running,
- // and the app that died was not running instrumentation,
- // then tell everyone we are now low on memory.
- if (!mProcessList.haveBackgroundProcessLocked()) {
- boolean doReport = Build.IS_DEBUGGABLE;
- if (doReport) {
- long now = SystemClock.uptimeMillis();
- if (now < (mLastMemUsageReportTime+5*60*1000)) {
- doReport = false;
- } else {
- mLastMemUsageReportTime = now;
- }
- }
- final ArrayList<ProcessMemInfo> memInfos
- = doReport ? new ArrayList<ProcessMemInfo>(mProcessList.getLruSizeLocked())
- : null;
- EventLogTags.writeAmLowMemory(mProcessList.getLruSizeLocked());
- long now = SystemClock.uptimeMillis();
- for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord rec = mProcessList.mLruProcesses.get(i);
- if (rec == dyingProc || rec.thread == null) {
- continue;
- }
- if (doReport) {
- memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
- rec.setProcState, rec.adjType, rec.makeAdjReason()));
- }
- if ((rec.lastLowMemory+mConstants.GC_MIN_INTERVAL) <= now) {
- // The low memory report is overriding any current
- // state for a GC request. Make sure to do
- // heavy/important/visible/foreground processes first.
- if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- rec.lastRequestedGc = 0;
- } else {
- rec.lastRequestedGc = rec.lastLowMemory;
- }
- rec.reportLowMemory = true;
- rec.lastLowMemory = now;
- mProcessesToGc.remove(rec);
- addProcessToGcListLocked(rec);
- }
- }
- if (doReport) {
- Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
- mHandler.sendMessage(msg);
- }
- scheduleAppGcsLocked();
- }
- }
-
@GuardedBy("this")
final void appDiedLocked(ProcessRecord app, String reason) {
appDiedLocked(app, app.pid, app.thread, false, reason);
@@ -3076,7 +2920,7 @@ public class ActivityManagerService extends IActivityManager.Stub
updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
}
if (doLowMem) {
- doLowMemReportIfNeededLocked(app);
+ mAppProfiler.doLowMemReportIfNeededLocked(app);
}
} else if (app.pid != pid) {
// A new process has already been started.
@@ -3379,55 +3223,55 @@ public class ActivityManagerService extends IActivityManager.Stub
final long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
- synchronized(this) {
- // Instant packages are not protected
- if (getPackageManagerInternalLocked().isPackageDataProtected(
- resolvedUserId, packageName)) {
- throw new SecurityException(
- "Cannot clear data for a protected package: " + packageName);
- }
+ // Instant packages are not protected
+ if (getPackageManagerInternal().isPackageDataProtected(
+ resolvedUserId, packageName)) {
+ throw new SecurityException(
+ "Cannot clear data for a protected package: " + packageName);
+ }
- ApplicationInfo applicationInfo = null;
- try {
- applicationInfo = pm.getApplicationInfo(packageName,
- MATCH_UNINSTALLED_PACKAGES, resolvedUserId);
- } catch (RemoteException e) {
- /* ignore */
- }
- appInfo = applicationInfo;
+ ApplicationInfo applicationInfo = null;
+ try {
+ applicationInfo = pm.getApplicationInfo(packageName,
+ MATCH_UNINSTALLED_PACKAGES, resolvedUserId);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ appInfo = applicationInfo;
- final boolean clearingOwnUidData = appInfo != null && appInfo.uid == uid;
+ final boolean clearingOwnUidData = appInfo != null && appInfo.uid == uid;
- if (!clearingOwnUidData && checkComponentPermission(permission.CLEAR_APP_USER_DATA,
+ if (!clearingOwnUidData && checkComponentPermission(permission.CLEAR_APP_USER_DATA,
pid, uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("PID " + pid + " does not have permission "
- + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data"
- + " of package " + packageName);
- }
-
- final boolean hasInstantMetadata = getPackageManagerInternalLocked()
- .hasInstantApplicationMetadata(packageName, resolvedUserId);
- final boolean isUninstalledAppWithoutInstantMetadata =
- (appInfo == null && !hasInstantMetadata);
- isInstantApp = (appInfo != null && appInfo.isInstantApp())
- || hasInstantMetadata;
- final boolean canAccessInstantApps = checkComponentPermission(
- permission.ACCESS_INSTANT_APPS, pid, uid, -1, true)
- == PackageManager.PERMISSION_GRANTED;
+ throw new SecurityException("PID " + pid + " does not have permission "
+ + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data"
+ + " of package " + packageName);
+ }
+
+ final boolean hasInstantMetadata = getPackageManagerInternal()
+ .hasInstantApplicationMetadata(packageName, resolvedUserId);
+ final boolean isUninstalledAppWithoutInstantMetadata =
+ (appInfo == null && !hasInstantMetadata);
+ isInstantApp = (appInfo != null && appInfo.isInstantApp())
+ || hasInstantMetadata;
+ final boolean canAccessInstantApps = checkComponentPermission(
+ permission.ACCESS_INSTANT_APPS, pid, uid, -1, true)
+ == PackageManager.PERMISSION_GRANTED;
- if (isUninstalledAppWithoutInstantMetadata || (isInstantApp
+ if (isUninstalledAppWithoutInstantMetadata || (isInstantApp
&& !canAccessInstantApps)) {
- Slog.w(TAG, "Invalid packageName: " + packageName);
- if (observer != null) {
- try {
- observer.onRemoveCompleted(packageName, false);
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
+ Slog.w(TAG, "Invalid packageName: " + packageName);
+ if (observer != null) {
+ try {
+ observer.onRemoveCompleted(packageName, false);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
}
- return false;
}
+ return false;
+ }
+ synchronized (this) {
if (appInfo != null) {
forceStopPackageLocked(packageName, appInfo.uid, "clear data");
mAtmInternal.removeRecentTasksByPackageName(packageName, resolvedUserId);
@@ -3566,7 +3410,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ApplicationExitInfo.SUBREASON_UNKNOWN,
"kill all background");
- doLowMemReportIfNeededLocked(null);
+ mAppProfiler.doLowMemReportIfNeededLocked(null);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -3623,7 +3467,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int[] users = userId == UserHandle.USER_ALL
? mUserController.getUsers() : new int[] { userId };
for (int user : users) {
- if (getPackageManagerInternalLocked().isPackageStateProtected(
+ if (getPackageManagerInternal().isPackageStateProtected(
packageName, user)) {
Slog.w(TAG, "Ignoring request to force stop protected package "
+ packageName + " u" + user);
@@ -3660,17 +3504,17 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void addPackageDependency(String packageName) {
- synchronized (this) {
- int callingPid = Binder.getCallingPid();
- if (callingPid == myPid()) {
- // Yeah, um, no.
- return;
- }
- ProcessRecord proc;
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(Binder.getCallingPid());
- }
- if (proc != null) {
+ int callingPid = Binder.getCallingPid();
+ if (callingPid == myPid()) {
+ // Yeah, um, no.
+ return;
+ }
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(Binder.getCallingPid());
+ }
+ if (proc != null) {
+ synchronized (this) {
if (proc.pkgDeps == null) {
proc.pkgDeps = new ArraySet<String>(1);
}
@@ -3743,15 +3587,22 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
+ final Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
for (int i=pids.length-1; i>=0; i--) {
- infos[i] = new Debug.MemoryInfo();
+ final Debug.MemoryInfo mi = infos[i] = new Debug.MemoryInfo();
final ProcessRecord proc;
final int oomAdj;
- synchronized (this) {
+ final ProcessProfileRecord profile;
+ synchronized (mAppProfiler.mProfilerLock) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pids[i]);
- oomAdj = proc != null ? proc.setAdj : 0;
+ if (proc != null) {
+ profile = proc.mProfile;
+ oomAdj = profile.getSetAdj();
+ } else {
+ profile = null;
+ oomAdj = 0;
+ }
}
}
final int targetUid = (proc != null) ? proc.uid : -1;
@@ -3766,43 +3617,43 @@ public class ActivityManagerService extends IActivityManager.Stub
continue; // Not allowed to see other users.
}
}
- if (proc != null && proc.lastMemInfoTime >= lastNow && proc.lastMemInfo != null
- && !isCallerInstrumentedFromShell) {
- // It hasn't been long enough that we want to take another sample; return
- // the last one.
- infos[i].set(proc.lastMemInfo);
- continue;
+ if (proc != null) {
+ synchronized (mAppProfiler.mProfilerLock) {
+ if (profile.getLastMemInfoTime() >= lastNow && profile.getLastMemInfo() != null
+ && !isCallerInstrumentedFromShell) {
+ // It hasn't been long enough that we want to take another sample; return
+ // the last one.
+ mi.set(profile.getLastMemInfo());
+ continue;
+ }
+ }
}
final long startTime = SystemClock.currentThreadTimeMillis();
final Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(pids[i], memInfo);
- final long endTime = SystemClock.currentThreadTimeMillis();
- infos[i].set(memInfo);
+ final long duration = SystemClock.currentThreadTimeMillis() - startTime;
+ mi.set(memInfo);
if (proc != null) {
- synchronized (this) {
- proc.lastMemInfo = memInfo;
- proc.lastMemInfoTime = SystemClock.uptimeMillis();
- if (proc.thread != null && proc.setAdj == oomAdj) {
+ synchronized (mAppProfiler.mProfilerLock) {
+ profile.setLastMemInfo(memInfo);
+ profile.setLastMemInfoTime(SystemClock.uptimeMillis());
+ if (profile.getThread() != null && profile.getSetAdj() == oomAdj) {
// Record this for posterity if the process has been stable.
- synchronized (mProcessStats.mLock) {
- proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
- infos[i].getTotalUss(), infos[i].getTotalRss(), false,
- ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime - startTime,
- proc.pkgList.mPkgList);
- }
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ profile.addPss(mi.getTotalPss(),
+ mi.getTotalUss(), mi.getTotalRss(), false,
+ ProcessStats.ADD_PSS_EXTERNAL_SLOW, duration);
+ proc.getPkgList().forEachPackageProcessStats(holder -> {
FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
proc.info.uid,
holder.state.getName(),
holder.state.getPackage(),
- infos[i].getTotalPss(),
- infos[i].getTotalUss(),
- infos[i].getTotalRss(),
+ mi.getTotalPss(),
+ mi.getTotalUss(),
+ mi.getTotalRss(),
ProcessStats.ADD_PSS_EXTERNAL_SLOW,
- endTime-startTime,
+ duration,
holder.appVersion);
- }
+ });
}
}
}
@@ -3823,7 +3674,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final boolean allUids = mAtmInternal.isGetTasksAllowed(
"getProcessPss", callingPid, callingUid);
- long[] pss = new long[pids.length];
+ final long[] pss = new long[pids.length];
for (int i=pids.length-1; i>=0; i--) {
ProcessRecord proc;
int oomAdj;
@@ -3838,29 +3689,29 @@ public class ActivityManagerService extends IActivityManager.Stub
// just leave it empty.
continue;
}
- long[] tmpUss = new long[3];
- long startTime = SystemClock.currentThreadTimeMillis();
- pss[i] = Debug.getPss(pids[i], tmpUss, null);
- long endTime = SystemClock.currentThreadTimeMillis();
+ final long[] tmpUss = new long[3];
+ final long startTime = SystemClock.currentThreadTimeMillis();
+ final long pi = pss[i] = Debug.getPss(pids[i], tmpUss, null);
+ final long duration = SystemClock.currentThreadTimeMillis() - startTime;
if (proc != null) {
- synchronized (this) {
- if (proc.thread != null && proc.setAdj == oomAdj) {
+ final ProcessProfileRecord profile = proc.mProfile;
+ synchronized (mAppProfiler.mProfilerLock) {
+ if (profile.getThread() != null && profile.getSetAdj() == oomAdj) {
// Record this for posterity if the process has been stable.
- synchronized (mProcessStats.mLock) {
- proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false,
- ProcessStats.ADD_PSS_EXTERNAL, endTime - startTime,
- proc.pkgList.mPkgList);
- }
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ profile.addPss(pi, tmpUss[0], tmpUss[2], false,
+ ProcessStats.ADD_PSS_EXTERNAL, duration);
+ proc.getPkgList().forEachPackageProcessStats(holder -> {
FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
proc.info.uid,
holder.state.getName(),
holder.state.getPackage(),
- pss[i], tmpUss[0], tmpUss[2],
- ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime,
+ pi,
+ tmpUss[0],
+ tmpUss[2],
+ ProcessStats.ADD_PSS_EXTERNAL,
+ duration,
holder.appVersion);
- }
+ });
}
}
}
@@ -4051,7 +3902,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.i(TAG, "Force stopping u" + userId + ": " + reason);
}
- mAppErrors.resetProcessCrashTimeLocked(packageName == null, appId, userId);
+ mAppErrors.resetProcessCrashTime(packageName == null, appId, userId);
}
// Notify first that the package is stopped, so its process won't be restarted unexpectedly
@@ -4425,7 +4276,11 @@ public class ActivityManagerService extends IActivityManager.Stub
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
mProcessList.updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
- app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
+ final long now = SystemClock.uptimeMillis();
+ synchronized (mAppProfiler.mProfilerLock) {
+ app.mProfile.setLastRequestedGc(now);
+ app.mProfile.setLastLowMemory(now);
+ }
} catch (Exception e) {
// We need kill the process group here. (b/148588589)
Slog.wtf(TAG, "Exception thrown during bind of " + app, e);
@@ -5439,7 +5294,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// If force-background-check is enabled, restrict all apps that aren't whitelisted.
if (mForceBackgroundCheck &&
!UserHandle.isCore(uid) &&
- !isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ true)) {
+ !isOnDeviceIdleAllowlistLocked(uid, /*allowExceptIdleToo=*/ true)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Force background check: " +
uid + "/" + packageName + " restricted");
@@ -5468,7 +5323,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// Non-persistent but background whitelisted?
- if (uidOnBackgroundWhitelist(uid)) {
+ if (uidOnBackgroundAllowlist(uid)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " on background whitelist; not restricted in background");
@@ -5477,7 +5332,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// Is this app on the battery whitelist?
- if (isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ false)) {
+ if (isOnDeviceIdleAllowlistLocked(uid, /*allowExceptIdleToo=*/ false)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " on idle whitelist; not restricted in background");
@@ -5501,7 +5356,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
boolean ephemeral;
if (uidRec == null) {
- ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
+ ephemeral = getPackageManagerInternal().isPackageEphemeral(
UserHandle.getUserId(uid), packageName);
} else {
ephemeral = uidRec.ephemeral;
@@ -5525,8 +5380,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_BACKGROUND_CHECK) {
Slog.d(TAG, "checkAllowBackground: uid=" + uid
+ " pkg=" + packageName + " startMode=" + startMode
- + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid, false)
- + " onwhitelist(ei)=" + isOnDeviceIdleWhitelistLocked(uid, true));
+ + " onallowlist=" + isOnDeviceIdleAllowlistLocked(uid, false)
+ + " onallowlist(ei)=" + isOnDeviceIdleAllowlistLocked(uid, true));
}
if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
// This is an old app that has been forced into a "compatible as possible"
@@ -5552,38 +5407,38 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
- * @return whether a UID is in the system, user or temp doze whitelist.
+ * @return whether a UID is in the system, user or temp doze allowlist.
*/
- boolean isOnDeviceIdleWhitelistLocked(int uid, boolean allowExceptIdleToo) {
+ boolean isOnDeviceIdleAllowlistLocked(int uid, boolean allowExceptIdleToo) {
final int appId = UserHandle.getAppId(uid);
- final int[] whitelist = allowExceptIdleToo
- ? mDeviceIdleExceptIdleWhitelist
- : mDeviceIdleWhitelist;
+ final int[] allowlist = allowExceptIdleToo
+ ? mDeviceIdleExceptIdleAllowlist
+ : mDeviceIdleAllowlist;
- return Arrays.binarySearch(whitelist, appId) >= 0
- || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0
- || mPendingTempWhitelist.indexOfKey(uid) >= 0;
+ return Arrays.binarySearch(allowlist, appId) >= 0
+ || Arrays.binarySearch(mDeviceIdleTempAllowlist, appId) >= 0
+ || mPendingTempAllowlist.indexOfKey(uid) >= 0;
}
- boolean isWhitelistedForFgsStartLocked(int uid) {
- return Arrays.binarySearch(mDeviceIdleExceptIdleWhitelist, UserHandle.getAppId(uid)) >= 0
+ boolean isAllowlistedForFgsStartLocked(int uid) {
+ return Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, UserHandle.getAppId(uid)) >= 0
|| mFgsStartTempAllowList.isAllowed(uid);
}
/**
- * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
- * the whitelist
+ * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
+ * the allowlist
*/
- String getPendingTempWhitelistTagForUidLocked(int uid) {
- final PendingTempWhitelist ptw = mPendingTempWhitelist.get(uid);
+ String getPendingTempAllowlistTagForUidLocked(int uid) {
+ final PendingTempAllowlist ptw = mPendingTempAllowlist.get(uid);
return ptw != null ? ptw.tag : null;
}
@VisibleForTesting
public void grantImplicitAccess(int userId, Intent intent, int visibleUid, int recipientAppId) {
- getPackageManagerInternalLocked().
- grantImplicitAccess(userId, intent, recipientAppId, visibleUid, true /*direct*/);
+ getPackageManagerInternal()
+ .grantImplicitAccess(userId, intent, recipientAppId, visibleUid, true /*direct*/);
}
/**
@@ -5831,14 +5686,18 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@VisibleForTesting
- public PackageManagerInternal getPackageManagerInternalLocked() {
+ public PackageManagerInternal getPackageManagerInternal() {
+ // Intentionally hold no locks: in case of race conditions, the mPackageManagerInt will
+ // be set to the same value anyway.
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
}
return mPackageManagerInt;
}
- private PermissionManagerServiceInternal getPermissionManagerInternalLocked() {
+ private PermissionManagerServiceInternal getPermissionManagerInternal() {
+ // Intentionally hold no locks: in case of race conditions, the mPermissionManagerInt will
+ // be set to the same value anyway.
if (mPermissionManagerInt == null) {
mPermissionManagerInt =
LocalServices.getService(PermissionManagerServiceInternal.class);
@@ -5983,12 +5842,11 @@ public class ActivityManagerService extends IActivityManager.Stub
// GLOBAL MANAGEMENT
// =========================================================
- private boolean uidOnBackgroundWhitelist(final int uid) {
+ private boolean uidOnBackgroundAllowlist(final int uid) {
final int appId = UserHandle.getAppId(uid);
- final int[] whitelist = mBackgroundAppIdWhitelist;
- final int N = whitelist.length;
- for (int i = 0; i < N; i++) {
- if (appId == whitelist[i]) {
+ final int[] allowlist = mBackgroundAppIdAllowlist;
+ for (int i = 0, len = allowlist.length; i < len; i++) {
+ if (appId == allowlist[i]) {
return true;
}
}
@@ -6028,11 +5886,11 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.i(TAG, "Adding uid " + uid + " to bg uid whitelist");
}
synchronized (this) {
- final int N = mBackgroundAppIdWhitelist.length;
- int[] newList = new int[N+1];
- System.arraycopy(mBackgroundAppIdWhitelist, 0, newList, 0, N);
- newList[N] = UserHandle.getAppId(uid);
- mBackgroundAppIdWhitelist = newList;
+ final int num = mBackgroundAppIdAllowlist.length;
+ int[] newList = new int[num + 1];
+ System.arraycopy(mBackgroundAppIdAllowlist, 0, newList, 0, num);
+ newList[num] = UserHandle.getAppId(uid);
+ mBackgroundAppIdAllowlist = newList;
}
}
@@ -6150,16 +6008,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void reportCurWakefulnessUsageEvent() {
- reportGlobalUsageEvent(mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE
+ reportGlobalUsageEvent(mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE
? UsageEvents.Event.SCREEN_INTERACTIVE
: UsageEvents.Event.SCREEN_NON_INTERACTIVE);
}
void onWakefulnessChanged(int wakefulness) {
synchronized(this) {
- boolean wasAwake = mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE;
+ boolean wasAwake = mWakefulness.getAndSet(wakefulness)
+ == PowerManagerInternal.WAKEFULNESS_AWAKE;
boolean isAwake = wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE;
- mWakefulness = wakefulness;
if (wasAwake != isAwake) {
// Also update state in a special way for running foreground services UI.
@@ -6269,17 +6127,16 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
@Override
public void setAgentApp(@NonNull String packageName, @Nullable String agent) {
- synchronized (this) {
- // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
- // its own permission.
- if (checkCallingPermission(
- android.Manifest.permission.SET_ACTIVITY_WATCHER) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER);
- }
+ // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+ // its own permission.
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
- mAppProfiler.setAgentAppLocked(packageName, agent);
+ synchronized (mAppProfiler.mProfilerLock) {
+ mAppProfiler.setAgentAppLPf(packageName, agent);
}
}
@@ -6296,7 +6153,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void setProfileApp(ApplicationInfo app, String processName, ProfilerInfo profilerInfo) {
- synchronized (this) {
+ synchronized (mAppProfiler.mProfilerLock) {
if (!Build.IS_DEBUGGABLE) {
boolean isAppDebuggable = (app.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
boolean isAppProfileable = app.isProfileableByShell();
@@ -6305,7 +6162,7 @@ public class ActivityManagerService extends IActivityManager.Stub
+ "and not profileable by shell: " + app.packageName);
}
}
- mAppProfiler.setProfileAppLocked(processName, profilerInfo);
+ mAppProfiler.setProfileAppLPf(processName, profilerInfo);
}
}
@@ -6391,8 +6248,8 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.w(TAG, "system process not in mPidsSelfLocked: " + myPid());
return;
}
- synchronized (this) {
- mAppProfiler.startHeapDumpLocked(pr, true);
+ synchronized (mAppProfiler.mProfilerLock) {
+ mAppProfiler.startHeapDumpLPf(pr.mProfile, true);
}
}
@@ -6572,16 +6429,12 @@ public class ActivityManagerService extends IActivityManager.Stub
public void registerProcessObserver(IProcessObserver observer) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
- synchronized (this) {
- mProcessObservers.register(observer);
- }
+ mProcessList.registerProcessObserver(observer);
}
@Override
public void unregisterProcessObserver(IProcessObserver observer) {
- synchronized (this) {
- mProcessObservers.unregister(observer);
- }
+ mProcessList.unregisterProcessObserver(observer);
}
@Override
@@ -6603,17 +6456,13 @@ public class ActivityManagerService extends IActivityManager.Stub
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
"registerUidObserver");
}
- synchronized (this) {
- mUidObserverController.register(observer, which, cutpoint, callingPackage,
- Binder.getCallingUid());
- }
+ mUidObserverController.register(observer, which, cutpoint, callingPackage,
+ Binder.getCallingUid());
}
@Override
public void unregisterUidObserver(IUidObserver observer) {
- synchronized (this) {
- mUidObserverController.unregister(observer);
- }
+ mUidObserverController.unregister(observer);
}
@Override
@@ -7205,28 +7054,35 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i = mProcessList.mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord proc = mProcessList.mLruProcesses.get(i);
+ final ProcessProfileRecord pr = proc.mProfile;
if (proc.notCachedSinceIdle) {
if (proc.setProcState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
- if (doKilling && proc.initialIdlePss != 0
- && proc.lastPss > ((proc.initialIdlePss * 3) / 2)
- && proc.lastPss > (proc.initialIdlePss + memoryGrowthThreshold)) {
+ final long initialIdlePss, lastPss, lastSwapPss;
+ synchronized (mAppProfiler.mProfilerLock) {
+ initialIdlePss = pr.getInitialIdlePss();
+ lastPss = pr.getLastPss();
+ lastSwapPss = pr.getLastSwapPss();
+ }
+ if (doKilling && initialIdlePss != 0
+ && lastPss > ((initialIdlePss * 3) / 2)
+ && lastPss > (initialIdlePss + memoryGrowthThreshold)) {
sb = new StringBuilder(128);
sb.append("Kill");
sb.append(proc.processName);
sb.append(" in idle maint: pss=");
- sb.append(proc.lastPss);
+ sb.append(lastPss);
sb.append(", swapPss=");
- sb.append(proc.lastSwapPss);
+ sb.append(lastSwapPss);
sb.append(", initialPss=");
- sb.append(proc.initialIdlePss);
+ sb.append(initialIdlePss);
sb.append(", period=");
TimeUtils.formatDuration(timeSinceLastIdle, sb);
sb.append(", lowRamPeriod=");
TimeUtils.formatDuration(lowRamSinceLastIdle, sb);
Slog.wtfQuiet(TAG, sb.toString());
- proc.kill("idle maint (pss " + proc.lastPss
- + " from " + proc.initialIdlePss + ")",
+ proc.kill("idle maint (pss " + lastPss
+ + " from " + initialIdlePss + ")",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_MEMORY_PRESSURE,
true);
@@ -7235,8 +7091,11 @@ public class ActivityManagerService extends IActivityManager.Stub
} else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME
&& proc.setProcState >= ActivityManager.PROCESS_STATE_PERSISTENT) {
proc.notCachedSinceIdle = true;
- proc.initialIdlePss = 0;
- mAppProfiler.updateNextPssTimeLocked(proc.setProcState, proc, now, true);
+ synchronized (mAppProfiler.mProfilerLock) {
+ pr.setInitialIdlePss(0);
+ mAppProfiler.updateNextPssTimeLPf(
+ proc.setProcState, proc.mProfile, now, true);
+ }
}
}
}
@@ -7277,14 +7136,13 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppProfiler.retrieveSettings();
+ final Resources res;
synchronized (this) {
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
// Load resources only after the current configuration has been set.
- final Resources res = mContext.getResources();
- mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
- com.android.internal.R.string.config_appsNotReportingCrashes));
+ res = mContext.getResources();
final boolean userSwitchUiEnabled = !res.getBoolean(
com.android.internal.R.bool.config_customUserSwitchUi);
final int maxRunningUsers = res.getInteger(
@@ -7295,6 +7153,8 @@ public class ActivityManagerService extends IActivityManager.Stub
delayUserDataLocking);
mWaitForNetworkTimeoutMs = waitForNetworkTimeoutMs;
}
+ mAppErrors.loadAppsNotReportingCrashesFromConfig(res.getString(
+ com.android.internal.R.string.config_appsNotReportingCrashes));
}
/**
@@ -7714,9 +7574,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if ((penaltyMask & StrictMode.PENALTY_DIALOG) != 0) {
AppErrorResult result = new AppErrorResult();
- synchronized (this) {
- final long origId = Binder.clearCallingIdentity();
-
+ final long origId = Binder.clearCallingIdentity();
+ try {
Message msg = Message.obtain();
msg.what = SHOW_STRICT_MODE_VIOLATION_UI_MSG;
HashMap<String, Object> data = new HashMap<String, Object>();
@@ -7725,7 +7584,7 @@ public class ActivityManagerService extends IActivityManager.Stub
data.put("info", info);
msg.obj = data;
mUiHandler.sendMessage(msg);
-
+ } finally {
Binder.restoreCallingIdentity(origId);
}
int res = result.get();
@@ -7927,8 +7786,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int flags = process.info.flags;
IPackageManager pm = AppGlobals.getPackageManager();
sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
- for (int ip=0; ip<process.pkgList.size(); ip++) {
- String pkg = process.pkgList.keyAt(ip);
+ process.getPkgList().forEachPackage(pkg -> {
sb.append("Package: ").append(pkg);
try {
PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId());
@@ -7942,7 +7800,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.e(TAG, "Error getting package info: " + pkg, e);
}
sb.append("\n");
- }
+ });
if (process.info.isInstantApp()) {
sb.append("Instant-App: true\n");
}
@@ -8373,7 +8231,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpPermissionsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ dumpPermissions(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
sdumper = mServices.newServiceDumperLocked(fd, pw, args, opti, dumpAll, dumpPackage);
if (!dumpClient) {
@@ -8470,12 +8328,12 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
+ mProcessList.dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpUsersLocked(pw);
+ dumpUsers(pw);
}
}
@@ -8574,7 +8432,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// output proto is ProcessProto
synchronized (this) {
- writeProcessesToProtoLocked(proto, dumpPackage);
+ mProcessList.writeProcessesToProtoLocked(proto, dumpPackage);
}
} else {
// default option, dump everything, output is ActivityManagerServiceProto
@@ -8593,7 +8451,7 @@ public class ActivityManagerService extends IActivityManager.Stub
proto.end(serviceToken);
long processToken = proto.start(ActivityManagerServiceProto.PROCESSES);
- writeProcessesToProtoLocked(proto, dumpPackage);
+ mProcessList.writeProcessesToProtoLocked(proto, dumpPackage);
proto.end(processToken);
}
}
@@ -8660,20 +8518,19 @@ public class ActivityManagerService extends IActivityManager.Stub
dumpPackage = args[opti];
opti++;
}
- synchronized (this) {
- mPendingIntentController.dumpPendingIntents(pw, true, dumpPackage);
- }
+ mPendingIntentController.dumpPendingIntents(pw, true, dumpPackage);
} else if ("processes".equals(cmd) || "p".equals(cmd)) {
if (opti < args.length) {
dumpPackage = args[opti];
opti++;
}
synchronized (this) {
- dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage, dumpAppId);
+ mProcessList.dumpProcessesLocked(
+ fd, pw, args, opti, true, dumpPackage, dumpAppId);
}
} else if ("oom".equals(cmd) || "o".equals(cmd)) {
synchronized (this) {
- dumpOomLocked(fd, pw, false, args, opti, true, dumpPackage, true);
+ mProcessList.dumpOomLocked(fd, pw, false, args, opti, true, dumpPackage, true);
}
} else if ("lmk".equals(cmd)) {
synchronized (this) {
@@ -8681,12 +8538,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
} else if ("lru".equals(cmd)) {
synchronized (this) {
- dumpLruLocked(pw, dumpPackage, null);
+ mProcessList.dumpLruLocked(pw, dumpPackage, null);
}
} else if ("permissions".equals(cmd) || "perm".equals(cmd)) {
- synchronized (this) {
- dumpPermissionsLocked(fd, pw, args, opti, true, dumpPackage);
- }
+ dumpPermissions(fd, pw, args, opti, true, dumpPackage);
} else if ("provider".equals(cmd)) {
String[] newArgs;
String name;
@@ -8779,9 +8634,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} else if ("locks".equals(cmd)) {
LockGuard.dump(fd, pw, args);
} else if ("users".equals(cmd)) {
- synchronized (this) {
- dumpUsersLocked(pw);
- }
+ dumpUsers(pw);
} else if ("exit-info".equals(cmd)) {
if (opti < args.length) {
dumpPackage = args[opti];
@@ -8918,7 +8771,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private int getAppId(String dumpPackage) {
+ int getAppId(String dumpPackage) {
if (dumpPackage != null) {
try {
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
@@ -8983,177 +8836,12 @@ public class ActivityManagerService extends IActivityManager.Stub
" Counts of Binder Proxies held by SYSTEM");
}
- void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc, String prefix) {
- pw.print(prefix);
- pw.print('#');
- if (index < 10) {
- pw.print(' ');
- }
- pw.print(index);
- pw.print(": ");
- pw.print(ProcessList.makeOomAdjString(proc.setAdj, false));
- pw.print(' ');
- pw.print(ProcessList.makeProcStateString(proc.getCurProcState()));
- pw.print(' ');
- ActivityManager.printCapabilitiesSummary(pw, proc.curCapability);
- pw.print(' ');
- pw.print(proc.toShortString());
- if (proc.hasActivitiesOrRecentTasks() || proc.hasClientActivities()
- || proc.treatLikeActivity) {
- pw.print(" act:");
- boolean printed = false;
- if (proc.hasActivities()) {
- pw.print("activities");
- printed = true;
- }
- if (proc.hasRecentTasks()) {
- if (printed) {
- pw.print("|");
- }
- pw.print("recents");
- printed = true;
- }
- if (proc.hasClientActivities()) {
- if (printed) {
- pw.print("|");
- }
- pw.print("client");
- printed = true;
- }
- if (proc.treatLikeActivity) {
- if (printed) {
- pw.print("|");
- }
- pw.print("treated");
- }
- }
- pw.println();
- }
-
- // TODO: Move to ProcessList?
- boolean dumpLruLocked(PrintWriter pw, String dumpPackage, String prefix) {
- final int N = mProcessList.mLruProcesses.size();
- final String innerPrefix;
- if (prefix == null) {
- pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)");
- innerPrefix = " ";
- } else {
- boolean haveAny = false;
- for (int i = N - 1; i >= 0; i--) {
- final ProcessRecord r = mProcessList.mLruProcesses.get(i);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- haveAny = true;
- break;
- }
- if (!haveAny) {
- return false;
- }
- pw.print(prefix);
- pw.println("Raw LRU list (dumpsys activity lru):");
- innerPrefix = prefix + " ";
- }
- int i;
- boolean first = true;
- for (i = N - 1; i >= mProcessList.mLruProcessActivityStart; i--) {
- final ProcessRecord r = mProcessList.mLruProcesses.get(i);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- if (first) {
- pw.print(innerPrefix);
- pw.println("Activities:");
- first = false;
- }
- dumpLruEntryLocked(pw, i, r, innerPrefix);
- }
- first = true;
- for (; i >= mProcessList.mLruProcessServiceStart; i--) {
- final ProcessRecord r = mProcessList.mLruProcesses.get(i);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- if (first) {
- pw.print(innerPrefix);
- pw.println("Services:");
- first = false;
- }
- dumpLruEntryLocked(pw, i, r, innerPrefix);
- }
- first = true;
- for (; i >= 0; i--) {
- final ProcessRecord r = mProcessList.mLruProcesses.get(i);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- if (first) {
- pw.print(innerPrefix);
- pw.println("Other:");
- first = false;
- }
- dumpLruEntryLocked(pw, i, r, innerPrefix);
- }
- return true;
- }
-
- // TODO: Move to ProcessList?
@GuardedBy("this")
- void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
- boolean needSep = false;
- int numPers = 0;
-
- pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
-
- if (dumpAll || dumpPackage != null) {
- final int NP = mProcessList.mProcessNames.getMap().size();
- for (int ip=0; ip<NP; ip++) {
- SparseArray<ProcessRecord> procs = mProcessList.mProcessNames.getMap().valueAt(ip);
- final int NA = procs.size();
- for (int ia=0; ia<NA; ia++) {
- ProcessRecord r = procs.valueAt(ia);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- if (!needSep) {
- pw.println(" All known processes:");
- needSep = true;
- }
- pw.print(r.isPersistent() ? " *PERS*" : " *APP*");
- pw.print(" UID "); pw.print(procs.keyAt(ia));
- pw.print(" "); pw.println(r);
- r.dump(pw, " ");
- if (r.isPersistent()) {
- numPers++;
- }
- }
- }
- }
-
- if (mProcessList.mIsolatedProcesses.size() > 0) {
- boolean printed = false;
- for (int i=0; i<mProcessList.mIsolatedProcesses.size(); i++) {
- ProcessRecord r = mProcessList.mIsolatedProcesses.valueAt(i);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- pw.println(" Isolated process list (sorted by uid):");
- printed = true;
- needSep = true;
- }
- pw.print(" Isolated #"); pw.print(i); pw.print(": ");
- pw.println(r);
- }
- }
-
- if (mActiveInstrumentation.size() > 0) {
+ boolean dumpActiveInstruments(PrintWriter pw, String dumpPackage, boolean needSep) {
+ final int size = mActiveInstrumentation.size();
+ if (size > 0) {
boolean printed = false;
- for (int i=0; i<mActiveInstrumentation.size(); i++) {
+ for (int i = 0; i < size; i++) {
ActiveInstrumentation ai = mActiveInstrumentation.get(i);
if (dumpPackage != null && !ai.mClass.getPackageName().equals(dumpPackage)
&& !ai.mTargetInfo.packageName.equals(dumpPackage)) {
@@ -9172,48 +8860,20 @@ public class ActivityManagerService extends IActivityManager.Stub
ai.dump(pw, " ");
}
}
+ return needSep;
+ }
- if (dumpOomLocked(fd, pw, needSep, args, opti, dumpAll, dumpPackage, false)) {
- needSep = true;
- }
-
- needSep = dumpProcessesToGc(pw, needSep, dumpPackage);
-
- if (mProcessList.mActiveUids.size() > 0) {
- needSep |= mProcessList.mActiveUids.dump(pw, dumpPackage, dumpAppId,
- "UID states:", needSep);
- }
-
- if (dumpAll) {
- needSep |= mUidObserverController.dumpValidateUids(pw,
- dumpPackage, dumpAppId, "UID validation:", needSep);
- }
-
- if (needSep) {
- pw.println();
- }
- if (dumpLruLocked(pw, dumpPackage, " ")) {
- needSep = true;
- }
-
- if (mProcessList.getLruSizeLocked() > 0) {
- if (needSep) {
- pw.println();
- }
- mProcessList.dumpLruListHeaderLocked(pw);
- dumpProcessOomList(pw, this, mProcessList.mLruProcesses, " ", "Proc", "PERS", false,
- dumpPackage);
- needSep = true;
- }
-
+ @GuardedBy("this")
+ void dumpOtherProcessesInfoLocked(FileDescriptor fd, PrintWriter pw,
+ boolean dumpAll, String dumpPackage, int dumpAppId, int numPers, boolean needSep) {
if (dumpAll || dumpPackage != null) {
final SparseArray<ProcessRecord> pidToProcess = new SparseArray<>();
synchronized (mPidsSelfLocked) {
boolean printed = false;
- for (int i=0; i<mPidsSelfLocked.size(); i++) {
+ for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) {
ProcessRecord r = mPidsSelfLocked.valueAt(i);
pidToProcess.put(r.pid, r);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
continue;
}
if (!printed) {
@@ -9229,10 +8889,11 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (sActiveProcessInfoSelfLocked) {
boolean printed = false;
- for (int i = 0; i < sActiveProcessInfoSelfLocked.size(); i++) {
+ for (int i = 0, size = sActiveProcessInfoSelfLocked.size(); i < size; i++) {
ProcessInfo info = sActiveProcessInfoSelfLocked.valueAt(i);
ProcessRecord r = pidToProcess.get(sActiveProcessInfoSelfLocked.keyAt(i));
- if (r != null && dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ if (r != null && dumpPackage != null
+ && !r.getPkgList().containsKey(dumpPackage)) {
continue;
}
if (!printed) {
@@ -9261,11 +8922,11 @@ public class ActivityManagerService extends IActivityManager.Stub
if (mImportantProcesses.size() > 0) {
synchronized (mPidsSelfLocked) {
boolean printed = false;
- for (int i = 0; i< mImportantProcesses.size(); i++) {
+ for (int i = 0, size = mImportantProcesses.size(); i < size; i++) {
ProcessRecord r = mPidsSelfLocked.get(
mImportantProcesses.valueAt(i).pid);
if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
+ || !r.getPkgList().containsKey(dumpPackage))) {
continue;
}
if (!printed) {
@@ -9307,7 +8968,7 @@ public class ActivityManagerService extends IActivityManager.Stub
needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage);
needSep = mAtmInternal.dumpForProcesses(fd, pw, dumpAll, dumpPackage, dumpAppId, needSep,
- mAppProfiler.getTestPssModeLocked(), mWakefulness);
+ mAppProfiler.getTestPssMode(), mWakefulness.get());
if (dumpAll && mProcessList.mPendingStarts.size() > 0) {
if (needSep) pw.println();
@@ -9321,14 +8982,14 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpAll) {
mUidObserverController.dump(pw, dumpPackage);
- pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
- pw.println(" mDeviceIdleExceptIdleWhitelist="
- + Arrays.toString(mDeviceIdleExceptIdleWhitelist));
- pw.println(" mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
- if (mPendingTempWhitelist.size() > 0) {
- pw.println(" mPendingTempWhitelist:");
- for (int i = 0; i < mPendingTempWhitelist.size(); i++) {
- PendingTempWhitelist ptw = mPendingTempWhitelist.valueAt(i);
+ pw.println(" mDeviceIdleAllowlist=" + Arrays.toString(mDeviceIdleAllowlist));
+ pw.println(" mDeviceIdleExceptIdleAllowlist="
+ + Arrays.toString(mDeviceIdleExceptIdleAllowlist));
+ pw.println(" mDeviceIdleTempAllowlist=" + Arrays.toString(mDeviceIdleTempAllowlist));
+ if (mPendingTempAllowlist.size() > 0) {
+ pw.println(" mPendingTempAllowlist:");
+ for (int i = 0, size = mPendingTempAllowlist.size(); i < size; i++) {
+ PendingTempAllowlist ptw = mPendingTempAllowlist.valueAt(i);
pw.print(" ");
UserHandle.formatUid(pw, ptw.targetUid);
pw.print(": ");
@@ -9353,7 +9014,9 @@ public class ActivityManagerService extends IActivityManager.Stub
+ " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
}
}
- needSep = mAppProfiler.dumpMemWatchProcessesLocked(pw, needSep);
+ synchronized (mAppProfiler.mProfilerLock) {
+ needSep = mAppProfiler.dumpMemWatchProcessesLPf(pw, needSep);
+ }
if (mTrackAllocationApp != null) {
if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) {
if (needSep) {
@@ -9409,45 +9072,15 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println(" mForceBackgroundCheck=" + mForceBackgroundCheck);
}
- @GuardedBy("this")
- private void dumpUsersLocked(PrintWriter pw) {
+ private void dumpUsers(PrintWriter pw) {
pw.println("ACTIVITY MANAGER USERS (dumpsys activity users)");
mUserController.dump(pw);
}
@GuardedBy("this")
- void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) {
- int numPers = 0;
-
- final int NP = mProcessList.mProcessNames.getMap().size();
- for (int ip=0; ip<NP; ip++) {
- SparseArray<ProcessRecord> procs = mProcessList.mProcessNames.getMap().valueAt(ip);
- final int NA = procs.size();
- for (int ia = 0; ia<NA; ia++) {
- ProcessRecord r = procs.valueAt(ia);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.PROCS,
- mProcessList.mLruProcesses.indexOf(r)
- );
- if (r.isPersistent()) {
- numPers++;
- }
- }
- }
-
- for (int i=0; i<mProcessList.mIsolatedProcesses.size(); i++) {
- ProcessRecord r = mProcessList.mIsolatedProcesses.valueAt(i);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS,
- mProcessList.mLruProcesses.indexOf(r)
- );
- }
-
- for (int i=0; i<mActiveInstrumentation.size(); i++) {
+ void writeOtherProcessesInfoToProtoLocked(ProtoOutputStream proto, String dumpPackage,
+ int dumpAppId, int numPers) {
+ for (int i = 0, size = mActiveInstrumentation.size(); i < size; i++) {
ActiveInstrumentation ai = mActiveInstrumentation.get(i);
if (dumpPackage != null && !ai.mClass.getPackageName().equals(dumpPackage)
&& !ai.mTargetInfo.packageName.equals(dumpPackage)) {
@@ -9457,32 +9090,14 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityManagerServiceDumpProcessesProto.ACTIVE_INSTRUMENTATIONS);
}
- final int dumpAppId = getAppId(dumpPackage);
- mProcessList.mActiveUids.dumpProto(proto, dumpPackage, dumpAppId,
- ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
-
mUidObserverController.dumpValidateUidsProto(proto, dumpPackage, dumpAppId,
ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
- if (mProcessList.getLruSizeLocked() > 0) {
- long lruToken = proto.start(ActivityManagerServiceDumpProcessesProto.LRU_PROCS);
- int total = mProcessList.getLruSizeLocked();
- proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.SIZE, total);
- proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_ACT_AT,
- total - mProcessList.mLruProcessActivityStart);
- proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_SVC_AT,
- total - mProcessList.mLruProcessServiceStart);
- writeProcessOomListToProto(proto,
- ActivityManagerServiceDumpProcessesProto.LruProcesses.LIST, this,
- mProcessList.mLruProcesses,false, dumpPackage);
- proto.end(lruToken);
- }
-
if (dumpPackage != null) {
synchronized (mPidsSelfLocked) {
for (int i=0; i<mPidsSelfLocked.size(); i++) {
ProcessRecord r = mPidsSelfLocked.valueAt(i);
- if (!r.pkgList.containsKey(dumpPackage)) {
+ if (!r.getPkgList().containsKey(dumpPackage)) {
continue;
}
r.dumpDebug(proto,
@@ -9493,11 +9108,11 @@ public class ActivityManagerService extends IActivityManager.Stub
if (mImportantProcesses.size() > 0) {
synchronized (mPidsSelfLocked) {
- for (int i=0; i<mImportantProcesses.size(); i++) {
+ for (int i = 0, size = mImportantProcesses.size(); i < size; i++) {
ImportanceToken it = mImportantProcesses.valueAt(i);
ProcessRecord r = mPidsSelfLocked.get(it.pid);
if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
+ || !r.getPkgList().containsKey(dumpPackage))) {
continue;
}
it.dumpDebug(proto,
@@ -9506,7 +9121,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- for (int i=0; i<mPersistentStartingProcesses.size(); i++) {
+ for (int i = 0, size = mPersistentStartingProcesses.size(); i < size; i++) {
ProcessRecord r = mPersistentStartingProcesses.get(i);
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
@@ -9515,7 +9130,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityManagerServiceDumpProcessesProto.PERSISTENT_STARTING_PROCS);
}
- for (int i = 0; i < mProcessList.mRemovedProcesses.size(); i++) {
+ for (int i = 0, size = mProcessList.mRemovedProcesses.size(); i < size; i++) {
ProcessRecord r = mProcessList.mRemovedProcesses.get(i);
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
@@ -9523,7 +9138,7 @@ public class ActivityManagerService extends IActivityManager.Stub
r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.REMOVED_PROCS);
}
- for (int i=0; i<mProcessesOnHold.size(); i++) {
+ for (int i = 0, size = mProcessesOnHold.size(); i < size; i++) {
ProcessRecord r = mProcessesOnHold.get(i);
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
@@ -9531,12 +9146,15 @@ public class ActivityManagerService extends IActivityManager.Stub
r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ON_HOLD_PROCS);
}
- writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS,
- dumpPackage);
+ synchronized (mAppProfiler.mProfilerLock) {
+ mAppProfiler.writeProcessesToGcToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.GC_PROCS,
+ dumpPackage);
+ }
mAppErrors.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS,
dumpPackage);
- mAtmInternal.writeProcessesToProto(proto, dumpPackage, mWakefulness,
- mAppProfiler.getTestPssModeLocked());
+ mAtmInternal.writeProcessesToProto(proto, dumpPackage, mWakefulness.get(),
+ mAppProfiler.getTestPssMode());
if (dumpPackage == null) {
mUserController.dumpDebug(proto,
@@ -9545,17 +9163,17 @@ public class ActivityManagerService extends IActivityManager.Stub
mUidObserverController.dumpDebug(proto, dumpPackage);
- for (int v : mDeviceIdleWhitelist) {
+ for (int v : mDeviceIdleAllowlist) {
proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_WHITELIST, v);
}
- for (int v : mDeviceIdleTempWhitelist) {
+ for (int v : mDeviceIdleTempAllowlist) {
proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_TEMP_WHITELIST, v);
}
- if (mPendingTempWhitelist.size() > 0) {
- for (int i=0; i < mPendingTempWhitelist.size(); i++) {
- mPendingTempWhitelist.valueAt(i).dumpDebug(proto,
+ if (mPendingTempAllowlist.size() > 0) {
+ for (int i = 0, size = mPendingTempAllowlist.size(); i < size; i++) {
+ mPendingTempAllowlist.valueAt(i).dumpDebug(proto,
ActivityManagerServiceDumpProcessesProto.PENDING_TEMP_WHITELIST);
}
}
@@ -9573,7 +9191,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- mAppProfiler.writeMemWatchProcessToProtoLocked(proto);
+ synchronized (mAppProfiler.mProfilerLock) {
+ mAppProfiler.writeMemWatchProcessToProtoLPf(proto);
+ }
if (mTrackAllocationApp != null) {
if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) {
@@ -9608,113 +9228,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
- if (mProcessesToGc.size() > 0) {
- long now = SystemClock.uptimeMillis();
- for (int i=0; i<mProcessesToGc.size(); i++) {
- ProcessRecord r = mProcessesToGc.get(i);
- if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
- continue;
- }
- final long token = proto.start(fieldId);
- r.dumpDebug(proto, ProcessToGcProto.PROC);
- proto.write(ProcessToGcProto.REPORT_LOW_MEMORY, r.reportLowMemory);
- proto.write(ProcessToGcProto.NOW_UPTIME_MS, now);
- proto.write(ProcessToGcProto.LAST_GCED_MS, r.lastRequestedGc);
- proto.write(ProcessToGcProto.LAST_LOW_MEMORY_MS, r.lastLowMemory);
- proto.end(token);
- }
- }
- }
-
- boolean dumpProcessesToGc(PrintWriter pw, boolean needSep, String dumpPackage) {
- if (mProcessesToGc.size() > 0) {
- boolean printed = false;
- long now = SystemClock.uptimeMillis();
- for (int i=0; i<mProcessesToGc.size(); i++) {
- ProcessRecord proc = mProcessesToGc.get(i);
- if (dumpPackage != null && !dumpPackage.equals(proc.info.packageName)) {
- continue;
- }
- if (!printed) {
- if (needSep) pw.println();
- needSep = true;
- pw.println(" Processes that are waiting to GC:");
- printed = true;
- }
- pw.print(" Process "); pw.println(proc);
- pw.print(" lowMem="); pw.print(proc.reportLowMemory);
- pw.print(", last gced=");
- pw.print(now-proc.lastRequestedGc);
- pw.print(" ms ago, last lowMem=");
- pw.print(now-proc.lastLowMemory);
- pw.println(" ms ago");
-
- }
- }
- return needSep;
- }
-
- void printOomLevel(PrintWriter pw, String name, int adj) {
- pw.print(" ");
- if (adj >= 0) {
- pw.print(' ');
- if (adj < 10) pw.print(' ');
- } else {
- if (adj > -10) pw.print(' ');
- }
- pw.print(adj);
- pw.print(": ");
- pw.print(name);
- pw.print(" (");
- pw.print(stringifySize(mProcessList.getMemLevel(adj), 1024));
- pw.println(")");
- }
-
- boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String[] args,
- int opti, boolean dumpAll, String dumpPackage, boolean inclGc) {
- if (mProcessList.getLruSizeLocked() > 0) {
- if (needSep) pw.println();
- needSep = true;
- pw.println(" OOM levels:");
- printOomLevel(pw, "SYSTEM_ADJ", ProcessList.SYSTEM_ADJ);
- printOomLevel(pw, "PERSISTENT_PROC_ADJ", ProcessList.PERSISTENT_PROC_ADJ);
- printOomLevel(pw, "PERSISTENT_SERVICE_ADJ", ProcessList.PERSISTENT_SERVICE_ADJ);
- printOomLevel(pw, "FOREGROUND_APP_ADJ", ProcessList.FOREGROUND_APP_ADJ);
- printOomLevel(pw, "VISIBLE_APP_ADJ", ProcessList.VISIBLE_APP_ADJ);
- printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", ProcessList.PERCEPTIBLE_APP_ADJ);
- printOomLevel(pw, "PERCEPTIBLE_LOW_APP_ADJ", ProcessList.PERCEPTIBLE_LOW_APP_ADJ);
- printOomLevel(pw, "BACKUP_APP_ADJ", ProcessList.BACKUP_APP_ADJ);
- printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", ProcessList.HEAVY_WEIGHT_APP_ADJ);
- printOomLevel(pw, "SERVICE_ADJ", ProcessList.SERVICE_ADJ);
- printOomLevel(pw, "HOME_APP_ADJ", ProcessList.HOME_APP_ADJ);
- printOomLevel(pw, "PREVIOUS_APP_ADJ", ProcessList.PREVIOUS_APP_ADJ);
- printOomLevel(pw, "SERVICE_B_ADJ", ProcessList.SERVICE_B_ADJ);
- printOomLevel(pw, "CACHED_APP_MIN_ADJ", ProcessList.CACHED_APP_MIN_ADJ);
- printOomLevel(pw, "CACHED_APP_MAX_ADJ", ProcessList.CACHED_APP_MAX_ADJ);
-
- if (needSep) pw.println();
- pw.print(" Process OOM control ("); pw.print(mProcessList.getLruSizeLocked());
- pw.print(" total, non-act at ");
- pw.print(mProcessList.getLruSizeLocked()
- - mProcessList.mLruProcessActivityStart);
- pw.print(", non-svc at ");
- pw.print(mProcessList.getLruSizeLocked()
- - mProcessList.mLruProcessServiceStart);
- pw.println("):");
- dumpProcessOomList(pw, this, mProcessList.mLruProcesses, " ", "Proc", "PERS", true,
- dumpPackage);
- needSep = true;
- }
-
- dumpProcessesToGc(pw, needSep, dumpPackage);
-
- pw.println();
- mAtmInternal.dumpForOom(pw);
-
- return true;
- }
-
private boolean reportLmkKillAtOrBelow(PrintWriter pw, int oom_adj) {
Integer cnt = ProcessList.getLmkdKillCount(0, oom_adj);
if (cnt != null) {
@@ -10050,8 +9563,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- @GuardedBy("this")
- void dumpPermissionsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ void dumpPermissions(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
pw.println("ACTIVITY MANAGER URI PERMISSIONS (dumpsys activity permissions)");
@@ -10080,270 +9592,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return numPers;
}
- private static final ArrayList<Pair<ProcessRecord, Integer>>
- sortProcessOomList(List<ProcessRecord> origList, String dumpPackage) {
- ArrayList<Pair<ProcessRecord, Integer>> list
- = new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
- for (int i=0; i<origList.size(); i++) {
- ProcessRecord r = origList.get(i);
- if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
- continue;
- }
- list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i));
- }
-
- Comparator<Pair<ProcessRecord, Integer>> comparator
- = new Comparator<Pair<ProcessRecord, Integer>>() {
- @Override
- public int compare(Pair<ProcessRecord, Integer> object1,
- Pair<ProcessRecord, Integer> object2) {
- if (object1.first.setAdj != object2.first.setAdj) {
- return object1.first.setAdj > object2.first.setAdj ? -1 : 1;
- }
- if (object1.first.setProcState != object2.first.setProcState) {
- return object1.first.setProcState > object2.first.setProcState ? -1 : 1;
- }
- if (object1.second.intValue() != object2.second.intValue()) {
- return object1.second.intValue() > object2.second.intValue() ? -1 : 1;
- }
- return 0;
- }
- };
-
- Collections.sort(list, comparator);
- return list;
- }
-
- private static final boolean writeProcessOomListToProto(ProtoOutputStream proto, long fieldId,
- ActivityManagerService service, List<ProcessRecord> origList,
- boolean inclDetails, String dumpPackage) {
- ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
- if (list.isEmpty()) return false;
-
- final long curUptime = SystemClock.uptimeMillis();
-
- for (int i = list.size() - 1; i >= 0; i--) {
- ProcessRecord r = list.get(i).first;
- long token = proto.start(fieldId);
- String oomAdj = ProcessList.makeOomAdjString(r.setAdj, true);
- proto.write(ProcessOomProto.PERSISTENT, r.isPersistent());
- proto.write(ProcessOomProto.NUM, (origList.size()-1)-list.get(i).second);
- proto.write(ProcessOomProto.OOM_ADJ, oomAdj);
- int schedGroup = ProcessOomProto.SCHED_GROUP_UNKNOWN;
- switch (r.setSchedGroup) {
- case ProcessList.SCHED_GROUP_BACKGROUND:
- schedGroup = ProcessOomProto.SCHED_GROUP_BACKGROUND;
- break;
- case ProcessList.SCHED_GROUP_DEFAULT:
- schedGroup = ProcessOomProto.SCHED_GROUP_DEFAULT;
- break;
- case ProcessList.SCHED_GROUP_TOP_APP:
- schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP;
- break;
- case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
- schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP_BOUND;
- break;
- }
- if (schedGroup != ProcessOomProto.SCHED_GROUP_UNKNOWN) {
- proto.write(ProcessOomProto.SCHED_GROUP, schedGroup);
- }
- if (r.hasForegroundActivities()) {
- proto.write(ProcessOomProto.ACTIVITIES, true);
- } else if (r.hasForegroundServices()) {
- proto.write(ProcessOomProto.SERVICES, true);
- }
- proto.write(ProcessOomProto.STATE,
- ProcessList.makeProcStateProtoEnum(r.getCurProcState()));
- proto.write(ProcessOomProto.TRIM_MEMORY_LEVEL, r.trimMemoryLevel);
- r.dumpDebug(proto, ProcessOomProto.PROC);
- proto.write(ProcessOomProto.ADJ_TYPE, r.adjType);
- if (r.adjSource != null || r.adjTarget != null) {
- if (r.adjTarget instanceof ComponentName) {
- ComponentName cn = (ComponentName) r.adjTarget;
- cn.dumpDebug(proto, ProcessOomProto.ADJ_TARGET_COMPONENT_NAME);
- } else if (r.adjTarget != null) {
- proto.write(ProcessOomProto.ADJ_TARGET_OBJECT, r.adjTarget.toString());
- }
- if (r.adjSource instanceof ProcessRecord) {
- ProcessRecord p = (ProcessRecord) r.adjSource;
- p.dumpDebug(proto, ProcessOomProto.ADJ_SOURCE_PROC);
- } else if (r.adjSource != null) {
- proto.write(ProcessOomProto.ADJ_SOURCE_OBJECT, r.adjSource.toString());
- }
- }
- if (inclDetails) {
- long detailToken = proto.start(ProcessOomProto.DETAIL);
- proto.write(ProcessOomProto.Detail.MAX_ADJ, r.maxAdj);
- proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, r.getCurRawAdj());
- proto.write(ProcessOomProto.Detail.SET_RAW_ADJ, r.setRawAdj);
- proto.write(ProcessOomProto.Detail.CUR_ADJ, r.curAdj);
- proto.write(ProcessOomProto.Detail.SET_ADJ, r.setAdj);
- proto.write(ProcessOomProto.Detail.CURRENT_STATE,
- ProcessList.makeProcStateProtoEnum(r.getCurProcState()));
- proto.write(ProcessOomProto.Detail.SET_STATE,
- ProcessList.makeProcStateProtoEnum(r.setProcState));
- proto.write(ProcessOomProto.Detail.LAST_PSS, DebugUtils.sizeValueToString(
- r.lastPss*1024, new StringBuilder()));
- proto.write(ProcessOomProto.Detail.LAST_SWAP_PSS, DebugUtils.sizeValueToString(
- r.lastSwapPss*1024, new StringBuilder()));
- proto.write(ProcessOomProto.Detail.LAST_CACHED_PSS, DebugUtils.sizeValueToString(
- r.lastCachedPss*1024, new StringBuilder()));
- proto.write(ProcessOomProto.Detail.CACHED, r.isCached());
- proto.write(ProcessOomProto.Detail.EMPTY, r.empty);
- proto.write(ProcessOomProto.Detail.HAS_ABOVE_CLIENT, r.hasAboveClient);
-
- if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
- if (r.lastCpuTime != 0) {
- long uptimeSince = curUptime - service.mLastPowerCheckUptime;
- long timeUsed = r.curCpuTime - r.lastCpuTime;
- long cpuTimeToken = proto.start(ProcessOomProto.Detail.SERVICE_RUN_TIME);
- proto.write(ProcessOomProto.Detail.CpuRunTime.OVER_MS, uptimeSince);
- proto.write(ProcessOomProto.Detail.CpuRunTime.USED_MS, timeUsed);
- proto.write(ProcessOomProto.Detail.CpuRunTime.ULTILIZATION,
- (100.0*timeUsed)/uptimeSince);
- proto.end(cpuTimeToken);
- }
- }
- proto.end(detailToken);
- }
- proto.end(token);
- }
-
- return true;
- }
-
- private static final boolean dumpProcessOomList(PrintWriter pw,
- ActivityManagerService service, List<ProcessRecord> origList,
- String prefix, String normalLabel, String persistentLabel,
- boolean inclDetails, String dumpPackage) {
-
- ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
- if (list.isEmpty()) return false;
-
- final long curUptime = SystemClock.uptimeMillis();
- final long uptimeSince = curUptime - service.mLastPowerCheckUptime;
-
- for (int i=list.size()-1; i>=0; i--) {
- ProcessRecord r = list.get(i).first;
- String oomAdj = ProcessList.makeOomAdjString(r.setAdj, false);
- char schedGroup;
- switch (r.setSchedGroup) {
- case ProcessList.SCHED_GROUP_BACKGROUND:
- schedGroup = 'b';
- break;
- case ProcessList.SCHED_GROUP_DEFAULT:
- schedGroup = 'F';
- break;
- case ProcessList.SCHED_GROUP_TOP_APP:
- schedGroup = 'T';
- break;
- case ProcessList.SCHED_GROUP_RESTRICTED:
- schedGroup = 'R';
- break;
- case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
- schedGroup = 'B';
- break;
- default:
- schedGroup = '?';
- break;
- }
- char foreground;
- if (r.hasForegroundActivities()) {
- foreground = 'A';
- } else if (r.hasForegroundServices()) {
- foreground = 'S';
- } else {
- foreground = ' ';
- }
- String procState = ProcessList.makeProcStateString(r.getCurProcState());
- pw.print(prefix);
- pw.print(r.isPersistent() ? persistentLabel : normalLabel);
- pw.print(" #");
- int num = (origList.size()-1)-list.get(i).second;
- if (num < 10) pw.print(' ');
- pw.print(num);
- pw.print(": ");
- pw.print(oomAdj);
- pw.print(' ');
- pw.print(schedGroup);
- pw.print('/');
- pw.print(foreground);
- pw.print('/');
- pw.print(procState);
- pw.print(' ');
- ActivityManager.printCapabilitiesSummary(pw, r.curCapability);
- pw.print(' ');
- pw.print(" t:");
- if (r.trimMemoryLevel < 10) pw.print(' ');
- pw.print(r.trimMemoryLevel);
- pw.print(' ');
- pw.print(r.toShortString());
- pw.print(" (");
- pw.print(r.adjType);
- pw.println(')');
- if (r.adjSource != null || r.adjTarget != null) {
- pw.print(prefix);
- pw.print(" ");
- if (r.adjTarget instanceof ComponentName) {
- pw.print(((ComponentName)r.adjTarget).flattenToShortString());
- } else if (r.adjTarget != null) {
- pw.print(r.adjTarget.toString());
- } else {
- pw.print("{null}");
- }
- pw.print("<=");
- if (r.adjSource instanceof ProcessRecord) {
- pw.print("Proc{");
- pw.print(((ProcessRecord)r.adjSource).toShortString());
- pw.println("}");
- } else if (r.adjSource != null) {
- pw.println(r.adjSource.toString());
- } else {
- pw.println("{null}");
- }
- }
- if (inclDetails) {
- pw.print(prefix);
- pw.print(" ");
- pw.print("oom: max="); pw.print(r.maxAdj);
- pw.print(" curRaw="); pw.print(r.getCurRawAdj());
- pw.print(" setRaw="); pw.print(r.setRawAdj);
- pw.print(" cur="); pw.print(r.curAdj);
- pw.print(" set="); pw.println(r.setAdj);
- pw.print(prefix);
- pw.print(" ");
- pw.print("state: cur="); pw.print(
- ProcessList.makeProcStateString(r.getCurProcState()));
- pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
- pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
- pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, r.lastSwapPss*1024);
- pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024);
- pw.println();
- pw.print(prefix);
- pw.print(" ");
- pw.print("cached="); pw.print(r.isCached());
- pw.print(" empty="); pw.print(r.empty);
- pw.print(" hasAboveClient="); pw.println(r.hasAboveClient);
-
- if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
- if (r.lastCpuTime != 0) {
- long timeUsed = r.curCpuTime - r.lastCpuTime;
- pw.print(prefix);
- pw.print(" ");
- pw.print("run cpu over ");
- TimeUtils.formatDuration(uptimeSince, pw);
- pw.print(" used ");
- TimeUtils.formatDuration(timeUsed, pw);
- pw.print(" (");
- pw.print((timeUsed*100)/uptimeSince);
- pw.println("%)");
- }
- }
- }
- }
- return true;
- }
-
ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, int start, boolean allPkgs,
String[] args) {
synchronized (this) {
@@ -10637,12 +9885,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private static final int KSM_SHARED = 0;
- private static final int KSM_SHARING = 1;
- private static final int KSM_UNSHARED = 2;
- private static final int KSM_VOLATILE = 3;
+ static final int KSM_SHARED = 0;
+ static final int KSM_SHARING = 1;
+ static final int KSM_UNSHARED = 2;
+ static final int KSM_VOLATILE = 3;
- private final long[] getKsmInfo() {
+ static final long[] getKsmInfo() {
long[] longOut = new long[4];
final int[] SINGLE_LONG_FORMAT = new int[] {
PROC_SPACE_TERM| PROC_OUT_LONG
@@ -10666,7 +9914,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return longOut;
}
- private static String stringifySize(long size, int order) {
+ static String stringifySize(long size, int order) {
Locale locale = Locale.US;
switch (order) {
case 1:
@@ -10682,7 +9930,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private static String stringifyKBSize(long size) {
+ static String stringifyKBSize(long size) {
return stringifySize(size * 1024, 1024);
}
@@ -10978,12 +10226,9 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
- synchronized (mProcessStats.mLock) {
- r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
- reportType, endTime - startTime, r.pkgList.mPkgList);
- }
- for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg);
+ r.mProfile.addPss(myTotalPss, myTotalUss, myTotalRss, true,
+ reportType, endTime - startTime);
+ r.getPkgList().forEachPackageProcessStats(holder -> {
FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
r.info.uid,
holder.state.getName(),
@@ -10991,7 +10236,7 @@ public class ActivityManagerService extends IActivityManager.Stub
myTotalPss, myTotalUss, myTotalRss, reportType,
endTime-startTime,
holder.appVersion);
- }
+ });
}
}
@@ -11561,19 +10806,16 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
- synchronized (mProcessStats.mLock) {
- r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
- reportType, endTime - startTime, r.pkgList.mPkgList);
- }
- for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg);
+ r.mProfile.addPss(myTotalPss, myTotalUss, myTotalRss, true,
+ reportType, endTime - startTime);
+ r.getPkgList().forEachPackageProcessStats(holder -> {
FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
r.info.uid,
holder.state.getName(),
holder.state.getPackage(),
myTotalPss, myTotalUss, myTotalRss, reportType, endTime-startTime,
holder.appVersion);
- }
+ });
}
}
@@ -11844,7 +11086,7 @@ public class ActivityManagerService extends IActivityManager.Stub
proto.flush();
}
- private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
+ static void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
long memtrack, String name) {
sb.append(" ");
sb.append(ProcessList.makeOomAdjString(oomAdj, false));
@@ -11861,7 +11103,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
+ static void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.memtrack, mi.name);
sb.append(" (pid ");
sb.append(mi.pid);
@@ -11875,283 +11117,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
- final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
- infoMap.put(mi.pid, mi);
- }
- updateCpuStatsNow();
- long[] memtrackTmp = new long[1];
- long[] swaptrackTmp = new long[2];
- // Get a list of Stats that have vsize > 0
- final List<ProcessCpuTracker.Stats> stats = mAppProfiler.getCpuStats(st -> st.vsize > 0);
- final int statsCount = stats.size();
- for (int i = 0; i < statsCount; i++) {
- ProcessCpuTracker.Stats st = stats.get(i);
- long pss = Debug.getPss(st.pid, swaptrackTmp, memtrackTmp);
- if (pss > 0) {
- if (infoMap.indexOfKey(st.pid) < 0) {
- ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
- ProcessList.NATIVE_ADJ, -1, "native", null);
- mi.pss = pss;
- mi.swapPss = swaptrackTmp[1];
- mi.memtrack = memtrackTmp[0];
- memInfos.add(mi);
- }
- }
- }
-
- long totalPss = 0;
- long totalSwapPss = 0;
- long totalMemtrack = 0;
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
- if (mi.pss == 0) {
- mi.pss = Debug.getPss(mi.pid, swaptrackTmp, memtrackTmp);
- mi.swapPss = swaptrackTmp[1];
- mi.memtrack = memtrackTmp[0];
- }
- totalPss += mi.pss;
- totalSwapPss += mi.swapPss;
- totalMemtrack += mi.memtrack;
- }
- Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
- @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
- if (lhs.oomAdj != rhs.oomAdj) {
- return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
- }
- if (lhs.pss != rhs.pss) {
- return lhs.pss < rhs.pss ? 1 : -1;
- }
- return 0;
- }
- });
-
- StringBuilder tag = new StringBuilder(128);
- StringBuilder stack = new StringBuilder(128);
- tag.append("Low on memory -- ");
- appendMemBucket(tag, totalPss, "total", false);
- appendMemBucket(stack, totalPss, "total", true);
-
- StringBuilder fullNativeBuilder = new StringBuilder(1024);
- StringBuilder shortNativeBuilder = new StringBuilder(1024);
- StringBuilder fullJavaBuilder = new StringBuilder(1024);
-
- boolean firstLine = true;
- int lastOomAdj = Integer.MIN_VALUE;
- long extraNativeRam = 0;
- long extraNativeMemtrack = 0;
- long cachedPss = 0;
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
-
- if (mi.oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- cachedPss += mi.pss;
- }
-
- if (mi.oomAdj != ProcessList.NATIVE_ADJ
- && (mi.oomAdj < ProcessList.SERVICE_ADJ
- || mi.oomAdj == ProcessList.HOME_APP_ADJ
- || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
- if (lastOomAdj != mi.oomAdj) {
- lastOomAdj = mi.oomAdj;
- if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
- tag.append(" / ");
- }
- if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- if (firstLine) {
- stack.append(":");
- firstLine = false;
- }
- stack.append("\n\t at ");
- } else {
- stack.append("$");
- }
- } else {
- tag.append(" ");
- stack.append("$");
- }
- if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
- appendMemBucket(tag, mi.pss, mi.name, false);
- }
- appendMemBucket(stack, mi.pss, mi.name, true);
- if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
- && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
- stack.append("(");
- for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
- if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
- stack.append(DUMP_MEM_OOM_LABEL[k]);
- stack.append(":");
- stack.append(DUMP_MEM_OOM_ADJ[k]);
- }
- }
- stack.append(")");
- }
- }
-
- appendMemInfo(fullNativeBuilder, mi);
- if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
- // The short form only has native processes that are >= 512K.
- if (mi.pss >= 512) {
- appendMemInfo(shortNativeBuilder, mi);
- } else {
- extraNativeRam += mi.pss;
- extraNativeMemtrack += mi.memtrack;
- }
- } else {
- // Short form has all other details, but if we have collected RAM
- // from smaller native processes let's dump a summary of that.
- if (extraNativeRam > 0) {
- appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
- -1, extraNativeRam, extraNativeMemtrack, "(Other native)");
- shortNativeBuilder.append('\n');
- extraNativeRam = 0;
- }
- appendMemInfo(fullJavaBuilder, mi);
- }
- }
-
- fullJavaBuilder.append(" ");
- ProcessList.appendRamKb(fullJavaBuilder, totalPss);
- fullJavaBuilder.append(": TOTAL");
- if (totalMemtrack > 0) {
- fullJavaBuilder.append(" (");
- fullJavaBuilder.append(stringifyKBSize(totalMemtrack));
- fullJavaBuilder.append(" memtrack)");
- } else {
- }
- fullJavaBuilder.append("\n");
-
- MemInfoReader memInfo = new MemInfoReader();
- memInfo.readMemInfo();
- final long[] infos = memInfo.getRawInfo();
-
- StringBuilder memInfoBuilder = new StringBuilder(1024);
- Debug.getMemInfo(infos);
- memInfoBuilder.append(" MemInfo: ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SLAB])).append(" slab, ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SHMEM])).append(" shmem, ");
- memInfoBuilder.append(stringifyKBSize(
- infos[Debug.MEMINFO_VM_ALLOC_USED])).append(" vm alloc, ");
- memInfoBuilder.append(stringifyKBSize(
- infos[Debug.MEMINFO_PAGE_TABLES])).append(" page tables ");
- memInfoBuilder.append(stringifyKBSize(
- infos[Debug.MEMINFO_KERNEL_STACK])).append(" kernel stack\n");
- memInfoBuilder.append(" ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_BUFFERS])).append(" buffers, ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_CACHED])).append(" cached, ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_MAPPED])).append(" mapped, ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_FREE])).append(" free\n");
- if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
- memInfoBuilder.append(" ZRAM: ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_ZRAM_TOTAL]));
- memInfoBuilder.append(" RAM, ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SWAP_TOTAL]));
- memInfoBuilder.append(" swap total, ");
- memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SWAP_FREE]));
- memInfoBuilder.append(" swap free\n");
- }
- final long[] ksm = getKsmInfo();
- if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
- || ksm[KSM_VOLATILE] != 0) {
- memInfoBuilder.append(" KSM: ");
- memInfoBuilder.append(stringifyKBSize(ksm[KSM_SHARING]));
- memInfoBuilder.append(" saved from shared ");
- memInfoBuilder.append(stringifyKBSize(ksm[KSM_SHARED]));
- memInfoBuilder.append("\n ");
- memInfoBuilder.append(stringifyKBSize(ksm[KSM_UNSHARED]));
- memInfoBuilder.append(" unshared; ");
- memInfoBuilder.append(stringifyKBSize(ksm[KSM_VOLATILE]));
- memInfoBuilder.append(" volatile\n");
- }
- memInfoBuilder.append(" Free RAM: ");
- memInfoBuilder.append(stringifyKBSize(cachedPss + memInfo.getCachedSizeKb()
- + memInfo.getFreeSizeKb()));
- memInfoBuilder.append("\n");
- long kernelUsed = memInfo.getKernelUsedSizeKb();
- final long ionHeap = Debug.getIonHeapsSizeKb();
- final long ionPool = Debug.getIonPoolsSizeKb();
- if (ionHeap >= 0 && ionPool >= 0) {
- final long ionMapped = Debug.getIonMappedSizeKb();
- final long ionUnmapped = ionHeap - ionMapped;
- memInfoBuilder.append(" ION: ");
- memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
- memInfoBuilder.append("\n");
- // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
- // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
- kernelUsed += ionHeap;
- }
- final long gpuUsage = Debug.getGpuTotalUsageKb();
- if (gpuUsage >= 0) {
- memInfoBuilder.append(" GPU: ");
- memInfoBuilder.append(stringifyKBSize(gpuUsage));
- memInfoBuilder.append("\n");
- }
- memInfoBuilder.append(" Used RAM: ");
- memInfoBuilder.append(stringifyKBSize(
- totalPss - cachedPss + kernelUsed));
- memInfoBuilder.append("\n");
- memInfoBuilder.append(" Lost RAM: ");
- memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb()
- - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- - kernelUsed - memInfo.getZramTotalSizeKb()));
- memInfoBuilder.append("\n");
- Slog.i(TAG, "Low on memory:");
- Slog.i(TAG, shortNativeBuilder.toString());
- Slog.i(TAG, fullJavaBuilder.toString());
- Slog.i(TAG, memInfoBuilder.toString());
-
- StringBuilder dropBuilder = new StringBuilder(1024);
- /*
- StringWriter oomSw = new StringWriter();
- PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
- StringWriter catSw = new StringWriter();
- PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
- String[] emptyArgs = new String[] { };
- dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw);
- oomPw.flush();
- String oomString = oomSw.toString();
- */
- dropBuilder.append("Low on memory:");
- dropBuilder.append(stack);
- dropBuilder.append('\n');
- dropBuilder.append(fullNativeBuilder);
- dropBuilder.append(fullJavaBuilder);
- dropBuilder.append('\n');
- dropBuilder.append(memInfoBuilder);
- dropBuilder.append('\n');
- /*
- dropBuilder.append(oomString);
- dropBuilder.append('\n');
- */
- StringWriter catSw = new StringWriter();
- synchronized (ActivityManagerService.this) {
- PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
- String[] emptyArgs = new String[] { };
- catPw.println();
- dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null, -1);
- catPw.println();
- mServices.newServiceDumperLocked(null, catPw, emptyArgs, 0,
- false, null).dumpLocked();
- catPw.println();
- mAtmInternal.dump(DUMP_ACTIVITIES_CMD, null, catPw, emptyArgs, 0, false, false, null);
- catPw.flush();
- }
- dropBuilder.append(catSw.toString());
- FrameworkStatsLog.write(FrameworkStatsLog.LOW_MEM_REPORTED);
- addErrorToDropBox("lowmem", null, "system_server", null,
- null, null, tag.toString(), dropBuilder.toString(), null, null);
- //Slog.i(TAG, "Sent to dropbox:");
- //Slog.i(TAG, dropBuilder.toString());
- synchronized (ActivityManagerService.this) {
- long now = SystemClock.uptimeMillis();
- if (mLastMemUsageReportTime < now) {
- mLastMemUsageReportTime = now;
- }
- }
- }
-
/**
* Searches array of arguments for the specified string
* @param args array of argument strings
@@ -12185,7 +11150,6 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessList.remove(app.pid);
}
- mProcessesToGc.remove(app);
mAppProfiler.onCleanupApplicationRecordLocked(app);
// Dismiss any open dialogs.
@@ -12285,15 +11249,7 @@ public class ActivityManagerService extends IActivityManager.Stub
});
}
- for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
- ProcessChangeItem item = mPendingProcessChanges.get(i);
- if (app.pid > 0 && item.pid == app.pid) {
- mPendingProcessChanges.remove(i);
- mAvailProcessChanges.add(item);
- }
- }
- mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, app.pid, app.info.uid,
- null).sendToTarget();
+ mProcessList.scheduleDispatchProcessDiedLocked(app.pid, app.info.uid);
// If this is a precede instance of another process instance
allowRestart = true;
@@ -12626,7 +11582,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
- mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
+ mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res, false);
}
}
@@ -12938,9 +11894,9 @@ public class ActivityManagerService extends IActivityManager.Stub
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
- if (callerApp.info.uid != SYSTEM_UID &&
- !callerApp.pkgList.containsKey(callerPackage) &&
- !"android".equals(callerPackage)) {
+ if (callerApp.info.uid != SYSTEM_UID
+ && !callerApp.getPkgList().containsKey(callerPackage)
+ && !"android".equals(callerPackage)) {
throw new SecurityException("Given caller package " + callerPackage
+ " is not running in process " + callerApp);
}
@@ -14509,8 +13465,11 @@ public class ActivityManagerService extends IActivityManager.Stub
return;
}
final long origId = Binder.clearCallingIdentity();
- addInstrumentationResultsLocked(app, results);
- Binder.restoreCallingIdentity(origId);
+ try {
+ addInstrumentationResultsLocked(app, results);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
}
@@ -14542,7 +13501,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppOpsService.setMode(AppOpsManager.OP_NO_ISOLATED_STORAGE, app.uid,
app.info.packageName, AppOpsManager.MODE_ERRORED);
mAppOpsService.setAppOpsServiceDelegate(null);
- getPermissionManagerInternalLocked().stopShellPermissionIdentityDelegation();
+ getPermissionManagerInternal().stopShellPermissionIdentityDelegation();
mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
instr.mUiAutomationConnection).sendToTarget();
}
@@ -14813,28 +13772,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
- * Ask a given process to GC right now.
- */
- final void performAppGcLocked(ProcessRecord app) {
- try {
- app.lastRequestedGc = SystemClock.uptimeMillis();
- if (app.thread != null) {
- if (app.reportLowMemory) {
- app.reportLowMemory = false;
- app.thread.scheduleLowMemory();
- } else {
- app.thread.processInBackground();
- }
- }
- } catch (Exception e) {
- // whatever.
- }
- }
-
- /**
* Returns true if things are idle enough to perform GCs.
*/
- private final boolean canGcNowLocked() {
+ final boolean canGcNowLocked() {
for (BroadcastQueue q : mBroadcastQueues) {
if (!q.mParallelBroadcasts.isEmpty() || !q.mDispatcher.isEmpty()) {
return false;
@@ -14843,107 +13783,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return mAtmInternal.canGcNow();
}
- /**
- * Perform GCs on all processes that are waiting for it, but only
- * if things are idle.
- */
- final void performAppGcsLocked() {
- final int N = mProcessesToGc.size();
- if (N <= 0) {
- return;
- }
- if (canGcNowLocked()) {
- while (mProcessesToGc.size() > 0) {
- ProcessRecord proc = mProcessesToGc.remove(0);
- if (proc.getCurRawAdj() > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
- if ((proc.lastRequestedGc+mConstants.GC_MIN_INTERVAL)
- <= SystemClock.uptimeMillis()) {
- // To avoid spamming the system, we will GC processes one
- // at a time, waiting a few seconds between each.
- performAppGcLocked(proc);
- scheduleAppGcsLocked();
- return;
- } else {
- // It hasn't been long enough since we last GCed this
- // process... put it in the list to wait for its time.
- addProcessToGcListLocked(proc);
- break;
- }
- }
- }
-
- scheduleAppGcsLocked();
- }
- }
-
- /**
- * If all looks good, perform GCs on all processes waiting for them.
- */
- final void performAppGcsIfAppropriateLocked() {
- if (canGcNowLocked()) {
- performAppGcsLocked();
- return;
- }
- // Still not idle, wait some more.
- scheduleAppGcsLocked();
- }
-
- /**
- * Schedule the execution of all pending app GCs.
- */
- final void scheduleAppGcsLocked() {
- mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
-
- if (mProcessesToGc.size() > 0) {
- // Schedule a GC for the time to the next process.
- ProcessRecord proc = mProcessesToGc.get(0);
- Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
-
- long when = proc.lastRequestedGc + mConstants.GC_MIN_INTERVAL;
- long now = SystemClock.uptimeMillis();
- if (when < (now+mConstants.GC_TIMEOUT)) {
- when = now + mConstants.GC_TIMEOUT;
- }
- mHandler.sendMessageAtTime(msg, when);
- }
- }
-
- /**
- * Add a process to the array of processes waiting to be GCed. Keeps the
- * list in sorted order by the last GC time. The process can't already be
- * on the list.
- */
- final void addProcessToGcListLocked(ProcessRecord proc) {
- boolean added = false;
- for (int i=mProcessesToGc.size()-1; i>=0; i--) {
- if (mProcessesToGc.get(i).lastRequestedGc <
- proc.lastRequestedGc) {
- added = true;
- mProcessesToGc.add(i+1, proc);
- break;
- }
- }
- if (!added) {
- mProcessesToGc.add(0, proc);
- }
- }
-
- /**
- * Set up to ask a process to GC itself. This will either do it
- * immediately, or put it on the list of processes to gc the next
- * time things are idle.
- */
- final void scheduleAppGcLocked(ProcessRecord app) {
- long now = SystemClock.uptimeMillis();
- if ((app.lastRequestedGc+mConstants.GC_MIN_INTERVAL) > now) {
- return;
- }
- if (!mProcessesToGc.contains(app)) {
- addProcessToGcListLocked(app);
- scheduleAppGcsLocked();
- }
- }
-
private void checkExcessivePowerUsage() {
updateCpuStatsNow();
@@ -14972,22 +13811,25 @@ public class ActivityManagerService extends IActivityManager.Stub
} else {
cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4;
}
- if (app.lastCpuTime > 0) {
- final long cputimeUsed = app.curCpuTime - app.lastCpuTime;
- if (checkExcessivePowerUsageLocked(uptimeSince, doCpuKills, cputimeUsed,
- app.processName, app.toShortString(), cpuLimit, app)) {
- app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
- + " dur=" + checkDur + " limit=" + cpuLimit,
- ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
- ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
- true);
- synchronized (mProcessStats.mLock) {
- app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList);
+ synchronized (mAppProfiler.mProfilerLock) {
+ final ProcessProfileRecord profile = app.mProfile;
+ final long curCpuTime = profile.mCurCpuTime.get();
+ final long lastCpuTime = profile.mLastCpuTime.get();
+ if (lastCpuTime > 0) {
+ final long cputimeUsed = curCpuTime - lastCpuTime;
+ if (checkExcessivePowerUsageLocked(uptimeSince, doCpuKills, cputimeUsed,
+ app.processName, app.toShortString(), cpuLimit, app)) {
+ app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
+ + " dur=" + checkDur + " limit=" + cpuLimit,
+ ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
+ true);
+ profile.reportExcessiveCpu();
}
}
+ profile.mLastCpuTime.set(curCpuTime);
}
- app.lastCpuTime = app.curCpuTime;
// Also check the phantom processes if there is any
final long chkDur = checkDur;
@@ -15036,15 +13878,14 @@ public class ActivityManagerService extends IActivityManager.Stub
if (((cputimeUsed * 100) / uptimeSince) >= cpuLimit) {
mBatteryStatsService.reportExcessiveCpu(app.info.uid, app.processName,
uptimeSince, cputimeUsed);
- for (int ipkg = app.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = app.pkgList.valueAt(ipkg);
+ app.getPkgList().forEachPackageProcessStats(holder -> {
FrameworkStatsLog.write(
FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED,
app.info.uid,
processName,
holder.state.getPackage(),
holder.appVersion);
- }
+ });
return true;
}
}
@@ -15056,7 +13897,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid
return false;
}
- return getPackageManagerInternalLocked().isPackageEphemeral(
+ return getPackageManagerInternal().isPackageEphemeral(
UserHandle.getUserId(uid), packages[0]);
}
@@ -15106,12 +13947,9 @@ public class ActivityManagerService extends IActivityManager.Stub
final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
synchronized (mProcessStats.mLock) {
- if (proc.thread != null && proc.baseProcessTracker != null) {
- final int procState = proc.getReportedProcState();
- if (procState != PROCESS_STATE_NONEXISTENT) {
- proc.baseProcessTracker.setState(
- procState, memFactor, now, proc.pkgList.mPkgList);
- }
+ if (proc.thread != null) {
+ proc.mProfile.setProcessTrackerState(
+ proc.getReportedProcState(), memFactor, now);
}
}
}
@@ -15148,7 +13986,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
proc.setReportedForegroundServiceTypes(fgServiceTypes);
- ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.pid, proc.info.uid);
+ ProcessChangeItem item = mProcessList.enqueueProcessChangeItemLocked(
+ proc.pid, proc.info.uid);
item.changes |= ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
item.foregroundServiceTypes = fgServiceTypes;
}
@@ -15159,7 +13998,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
// the logic there and in mBatteryStatsService to make them aware of multiple resumed activities
- ProcessRecord getTopAppLocked() {
+ ProcessRecord getTopApp() {
final WindowProcessController wpc = mAtmInternal != null ? mAtmInternal.getTopApp() : null;
final ProcessRecord r = wpc != null ? (ProcessRecord) wpc.mOwner : null;
String pkg;
@@ -15172,25 +14011,27 @@ public class ActivityManagerService extends IActivityManager.Stub
uid = -1;
}
// Has the UID or resumed package name changed?
- if (uid != mCurResumedUid || (pkg != mCurResumedPackage
- && (pkg == null || !pkg.equals(mCurResumedPackage)))) {
+ synchronized (mCurResumedAppLock) {
+ if (uid != mCurResumedUid || (pkg != mCurResumedPackage
+ && (pkg == null || !pkg.equals(mCurResumedPackage)))) {
- final long identity = Binder.clearCallingIdentity();
- try {
- if (mCurResumedPackage != null) {
- mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_FINISH,
- mCurResumedPackage, mCurResumedUid);
- }
- mCurResumedPackage = pkg;
- mCurResumedUid = uid;
- if (mCurResumedPackage != null) {
- mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_START,
- mCurResumedPackage, mCurResumedUid);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (mCurResumedPackage != null) {
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_FINISH,
+ mCurResumedPackage, mCurResumedUid);
+ }
+ mCurResumedPackage = pkg;
+ mCurResumedUid = uid;
+ if (mCurResumedPackage != null) {
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_START,
+ mCurResumedPackage, mCurResumedUid);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ }
}
return r;
}
@@ -15279,47 +14120,49 @@ public class ActivityManagerService extends IActivityManager.Stub
userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
userId, true, ALLOW_FULL_ONLY, "makePackageIdle", null);
final long callingId = Binder.clearCallingIdentity();
- synchronized(this) {
+ try {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ int pkgUid = -1;
try {
- IPackageManager pm = AppGlobals.getPackageManager();
- int pkgUid = -1;
+ pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES
+ | MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM);
+ } catch (RemoteException e) {
+ }
+ if (pkgUid == -1) {
+ throw new IllegalArgumentException("Unknown package name " + packageName);
+ }
+
+ synchronized (this) {
try {
- pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES
- | MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM);
- } catch (RemoteException e) {
- }
- if (pkgUid == -1) {
- throw new IllegalArgumentException("Unknown package name " + packageName);
- }
-
- if (mLocalPowerManager != null) {
- mLocalPowerManager.startUidChanges();
- }
- final int appId = UserHandle.getAppId(pkgUid);
- final int N = mProcessList.mActiveUids.size();
- for (int i = N - 1; i >= 0; i--) {
- final UidRecord uidRec = mProcessList.mActiveUids.valueAt(i);
- final long bgTime = uidRec.lastBackgroundTime;
- if (bgTime > 0 && !uidRec.idle) {
- if (UserHandle.getAppId(uidRec.uid) == appId) {
- if (userId == UserHandle.USER_ALL ||
- userId == UserHandle.getUserId(uidRec.uid)) {
- EventLogTags.writeAmUidIdle(uidRec.uid);
- uidRec.idle = true;
- uidRec.setIdle = true;
- Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
- + " from package " + packageName + " user " + userId);
- doStopUidLocked(uidRec.uid, uidRec);
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.startUidChanges();
+ }
+ final int appId = UserHandle.getAppId(pkgUid);
+ for (int i = mProcessList.mActiveUids.size() - 1; i >= 0; i--) {
+ final UidRecord uidRec = mProcessList.mActiveUids.valueAt(i);
+ final long bgTime = uidRec.lastBackgroundTime;
+ if (bgTime > 0 && !uidRec.idle) {
+ if (UserHandle.getAppId(uidRec.uid) == appId) {
+ if (userId == UserHandle.USER_ALL
+ || userId == UserHandle.getUserId(uidRec.uid)) {
+ EventLogTags.writeAmUidIdle(uidRec.uid);
+ uidRec.idle = true;
+ uidRec.setIdle = true;
+ Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
+ + " from package " + packageName + " user " + userId);
+ doStopUidLocked(uidRec.uid, uidRec);
+ }
}
}
}
+ } finally {
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.finishUidChanges();
+ }
}
- } finally {
- if (mLocalPowerManager != null) {
- mLocalPowerManager.finishUidChanges();
- }
- Binder.restoreCallingIdentity(callingId);
}
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@@ -15373,24 +14216,24 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
- * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
+ * Allowlists {@code targetUid} to temporarily bypass Power Save mode.
*/
@GuardedBy("this")
- void tempWhitelistForPendingIntentLocked(int callerPid, int callerUid, int targetUid,
+ void tempAllowlistForPendingIntentLocked(int callerPid, int callerUid, int targetUid,
long duration, int type, String tag) {
if (DEBUG_WHITELISTS) {
- Slog.d(TAG, "tempWhitelistForPendingIntentLocked(" + callerPid + ", " + callerUid + ", "
+ Slog.d(TAG, "tempAllowlistForPendingIntentLocked(" + callerPid + ", " + callerUid + ", "
+ targetUid + ", " + duration + ", " + type + ")");
}
synchronized (mPidsSelfLocked) {
final ProcessRecord pr = mPidsSelfLocked.get(callerPid);
if (pr == null) {
- Slog.w(TAG, "tempWhitelistForPendingIntentLocked() no ProcessRecord for pid "
+ Slog.w(TAG, "tempAllowlistForPendingIntentLocked() no ProcessRecord for pid "
+ callerPid);
return;
}
- if (!pr.whitelistManager) {
+ if (!pr.mAllowlistManager) {
if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid)
!= PackageManager.PERMISSION_GRANTED
&& checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callerPid, callerUid)
@@ -15398,7 +14241,7 @@ public class ActivityManagerService extends IActivityManager.Stub
&& checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callerPid,
callerUid) != PackageManager.PERMISSION_GRANTED) {
if (DEBUG_WHITELISTS) {
- Slog.d(TAG, "tempWhitelistForPendingIntentLocked() for target " + targetUid
+ Slog.d(TAG, "tempAllowlistForPendingIntentLocked() for target " + targetUid
+ ": pid " + callerPid + " is not allowed");
}
return;
@@ -15406,35 +14249,35 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- tempWhitelistUidLocked(targetUid, duration, tag, type);
+ tempAllowlistUidLocked(targetUid, duration, tag, type);
}
/**
- * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
+ * Allowlists {@code targetUid} to temporarily bypass Power Save mode.
*/
@GuardedBy("this")
- void tempWhitelistUidLocked(int targetUid, long duration, String tag, int type) {
- mPendingTempWhitelist.put(targetUid,
- new PendingTempWhitelist(targetUid, duration, tag, type));
- setUidTempWhitelistStateLocked(targetUid, true);
- mUiHandler.obtainMessage(PUSH_TEMP_WHITELIST_UI_MSG).sendToTarget();
+ void tempAllowlistUidLocked(int targetUid, long duration, String tag, int type) {
+ mPendingTempAllowlist.put(targetUid,
+ new PendingTempAllowlist(targetUid, duration, tag, type));
+ setUidTempAllowlistStateLocked(targetUid, true);
+ mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget();
if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
mFgsStartTempAllowList.add(targetUid, duration);
}
}
- void pushTempWhitelist() {
+ void pushTempAllowlist() {
final int N;
- final PendingTempWhitelist[] list;
+ final PendingTempAllowlist[] list;
// First copy out the pending changes... we need to leave them in the map for now,
// in case someone needs to check what is coming up while we don't have the lock held.
synchronized(this) {
- N = mPendingTempWhitelist.size();
- list = new PendingTempWhitelist[N];
+ N = mPendingTempAllowlist.size();
+ list = new PendingTempAllowlist[N];
for (int i = 0; i < N; i++) {
- list[i] = mPendingTempWhitelist.valueAt(i);
+ list[i] = mPendingTempAllowlist.valueAt(i);
}
}
@@ -15443,7 +14286,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// device idle policy anyway at this phase.
if (mLocalDeviceIdleController != null) {
for (int i = 0; i < N; i++) {
- PendingTempWhitelist ptw = list[i];
+ PendingTempAllowlist ptw = list[i];
mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid,
ptw.duration, ptw.type, true, ptw.tag);
}
@@ -15452,23 +14295,23 @@ public class ActivityManagerService extends IActivityManager.Stub
// And now we can safely remove them from the map.
synchronized(this) {
for (int i = 0; i < N; i++) {
- PendingTempWhitelist ptw = list[i];
- int index = mPendingTempWhitelist.indexOfKey(ptw.targetUid);
- if (index >= 0 && mPendingTempWhitelist.valueAt(index) == ptw) {
- mPendingTempWhitelist.removeAt(index);
+ PendingTempAllowlist ptw = list[i];
+ int index = mPendingTempAllowlist.indexOfKey(ptw.targetUid);
+ if (index >= 0 && mPendingTempAllowlist.valueAt(index) == ptw) {
+ mPendingTempAllowlist.removeAt(index);
}
}
}
}
@GuardedBy("this")
- final void setAppIdTempWhitelistStateLocked(int uid, boolean onWhitelist) {
- mOomAdjuster.setAppIdTempWhitelistStateLocked(uid, onWhitelist);
+ final void setAppIdTempAllowlistStateLocked(int uid, boolean onAllowlist) {
+ mOomAdjuster.setAppIdTempAllowlistStateLocked(uid, onAllowlist);
}
@GuardedBy("this")
- final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
- mOomAdjuster.setUidTempWhitelistStateLocked(uid, onWhitelist);
+ final void setUidTempAllowlistStateLocked(int uid, boolean onAllowlist) {
+ mOomAdjuster.setUidTempAllowlistStateLocked(uid, onAllowlist);
}
private void trimApplications(boolean forceFullOomAdj, String oomAdjReason) {
@@ -15530,13 +14373,13 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException("Only SIGNAL_USR1 is allowed");
}
- synchronized (this) {
- if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
- }
+ if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
+ }
+ synchronized (this) {
for (int i = mProcessList.mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mProcessList.mLruProcesses.get(i);
if (r.thread != null && r.isPersistent()) {
@@ -15548,20 +14391,20 @@ public class ActivityManagerService extends IActivityManager.Stub
public boolean profileControl(String process, int userId, boolean start,
ProfilerInfo profilerInfo, int profileType) throws RemoteException {
- synchronized (this) {
- // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
- // its own permission.
- if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SET_ACTIVITY_WATCHER);
- }
+ // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+ // its own permission.
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
- if (start && (profilerInfo == null || profilerInfo.profileFd == null)) {
- throw new IllegalArgumentException("null profile info or fd");
- }
+ if (start && (profilerInfo == null || profilerInfo.profileFd == null)) {
+ throw new IllegalArgumentException("null profile info or fd");
+ }
- ProcessRecord proc = null;
+ ProcessRecord proc = null;
+ synchronized (this) {
if (process != null) {
proc = findProcessLocked(process, userId, "profileControl");
}
@@ -15569,8 +14412,9 @@ public class ActivityManagerService extends IActivityManager.Stub
if (start && (proc == null || proc.thread == null)) {
throw new IllegalArgumentException("Unknown process: " + process);
}
-
- return mAppProfiler.profileControlLocked(proc, start, profilerInfo, profileType);
+ }
+ synchronized (mAppProfiler.mProfilerLock) {
+ return mAppProfiler.profileControlLPf(proc, start, profilerInfo, profileType);
}
}
@@ -15612,19 +14456,19 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) {
try {
- synchronized (this) {
- // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
- // its own permission (same as profileControl).
- if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SET_ACTIVITY_WATCHER);
- }
+ // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+ // its own permission (same as profileControl).
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
- if (fd == null) {
- throw new IllegalArgumentException("null fd");
- }
+ if (fd == null) {
+ throw new IllegalArgumentException("null fd");
+ }
+ synchronized (this) {
ProcessRecord proc = findProcessLocked(process, userId, "dumpHeap");
if (proc == null || proc.thread == null) {
throw new IllegalArgumentException("Unknown process: " + process);
@@ -15683,7 +14527,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
processName = proc.processName;
uid = proc.uid;
- if (reportPackage != null && !proc.pkgList.containsKey(reportPackage)) {
+ if (reportPackage != null && !proc.getPkgList().containsKey(reportPackage)) {
throw new SecurityException("Package " + reportPackage + " is not running in "
+ proc);
}
@@ -15871,16 +14715,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
public boolean startBinderTracking() throws RemoteException {
+ // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own
+ // permission (same as profileControl).
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
synchronized (this) {
mBinderTransactionTrackingEnabled = true;
- // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own
- // permission (same as profileControl).
- if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SET_ACTIVITY_WATCHER);
- }
-
for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
ProcessRecord process = mProcessList.mLruProcesses.get(i);
if (!processSanityChecksLocked(process)) {
@@ -15898,19 +14742,19 @@ public class ActivityManagerService extends IActivityManager.Stub
public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException {
try {
- synchronized (this) {
- mBinderTransactionTrackingEnabled = false;
- // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own
- // permission (same as profileControl).
- if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SET_ACTIVITY_WATCHER);
- }
+ // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own
+ // permission (same as profileControl).
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+ synchronized (this) {
if (fd == null) {
throw new IllegalArgumentException("null fd");
}
+ mBinderTransactionTrackingEnabled = false;
PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd.getFileDescriptor()));
pw.println("Binder transaction traces for all processes.\n");
@@ -16059,8 +14903,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
synchronized (ActivityManagerService.this) {
- mDeviceIdleWhitelist = allAppids;
- mDeviceIdleExceptIdleWhitelist = exceptIdleAppids;
+ mDeviceIdleAllowlist = allAppids;
+ mDeviceIdleExceptIdleAllowlist = exceptIdleAppids;
}
}
@@ -16068,13 +14912,13 @@ public class ActivityManagerService extends IActivityManager.Stub
public void updateDeviceIdleTempWhitelist(int[] appids, int changingUid, boolean adding,
long durationMs, @BroadcastOptions.TempAllowListType int type) {
synchronized (ActivityManagerService.this) {
- mDeviceIdleTempWhitelist = appids;
+ mDeviceIdleTempAllowlist = appids;
if (adding) {
if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
mFgsStartTempAllowList.add(changingUid, durationMs);
}
}
- setAppIdTempWhitelistStateLocked(changingUid, adding);
+ setAppIdTempAllowlistStateLocked(changingUid, adding);
}
}
@@ -16301,26 +15145,20 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void updateCpuStats() {
- synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.updateCpuStatsLocked();
- }
+ ActivityManagerService.this.updateCpuStats();
}
@Override
public void updateBatteryStats(ComponentName activity, int uid, int userId,
boolean resumed) {
- synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.updateBatteryStats(activity, uid, userId, resumed);
- }
+ ActivityManagerService.this.updateBatteryStats(activity, uid, userId, resumed);
}
@Override
public void updateActivityUsageStats(ComponentName activity, int userId, int event,
IBinder appToken, ComponentName taskRoot) {
- synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.updateActivityUsageStats(activity, userId, event,
- appToken, taskRoot);
- }
+ ActivityManagerService.this.updateActivityUsageStats(activity, userId, event,
+ appToken, taskRoot);
}
@Override
@@ -16397,16 +15235,14 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void scheduleAppGcs() {
- synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.scheduleAppGcsLocked();
+ synchronized (mAppProfiler.mProfilerLock) {
+ mAppProfiler.scheduleAppGcsLPf();
}
}
@Override
public int getTaskIdForActivity(IBinder token, boolean onlyRoot) {
- synchronized (ActivityManagerService.this) {
- return ActivityManagerService.this.getTaskForActivity(token, onlyRoot);
- }
+ return ActivityManagerService.this.getTaskForActivity(token, onlyRoot);
}
@Override
@@ -16446,7 +15282,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
long duration, int type, String tag) {
synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.tempWhitelistForPendingIntentLocked(
+ ActivityManagerService.this.tempAllowlistForPendingIntentLocked(
callerPid, callerUid, targetUid, duration, type, tag);
}
}
@@ -16527,7 +15363,8 @@ public class ActivityManagerService extends IActivityManager.Stub
(ActivityServiceConnectionsHolder) connectionHolder;
synchronized (ActivityManagerService.this) {
holder.forEachConnection(cr -> mServices.removeConnectionLocked(
- (ConnectionRecord) cr, null /* skipApp */, holder /* skipAct */));
+ (ConnectionRecord) cr, null /* skipApp */, holder /* skipAct */,
+ false /* enqueueOomAdj */));
}
}
@@ -16872,14 +15709,11 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException("Requires permission " + FILTER_EVENTS);
}
ProcessRecord proc;
- long timeoutMillis;
- synchronized (this) {
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(pid);
- }
- timeoutMillis = proc != null ? proc.getInputDispatchingTimeoutMillis() :
- DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
}
+ final long timeoutMillis = proc != null ? proc.getInputDispatchingTimeoutMillis() :
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
return 0;
@@ -17093,10 +15927,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* resources and overlaid values are available immediately.
*/
public void updateSystemUiContext() {
- PackageManagerInternal packageManagerInternal;
- synchronized (this) {
- packageManagerInternal = getPackageManagerInternalLocked();
- }
+ final PackageManagerInternal packageManagerInternal = getPackageManagerInternal();
ApplicationInfo ai = packageManagerInternal.getApplicationInfo("android",
GET_SHARED_LIBRARY_FILES, Binder.getCallingUid(), UserHandle.USER_SYSTEM);
@@ -17279,10 +16110,8 @@ public class ActivityManagerService extends IActivityManager.Stub
* like persisting database etc.
*/
public void prepareForPossibleShutdown() {
- synchronized (this) {
- if (mUsageStatsService != null) {
- mUsageStatsService.prepareForPossibleShutdown();
- }
+ if (mUsageStatsService != null) {
+ mUsageStatsService.prepareForPossibleShutdown();
}
}
@@ -17371,7 +16200,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final String packageName = instr.mTargetInfo.packageName;
final List<String> permissionNames = permissions != null ?
Arrays.asList(permissions) : null;
- getPermissionManagerInternalLocked().startShellPermissionIdentityDelegation(
+ getPermissionManagerInternal().startShellPermissionIdentityDelegation(
delegateUid, packageName, permissionNames);
return;
}
@@ -17386,7 +16215,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
synchronized (ActivityManagerService.this) {
mAppOpsService.setAppOpsServiceDelegate(null);
- getPermissionManagerInternalLocked().stopShellPermissionIdentityDelegation();
+ getPermissionManagerInternal().stopShellPermissionIdentityDelegation();
}
}
@@ -17525,7 +16354,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public void setActivityLocusContext(ComponentName activity, LocusId locusId, IBinder appToken) {
final int callingUid = Binder.getCallingUid();
final int userId = UserHandle.getCallingUserId();
- if (getPackageManagerInternalLocked().getPackageUid(activity.getPackageName(),
+ if (getPackageManagerInternal().getPackageUid(activity.getPackageName(),
/*flags=*/ 0, userId) != callingUid) {
throw new SecurityException("Calling uid " + callingUid + " cannot set locusId"
+ "for package " + activity.getPackageName());
@@ -17555,9 +16384,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void resetAppErrors() {
enforceCallingPermission(Manifest.permission.RESET_APP_ERRORS, "resetAppErrors");
- synchronized (this) {
- mAppErrors.resetStateLocked();
- }
+ mAppErrors.resetState();
}
@Override
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index d76e2d712ad9..779d37858ce2 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -71,8 +71,8 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
BidiFormatter bidi = BidiFormatter.getInstance();
CharSequence name;
- if ((mProc.pkgList.size() == 1) &&
- (name = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
+ if ((mProc.getPkgList().size() == 1)
+ && (name = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
setTitle(res.getString(
data.repeating ? com.android.internal.R.string.aerr_application_repeated
: com.android.internal.R.string.aerr_application,
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 35f46896ac94..7be54c29a218 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -52,6 +52,7 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -74,27 +75,32 @@ class AppErrors {
private final Context mContext;
private final PackageWatchdog mPackageWatchdog;
+ @GuardedBy("mBadProcessLock")
private ArraySet<String> mAppsNotReportingCrashes;
/**
* The last time that various processes have crashed since they were last explicitly started.
*/
+ @GuardedBy("mBadProcessLock")
private final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<>();
/**
* The last time that various processes have crashed (not reset even when explicitly started).
*/
+ @GuardedBy("mBadProcessLock")
private final ProcessMap<Long> mProcessCrashTimesPersistent = new ProcessMap<>();
/**
* The last time that various processes have crashed and shown an error dialog.
*/
+ @GuardedBy("mBadProcessLock")
private final ProcessMap<Long> mProcessCrashShowDialogTimes = new ProcessMap<>();
/**
* A pairing between how many times various processes have crashed since a given time.
* Entry and exit conditions for this map are similar to mProcessCrashTimes.
*/
+ @GuardedBy("mBadProcessLock")
private final ProcessMap<Pair<Long, Integer>> mProcessCrashCounts = new ProcessMap<>();
/**
@@ -116,6 +122,16 @@ class AppErrors {
* lock operations from the simple lookup cases.
*/
private volatile ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
+
+ /**
+ * Dedicated lock for {@link #mAppsNotReportingCrashes}, {@link #mProcessCrashTimes},
+ * {@link #mProcessCrashTimesPersistent}, {@link #mProcessCrashShowDialogTimes},
+ * {@link #mProcessCrashCounts} and {@link #mBadProcesses}.
+ *
+ * <p>The naming convention of the function with this lock should be "-LBp"</b>
+ *
+ * @See mBadProcesses
+ */
private final Object mBadProcessLock = new Object();
AppErrors(Context context, ActivityManagerService service, PackageWatchdog watchdog) {
@@ -126,147 +142,152 @@ class AppErrors {
}
/** Resets the current state but leaves the constructor-provided fields unchanged. */
- public void resetStateLocked() {
+ public void resetState() {
Slog.i(TAG, "Resetting AppErrors");
- mAppsNotReportingCrashes.clear();
- mProcessCrashTimes.clear();
- mProcessCrashTimesPersistent.clear();
- mProcessCrashShowDialogTimes.clear();
- mProcessCrashCounts.clear();
synchronized (mBadProcessLock) {
+ mAppsNotReportingCrashes.clear();
+ mProcessCrashTimes.clear();
+ mProcessCrashTimesPersistent.clear();
+ mProcessCrashShowDialogTimes.clear();
+ mProcessCrashCounts.clear();
mBadProcesses = new ProcessMap<>();
}
}
void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) {
- final ProcessMap<BadProcessInfo> badProcesses = mBadProcesses;
- if (mProcessCrashTimes.getMap().isEmpty() && badProcesses.getMap().isEmpty()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- final long now = SystemClock.uptimeMillis();
- proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
-
- if (!mProcessCrashTimes.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
- final int procCount = pmap.size();
- for (int ip = 0; ip < procCount; ip++) {
- final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<Long> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ synchronized (mBadProcessLock) {
+ final ProcessMap<BadProcessInfo> badProcesses = mBadProcesses;
+ if (mProcessCrashTimes.getMap().isEmpty() && badProcesses.getMap().isEmpty()) {
+ return;
+ }
- proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null
- && (r == null || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ final long token = proto.start(fieldId);
+ final long now = SystemClock.uptimeMillis();
+ proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
+
+ if (!mProcessCrashTimes.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+ final int procCount = pmap.size();
+ for (int ip = 0; ip < procCount; ip++) {
+ final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Long> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+
+ proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null
+ && (r == null || !r.getPkgList().containsKey(dumpPackage))) {
+ continue;
+ }
+ final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
+ uids.valueAt(i));
+ proto.end(etoken);
}
- final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
- uids.valueAt(i));
- proto.end(etoken);
+ proto.end(ctoken);
}
- proto.end(ctoken);
- }
-
- }
- if (!badProcesses.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = badProcesses.getMap();
- final int processCount = pmap.size();
- for (int ip = 0; ip < processCount; ip++) {
- final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ }
- proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ if (!badProcesses.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = badProcesses.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+
+ proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null && (r == null
+ || !r.getPkgList().containsKey(dumpPackage))) {
+ continue;
+ }
+ final BadProcessInfo info = uids.valueAt(i);
+ final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
+ proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
+ proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
+ proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
+ proto.end(etoken);
}
- final BadProcessInfo info = uids.valueAt(i);
- final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
- proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
- proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
- proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
- proto.end(etoken);
+ proto.end(btoken);
}
- proto.end(btoken);
}
- }
- proto.end(token);
+ proto.end(token);
+ }
}
boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
final long now = SystemClock.uptimeMillis();
- if (!mProcessCrashTimes.getMap().isEmpty()) {
- boolean printed = false;
- final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
- final int processCount = pmap.size();
- for (int ip = 0; ip < processCount; ip++) {
- final String pname = pmap.keyAt(ip);
- final SparseArray<Long> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
- continue;
- }
- if (!printed) {
- if (needSep) pw.println();
- needSep = true;
- pw.println(" Time since processes crashed:");
- printed = true;
+ synchronized (mBadProcessLock) {
+ if (!mProcessCrashTimes.getMap().isEmpty()) {
+ boolean printed = false;
+ final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Long> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null && (r == null
+ || !r.getPkgList().containsKey(dumpPackage))) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" Time since processes crashed:");
+ printed = true;
+ }
+ pw.print(" Process "); pw.print(pname);
+ pw.print(" uid "); pw.print(puid);
+ pw.print(": last crashed ");
+ TimeUtils.formatDuration(now - uids.valueAt(i), pw);
+ pw.println(" ago");
}
- pw.print(" Process "); pw.print(pname);
- pw.print(" uid "); pw.print(puid);
- pw.print(": last crashed ");
- TimeUtils.formatDuration(now-uids.valueAt(i), pw);
- pw.println(" ago");
}
}
- }
- if (!mProcessCrashCounts.getMap().isEmpty()) {
- boolean printed = false;
- final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pmap =
- mProcessCrashCounts.getMap();
- final int processCount = pmap.size();
- for (int ip = 0; ip < processCount; ip++) {
- final String pname = pmap.keyAt(ip);
- final SparseArray<Pair<Long, Integer>> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
- continue;
- }
- if (!printed) {
- if (needSep) pw.println();
- needSep = true;
- pw.println(" First time processes crashed and counts:");
- printed = true;
+ if (!mProcessCrashCounts.getMap().isEmpty()) {
+ boolean printed = false;
+ final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pmap =
+ mProcessCrashCounts.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Pair<Long, Integer>> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null
+ && (r == null || !r.getPkgList().containsKey(dumpPackage))) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" First time processes crashed and counts:");
+ printed = true;
+ }
+ pw.print(" Process "); pw.print(pname);
+ pw.print(" uid "); pw.print(puid);
+ pw.print(": first crashed ");
+ TimeUtils.formatDuration(now - uids.valueAt(i).first, pw);
+ pw.print(" ago; crashes since then: "); pw.println(uids.valueAt(i).second);
}
- pw.print(" Process "); pw.print(pname);
- pw.print(" uid "); pw.print(puid);
- pw.print(": first crashed ");
- TimeUtils.formatDuration(now - uids.valueAt(i).first, pw);
- pw.print(" ago; crashes since then: "); pw.println(uids.valueAt(i).second);
}
}
}
@@ -284,7 +305,7 @@ class AppErrors {
final int puid = uids.keyAt(i);
final ProcessRecord r = mService.getProcessNames().get(pname, puid);
if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
+ || !r.getPkgList().containsKey(dumpPackage))) {
continue;
}
if (!printed) {
@@ -349,33 +370,38 @@ class AppErrors {
}
}
- void resetProcessCrashTimeLocked(final String processName, final int uid) {
- mProcessCrashTimes.remove(processName, uid);
- mProcessCrashCounts.remove(processName, uid);
+ void resetProcessCrashTime(final String processName, final int uid) {
+ synchronized (mBadProcessLock) {
+ mProcessCrashTimes.remove(processName, uid);
+ mProcessCrashCounts.remove(processName, uid);
+ }
}
- void resetProcessCrashTimeLocked(boolean resetEntireUser, int appId, int userId) {
- final ArrayMap<String, SparseArray<Long>> pTimeMap = mProcessCrashTimes.getMap();
- for (int ip = pTimeMap.size() - 1; ip >= 0; ip--) {
- SparseArray<Long> ba = pTimeMap.valueAt(ip);
- resetProcessCrashMapLocked(ba, resetEntireUser, appId, userId);
- if (ba.size() == 0) {
- pTimeMap.removeAt(ip);
+ void resetProcessCrashTime(boolean resetEntireUser, int appId, int userId) {
+ synchronized (mBadProcessLock) {
+ final ArrayMap<String, SparseArray<Long>> pTimeMap = mProcessCrashTimes.getMap();
+ for (int ip = pTimeMap.size() - 1; ip >= 0; ip--) {
+ SparseArray<Long> ba = pTimeMap.valueAt(ip);
+ resetProcessCrashMapLBp(ba, resetEntireUser, appId, userId);
+ if (ba.size() == 0) {
+ pTimeMap.removeAt(ip);
+ }
}
- }
- final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pCountMap =
- mProcessCrashCounts.getMap();
- for (int ip = pCountMap.size() - 1; ip >= 0; ip--) {
- SparseArray<Pair<Long, Integer>> ba = pCountMap.valueAt(ip);
- resetProcessCrashMapLocked(ba, resetEntireUser, appId, userId);
- if (ba.size() == 0) {
- pCountMap.removeAt(ip);
+ final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pCountMap =
+ mProcessCrashCounts.getMap();
+ for (int ip = pCountMap.size() - 1; ip >= 0; ip--) {
+ SparseArray<Pair<Long, Integer>> ba = pCountMap.valueAt(ip);
+ resetProcessCrashMapLBp(ba, resetEntireUser, appId, userId);
+ if (ba.size() == 0) {
+ pCountMap.removeAt(ip);
+ }
}
}
}
- private void resetProcessCrashMapLocked(SparseArray<?> ba, boolean resetEntireUser,
+ @GuardedBy("mBadProcessLock")
+ private void resetProcessCrashMapLBp(SparseArray<?> ba, boolean resetEntireUser,
int appId, int userId) {
for (int i = ba.size() - 1; i >= 0; i--) {
boolean remove = false;
@@ -399,12 +425,14 @@ class AppErrors {
}
}
- void loadAppsNotReportingCrashesFromConfigLocked(String appsNotReportingCrashesConfig) {
+ void loadAppsNotReportingCrashesFromConfig(String appsNotReportingCrashesConfig) {
if (appsNotReportingCrashesConfig != null) {
final String[] split = appsNotReportingCrashesConfig.split(",");
if (split.length > 0) {
- mAppsNotReportingCrashes = new ArraySet<>();
- Collections.addAll(mAppsNotReportingCrashes, split);
+ synchronized (mBadProcessLock) {
+ mAppsNotReportingCrashes = new ArraySet<>();
+ Collections.addAll(mAppsNotReportingCrashes, split);
+ }
}
}
}
@@ -465,7 +493,7 @@ class AppErrors {
proc = p;
break;
}
- if (p.pkgList.containsKey(packageName)
+ if (p.getPkgList().containsKey(packageName)
&& (userId < 0 || p.userId == userId)) {
proc = p;
}
@@ -516,7 +544,7 @@ class AppErrors {
}
}
- void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
+ private void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
int callingPid, int callingUid) {
long timeMillis = System.currentTimeMillis();
String shortMsg = crashInfo.exceptionClassName;
@@ -599,44 +627,50 @@ class AppErrors {
if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
res = AppErrorDialog.FORCE_QUIT;
}
- synchronized (mService) {
- if (res == AppErrorDialog.MUTE) {
- stopReportingCrashesLocked(r);
+ if (res == AppErrorDialog.MUTE) {
+ synchronized (mBadProcessLock) {
+ stopReportingCrashesLBp(r);
}
- if (res == AppErrorDialog.RESTART) {
+ }
+ if (res == AppErrorDialog.RESTART) {
+ synchronized (mService) {
mService.mProcessList.removeProcessLocked(r, false, true,
ApplicationExitInfo.REASON_CRASH, "crash");
- if (taskId != INVALID_TASK_ID) {
- try {
- mService.startActivityFromRecents(taskId,
- ActivityOptions.makeBasic().toBundle());
- } catch (IllegalArgumentException e) {
- // Hmm...that didn't work. Task should either be in recents or associated
- // with a stack.
- Slog.e(TAG, "Could not restart taskId=" + taskId, e);
- }
- }
}
- if (res == AppErrorDialog.FORCE_QUIT) {
- final long orig = Binder.clearCallingIdentity();
+ if (taskId != INVALID_TASK_ID) {
try {
- // Kill it with fire!
- mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
- if (!r.isPersistent()) {
+ mService.startActivityFromRecents(taskId,
+ ActivityOptions.makeBasic().toBundle());
+ } catch (IllegalArgumentException e) {
+ // Hmm...that didn't work. Task should either be in recents or associated
+ // with a stack.
+ Slog.e(TAG, "Could not restart taskId=" + taskId, e);
+ }
+ }
+ }
+ if (res == AppErrorDialog.FORCE_QUIT) {
+ final long orig = Binder.clearCallingIdentity();
+ try {
+ // Kill it with fire!
+ mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
+ if (!r.isPersistent()) {
+ synchronized (mService) {
mService.mProcessList.removeProcessLocked(r, false, false,
ApplicationExitInfo.REASON_CRASH, "crash");
- mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
}
- } finally {
- Binder.restoreCallingIdentity(orig);
+ mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
}
+ } finally {
+ Binder.restoreCallingIdentity(orig);
}
- if (res == AppErrorDialog.APP_INFO) {
- appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
- appErrorIntent.setData(Uri.parse("package:" + r.info.packageName));
- appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
- if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
+ }
+ if (res == AppErrorDialog.APP_INFO) {
+ appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ appErrorIntent.setData(Uri.parse("package:" + r.info.packageName));
+ appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+ if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
+ synchronized (mService) {
appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
}
}
@@ -769,7 +803,7 @@ class AppErrors {
return report;
}
- boolean handleAppCrashLocked(ProcessRecord app, String reason,
+ private boolean handleAppCrashLocked(ProcessRecord app, String reason,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
final long now = SystemClock.uptimeMillis();
final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
@@ -783,109 +817,116 @@ class AppErrors {
Long crashTimePersistent;
boolean tryAgain = false;
- if (!app.isolated) {
- crashTime = mProcessCrashTimes.get(app.processName, app.uid);
- crashTimePersistent = mProcessCrashTimesPersistent.get(app.processName, app.uid);
- } else {
- crashTime = crashTimePersistent = null;
- }
-
- // Bump up the crash count of any services currently running in the proc.
- for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
- // Any services running in the application need to be placed
- // back in the pending list.
- ServiceRecord sr = app.getRunningServiceAt(i);
- // If the service was restarted a while ago, then reset crash count, else increment it.
- if (now > sr.restartTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
- sr.crashCount = 1;
+ synchronized (mBadProcessLock) {
+ if (!app.isolated) {
+ crashTime = mProcessCrashTimes.get(app.processName, app.uid);
+ crashTimePersistent = mProcessCrashTimesPersistent.get(app.processName, app.uid);
} else {
- sr.crashCount++;
+ crashTime = crashTimePersistent = null;
}
- // Allow restarting for started or bound foreground services that are crashing.
- // This includes wallpapers.
- if (sr.crashCount < mService.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY
- && (sr.isForeground || procIsBoundForeground)) {
- tryAgain = true;
+
+ // Bump up the crash count of any services currently running in the proc.
+ for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
+ // Any services running in the application need to be placed
+ // back in the pending list.
+ ServiceRecord sr = app.getRunningServiceAt(i);
+ // If the service was restarted a while ago, then reset crash count,
+ // else increment it.
+ if (now > sr.restartTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
+ sr.crashCount = 1;
+ } else {
+ sr.crashCount++;
+ }
+ // Allow restarting for started or bound foreground services that are crashing.
+ // This includes wallpapers.
+ if (sr.crashCount < mService.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY
+ && (sr.isForeground || procIsBoundForeground)) {
+ tryAgain = true;
+ }
}
- }
- final boolean quickCrash = crashTime != null
- && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
- if (quickCrash || isProcOverCrashLimit(app, now)) {
- // The process either crashed again very quickly or has been crashing periodically in
- // the last few hours. If it was a bound foreground service, let's try to restart again
- // in a while, otherwise the process loses!
- Slog.w(TAG, "Process " + app.processName + " has crashed too many times, killing!"
- + " Reason: " + (quickCrash ? "crashed quickly" : "over process crash limit"));
- EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
- app.userId, app.processName, app.uid);
- mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
- if (!app.isPersistent()) {
- // We don't want to start this process again until the user
- // explicitly does so... but for persistent process, we really
- // need to keep it running. If a persistent process is actually
- // repeatedly crashing, then badness for everyone.
- EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
- app.processName);
- if (!app.isolated) {
- // XXX We don't have a way to mark isolated processes
- // as bad, since they don't have a persistent identity.
- markBadProcess(app.processName, app.uid,
- new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
- mProcessCrashTimes.remove(app.processName, app.uid);
- mProcessCrashCounts.remove(app.processName, app.uid);
+ final boolean quickCrash = crashTime != null
+ && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
+ if (quickCrash || isProcOverCrashLimitLBp(app, now)) {
+ // The process either crashed again very quickly or has been crashing periodically
+ // in the last few hours. If it was a bound foreground service, let's try to
+ // restart again in a while, otherwise the process loses!
+ Slog.w(TAG, "Process " + app.processName + " has crashed too many times, killing!"
+ + " Reason: "
+ + (quickCrash ? "crashed quickly" : "over process crash limit"));
+ EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
+ app.userId, app.processName, app.uid);
+ mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
+ if (!app.isPersistent()) {
+ // We don't want to start this process again until the user
+ // explicitly does so... but for persistent process, we really
+ // need to keep it running. If a persistent process is actually
+ // repeatedly crashing, then badness for everyone.
+ EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
+ app.processName);
+ if (!app.isolated) {
+ // XXX We don't have a way to mark isolated processes
+ // as bad, since they don't have a persistent identity.
+ markBadProcess(app.processName, app.uid,
+ new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ mProcessCrashTimes.remove(app.processName, app.uid);
+ mProcessCrashCounts.remove(app.processName, app.uid);
+ }
+ app.bad = true;
+ app.removed = true;
+ // Don't let services in this process be restarted and potentially
+ // annoy the user repeatedly. Unless it is persistent, since those
+ // processes run critical code.
+ mService.mProcessList.removeProcessLocked(app, false, tryAgain,
+ ApplicationExitInfo.REASON_CRASH, "crash");
+ mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
+ if (!showBackground) {
+ return false;
+ }
}
- app.bad = true;
- app.removed = true;
- // Don't let services in this process be restarted and potentially
- // annoy the user repeatedly. Unless it is persistent, since those
- // processes run critical code.
- mService.mProcessList.removeProcessLocked(app, false, tryAgain,
- ApplicationExitInfo.REASON_CRASH, "crash");
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
- if (!showBackground) {
- return false;
+ } else {
+ final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
+ app.getWindowProcessController(), reason);
+ if (data != null) {
+ data.taskId = affectedTaskId;
+ }
+ if (data != null && crashTimePersistent != null
+ && now < crashTimePersistent
+ + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
+ data.repeating = true;
}
}
- mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
- } else {
- final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
- app.getWindowProcessController(), reason);
- if (data != null) {
- data.taskId = affectedTaskId;
- }
- if (data != null && crashTimePersistent != null
- && now < crashTimePersistent + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
- data.repeating = true;
- }
- }
- if (data != null && tryAgain) {
- data.isRestartableForService = true;
- }
+ if (data != null && tryAgain) {
+ data.isRestartableForService = true;
+ }
- // If the crashing process is what we consider to be the "home process" and it has been
- // replaced by a third-party app, clear the package preferred activities from packages
- // with a home activity running in the process to prevent a repeatedly crashing app
- // from blocking the user to manually clear the list.
- final WindowProcessController proc = app.getWindowProcessController();
- if (proc.isHomeProcess() && proc.hasActivities() && (app.info.flags & FLAG_SYSTEM) == 0) {
- proc.clearPackagePreferredForHomeActivities();
- }
+ // If the crashing process is what we consider to be the "home process" and it has been
+ // replaced by a third-party app, clear the package preferred activities from packages
+ // with a home activity running in the process to prevent a repeatedly crashing app
+ // from blocking the user to manually clear the list.
+ final WindowProcessController proc = app.getWindowProcessController();
+ if (proc.isHomeProcess() && proc.hasActivities()
+ && (app.info.flags & FLAG_SYSTEM) == 0) {
+ proc.clearPackagePreferredForHomeActivities();
+ }
- if (!app.isolated) {
- // XXX Can't keep track of crash times for isolated processes,
- // because they don't have a persistent identity.
- mProcessCrashTimes.put(app.processName, app.uid, now);
- mProcessCrashTimesPersistent.put(app.processName, app.uid, now);
- updateProcessCrashCount(app.processName, app.uid, now);
+ if (!app.isolated) {
+ // XXX Can't keep track of crash times for isolated processes,
+ // because they don't have a persistent identity.
+ mProcessCrashTimes.put(app.processName, app.uid, now);
+ mProcessCrashTimesPersistent.put(app.processName, app.uid, now);
+ updateProcessCrashCountLBp(app.processName, app.uid, now);
+ }
}
if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
return true;
}
- private void updateProcessCrashCount(String processName, int uid, long now) {
+ @GuardedBy("mBadProcessLock")
+ private void updateProcessCrashCountLBp(String processName, int uid, long now) {
Pair<Long, Integer> count = mProcessCrashCounts.get(processName, uid);
if (count == null || (count.first + PROCESS_CRASH_COUNT_RESET_INTERVAL) < now) {
count = new Pair<>(now, 1);
@@ -895,7 +936,8 @@ class AppErrors {
mProcessCrashCounts.put(processName, uid, count);
}
- private boolean isProcOverCrashLimit(ProcessRecord app, long now) {
+ @GuardedBy("mBadProcessLock")
+ private boolean isProcOverCrashLimitLBp(ProcessRecord app, long now) {
final Pair<Long, Integer> crashCount = mProcessCrashCounts.get(app.processName, app.uid);
return !app.isolated && crashCount != null
&& now < (crashCount.first + PROCESS_CRASH_COUNT_RESET_INTERVAL)
@@ -938,41 +980,44 @@ class AppErrors {
return;
}
Long crashShowErrorTime = null;
- if (!proc.isolated) {
- crashShowErrorTime = mProcessCrashShowDialogTimes.get(proc.processName,
- proc.uid);
- }
- final boolean showFirstCrash = Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.SHOW_FIRST_CRASH_DIALOG, 0) != 0;
- final boolean showFirstCrashDevOption = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
- 0,
- mService.mUserController.getCurrentUserId()) != 0;
- final boolean crashSilenced = mAppsNotReportingCrashes != null &&
- mAppsNotReportingCrashes.contains(proc.info.packageName);
- final long now = SystemClock.uptimeMillis();
- final boolean shouldThottle = crashShowErrorTime != null
- && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
- if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
- && !crashSilenced && !shouldThottle
- && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
- proc.getDialogController().showCrashDialogs(data);
+ synchronized (mBadProcessLock) {
if (!proc.isolated) {
- mProcessCrashShowDialogTimes.put(proc.processName, proc.uid, now);
+ crashShowErrorTime = mProcessCrashShowDialogTimes.get(proc.processName,
+ proc.uid);
}
- } else {
- // The device is asleep, so just pretend that the user
- // saw a crash dialog and hit "force quit".
- if (res != null) {
- res.set(AppErrorDialog.CANT_SHOW);
+ final boolean showFirstCrash = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.SHOW_FIRST_CRASH_DIALOG, 0) != 0;
+ final boolean showFirstCrashDevOption = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+ 0,
+ mService.mUserController.getCurrentUserId()) != 0;
+ final boolean crashSilenced = mAppsNotReportingCrashes != null
+ && mAppsNotReportingCrashes.contains(proc.info.packageName);
+ final long now = SystemClock.uptimeMillis();
+ final boolean shouldThottle = crashShowErrorTime != null
+ && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
+ if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
+ && !crashSilenced && !shouldThottle
+ && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
+ proc.getDialogController().showCrashDialogs(data);
+ if (!proc.isolated) {
+ mProcessCrashShowDialogTimes.put(proc.processName, proc.uid, now);
+ }
+ } else {
+ // The device is asleep, so just pretend that the user
+ // saw a crash dialog and hit "force quit".
+ if (res != null) {
+ res.set(AppErrorDialog.CANT_SHOW);
+ }
}
}
}
}
- private void stopReportingCrashesLocked(ProcessRecord proc) {
+ @GuardedBy("mBadProcessLock")
+ private void stopReportingCrashesLBp(ProcessRecord proc) {
if (mAppsNotReportingCrashes == null) {
mAppsNotReportingCrashes = new ArraySet<>();
}
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 20cad185d8d0..48aa8be1e2d5 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -79,6 +79,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -159,8 +160,7 @@ public final class AppExitInfoTracker {
* persistent storage.
*/
@VisibleForTesting
- @GuardedBy("mLock")
- boolean mAppExitInfoLoaded = false;
+ AtomicBoolean mAppExitInfoLoaded = new AtomicBoolean();
/**
* Temporary list being used to filter/sort intermediate results in {@link #getExitInfo}.
@@ -273,51 +273,45 @@ public final class AppExitInfoTracker {
return;
}
- synchronized (mLock) {
- if (!mAppExitInfoLoaded) {
- return;
- }
- mKillHandler.obtainMessage(KillHandler.MSG_PROC_DIED, obtainRawRecordLocked(app))
- .sendToTarget();
+ if (!mAppExitInfoLoaded.get()) {
+ return;
}
+ mKillHandler.obtainMessage(KillHandler.MSG_PROC_DIED, obtainRawRecord(app))
+ .sendToTarget();
}
void scheduleNoteAppKill(final ProcessRecord app, final @Reason int reason,
final @SubReason int subReason, final String msg) {
- synchronized (mLock) {
- if (!mAppExitInfoLoaded) {
- return;
- }
- if (app == null || app.info == null) {
- return;
- }
-
- ApplicationExitInfo raw = obtainRawRecordLocked(app);
- raw.setReason(reason);
- raw.setSubReason(subReason);
- raw.setDescription(msg);
- mKillHandler.obtainMessage(KillHandler.MSG_APP_KILL, raw).sendToTarget();
+ if (!mAppExitInfoLoaded.get()) {
+ return;
+ }
+ if (app == null || app.info == null) {
+ return;
}
+
+ ApplicationExitInfo raw = obtainRawRecord(app);
+ raw.setReason(reason);
+ raw.setSubReason(subReason);
+ raw.setDescription(msg);
+ mKillHandler.obtainMessage(KillHandler.MSG_APP_KILL, raw).sendToTarget();
}
void scheduleNoteAppKill(final int pid, final int uid, final @Reason int reason,
final @SubReason int subReason, final String msg) {
- synchronized (mLock) {
- if (!mAppExitInfoLoaded) {
- return;
- }
- ProcessRecord app;
- synchronized (mService.mPidsSelfLocked) {
- app = mService.mPidsSelfLocked.get(pid);
- }
- if (app == null) {
- if (DEBUG_PROCESSES) {
- Slog.w(TAG, "Skipping saving the kill reason for pid " + pid
- + "(uid=" + uid + ") since its process record is not found");
- }
- } else {
- scheduleNoteAppKill(app, reason, subReason, msg);
+ if (!mAppExitInfoLoaded.get()) {
+ return;
+ }
+ ProcessRecord app;
+ synchronized (mService.mPidsSelfLocked) {
+ app = mService.mPidsSelfLocked.get(pid);
+ }
+ if (app == null) {
+ if (DEBUG_PROCESSES) {
+ Slog.w(TAG, "Skipping saving the kill reason for pid " + pid
+ + "(uid=" + uid + ") since its process record is not found");
}
+ } else {
+ scheduleNoteAppKill(app, reason, subReason, msg);
}
}
@@ -414,7 +408,7 @@ public final class AppExitInfoTracker {
@GuardedBy("mLock")
private ApplicationExitInfo addExitInfoLocked(ApplicationExitInfo raw) {
- if (!mAppExitInfoLoaded) {
+ if (!mAppExitInfoLoaded.get()) {
Slog.w(TAG, "Skipping saving the exit info due to ongoing loading from storage");
return null;
}
@@ -627,9 +621,7 @@ public final class AppExitInfoTracker {
@VisibleForTesting
void loadExistingProcessExitInfo() {
if (!mProcExitInfoFile.canRead()) {
- synchronized (mLock) {
- mAppExitInfoLoaded = true;
- }
+ mAppExitInfoLoaded.set(true);
return;
}
@@ -665,7 +657,7 @@ public final class AppExitInfoTracker {
}
synchronized (mLock) {
pruneAnrTracesIfNecessaryLocked();
- mAppExitInfoLoaded = true;
+ mAppExitInfoLoaded.set(true);
}
}
@@ -834,7 +826,7 @@ public final class AppExitInfoTracker {
container.addExitInfoLocked(info);
}
- @GuardedBy("mLocked")
+ @GuardedBy("mLock")
private void forEachPackageLocked(
BiFunction<String, SparseArray<AppExitInfoContainer>, Integer> callback) {
if (callback != null) {
@@ -859,7 +851,7 @@ public final class AppExitInfoTracker {
}
}
- @GuardedBy("mLocked")
+ @GuardedBy("mLock")
private void removePackageLocked(String packageName, int uid, boolean removeUid, int userId) {
if (removeUid) {
mActiveAppStateSummary.remove(uid);
@@ -896,7 +888,7 @@ public final class AppExitInfoTracker {
}
}
- @GuardedBy("mLocked")
+ @GuardedBy("mLock")
private void removeByUserIdLocked(final int userId) {
if (userId == UserHandle.USER_ALL) {
mData.getMap().clear();
@@ -922,35 +914,36 @@ public final class AppExitInfoTracker {
}
@VisibleForTesting
- @GuardedBy("mLock")
- ApplicationExitInfo obtainRawRecordLocked(ProcessRecord app) {
+ ApplicationExitInfo obtainRawRecord(ProcessRecord app) {
ApplicationExitInfo info = mRawRecordsPool.acquire();
if (info == null) {
info = new ApplicationExitInfo();
}
- final int definingUid = app.hostingRecord != null ? app.hostingRecord.getDefiningUid() : 0;
- info.setPid(app.pid);
- info.setRealUid(app.uid);
- info.setPackageUid(app.info.uid);
- info.setDefiningUid(definingUid > 0 ? definingUid : app.info.uid);
- info.setProcessName(app.processName);
- info.setConnectionGroup(app.connectionGroup);
- info.setPackageName(app.info.packageName);
- info.setPackageList(app.getPackageList());
- info.setReason(ApplicationExitInfo.REASON_UNKNOWN);
- info.setStatus(0);
- info.setImportance(procStateToImportance(app.setProcState));
- info.setPss(app.lastPss);
- info.setRss(app.mLastRss);
- info.setTimestamp(System.currentTimeMillis());
+ synchronized (mService) {
+ final int definingUid = app.hostingRecord != null
+ ? app.hostingRecord.getDefiningUid() : 0;
+ info.setPid(app.pid);
+ info.setRealUid(app.uid);
+ info.setPackageUid(app.info.uid);
+ info.setDefiningUid(definingUid > 0 ? definingUid : app.info.uid);
+ info.setProcessName(app.processName);
+ info.setConnectionGroup(app.connectionGroup);
+ info.setPackageName(app.info.packageName);
+ info.setPackageList(app.getPackageList());
+ info.setReason(ApplicationExitInfo.REASON_UNKNOWN);
+ info.setStatus(0);
+ info.setImportance(procStateToImportance(app.setProcState));
+ info.setPss(app.mProfile.getLastPss());
+ info.setRss(app.mProfile.getLastRss());
+ info.setTimestamp(System.currentTimeMillis());
+ }
return info;
}
@VisibleForTesting
- @GuardedBy("mLock")
- void recycleRawRecordLocked(ApplicationExitInfo info) {
+ void recycleRawRecord(ApplicationExitInfo info) {
info.setProcessName(null);
info.setDescription(null);
info.setPackageList(null);
@@ -1549,16 +1542,16 @@ public final class AppExitInfoTracker {
ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj;
synchronized (mLock) {
handleNoteProcessDiedLocked(raw);
- recycleRawRecordLocked(raw);
}
+ recycleRawRecord(raw);
}
break;
case MSG_APP_KILL: {
ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj;
synchronized (mLock) {
handleNoteAppKillLocked(raw);
- recycleRawRecordLocked(raw);
}
+ recycleRawRecord(raw);
}
break;
default:
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index dac5325f239d..96e6f6ea4476 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -63,8 +63,8 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
? data.aInfo.loadLabel(context.getPackageManager())
: null;
CharSequence name2 = null;
- if ((mProc.pkgList.size() == 1) &&
- (name2=context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
+ if ((mProc.getPkgList().size() == 1)
+ && (name2 = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
if (name1 != null) {
resid = com.android.internal.R.string.anr_activity_application;
} else {
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index cace260c3c26..3df058c8ed82 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -29,8 +29,22 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.DUMP_MEM_OOM_ADJ;
+import static com.android.server.am.ActivityManagerService.DUMP_MEM_OOM_LABEL;
+import static com.android.server.am.ActivityManagerService.GC_BACKGROUND_PROCESSES_MSG;
+import static com.android.server.am.ActivityManagerService.KSM_SHARED;
+import static com.android.server.am.ActivityManagerService.KSM_SHARING;
+import static com.android.server.am.ActivityManagerService.KSM_UNSHARED;
+import static com.android.server.am.ActivityManagerService.KSM_VOLATILE;
+import static com.android.server.am.ActivityManagerService.REPORT_MEM_USAGE_MSG;
+import static com.android.server.am.ActivityManagerService.appendBasicMemEntry;
+import static com.android.server.am.ActivityManagerService.appendMemBucket;
+import static com.android.server.am.ActivityManagerService.appendMemInfo;
+import static com.android.server.am.ActivityManagerService.getKsmInfo;
+import static com.android.server.am.ActivityManagerService.stringifyKBSize;
import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.wm.ActivityTaskManagerService.DUMP_ACTIVITIES_CMD;
import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
@@ -75,16 +89,19 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.MemInfoReader;
import com.android.server.am.LowMemDetector.MemFactor;
-import com.android.server.am.ProcessList.ProcStateMemTracker;
import com.android.server.utils.PriorityDump;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -162,8 +179,8 @@ public class AppProfiler {
/**
* Processes we want to collect PSS data from.
*/
- @GuardedBy("mService")
- private final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
+ @GuardedBy("mProfilerLock")
+ private final ArrayList<ProcessProfileRecord> mPendingPssProfiles = new ArrayList<>();
/**
* Depth of overlapping activity-start PSS deferral notes
@@ -173,14 +190,14 @@ public class AppProfiler {
/**
* Last time we requested PSS data of all processes.
*/
- @GuardedBy("mService")
+ @GuardedBy("mProfilerLock")
private long mLastFullPssTime = SystemClock.uptimeMillis();
/**
* If set, the next time we collect PSS data we should do a full collection
* with data from native processes and the kernel.
*/
- @GuardedBy("mService")
+ @GuardedBy("mProfilerLock")
private boolean mFullPssPending = false;
/**
@@ -188,8 +205,7 @@ public class AppProfiler {
* much more rapidly to try to collect better data when the tests are rapidly
* running through apps.
*/
- @GuardedBy("mService")
- private boolean mTestPssMode = false;
+ private volatile boolean mTestPssMode = false;
@GuardedBy("mService")
private final LowMemDetector mLowMemDetector;
@@ -233,21 +249,53 @@ public class AppProfiler {
private long mLowRamStartTime = 0;
/**
+ * Last time we report a memory usage.
+ */
+ @GuardedBy("mService")
+ private long mLastMemUsageReportTime = 0;
+
+ /**
+ * List of processes that should gc as soon as things are idle.
+ */
+ @GuardedBy("mProfilerLock")
+ private final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<>();
+
+ /**
* Stores a map of process name -> agent string. When a process is started and mAgentAppMap
* is not null, this map is checked and the mapped agent installed during bind-time. Note:
* A non-null agent in mProfileInfo overrides this.
*/
+ @GuardedBy("mProfilerLock")
private @Nullable Map<String, String> mAppAgentMap = null;
+ @GuardedBy("mProfilerLock")
private int mProfileType = 0;
+
+ @GuardedBy("mProfilerLock")
+ private final ProfileData mProfileData = new ProfileData();
+
+ @GuardedBy("mProfilerLock")
private final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
+
+ @GuardedBy("mProfilerLock")
private String mMemWatchDumpProcName;
+
+ @GuardedBy("mProfilerLock")
private Uri mMemWatchDumpUri;
+
+ @GuardedBy("mProfilerLock")
private int mMemWatchDumpPid;
+
+ @GuardedBy("mProfilerLock")
private int mMemWatchDumpUid;
+
+ @GuardedBy("mProfilerLock")
private boolean mMemWatchIsUserInitiated;
+ @GuardedBy("mService")
boolean mHasHomeProcess;
+
+ @GuardedBy("mService")
boolean mHasPreviousProcess;
/**
@@ -263,8 +311,7 @@ public class AppProfiler {
private final AtomicBoolean mProcessCpuMutexFree = new AtomicBoolean(true);
private final CountDownLatch mProcessCpuInitLatch = new CountDownLatch(1);
- private long mLastWriteTime = 0;
- private final ProfileData mProfileData = new ProfileData();
+ private volatile long mLastWriteTime = 0;
/**
* Runtime CPU use collection thread. This object's lock is used to
@@ -276,6 +323,15 @@ public class AppProfiler {
private final Handler mBgHandler;
/**
+ * The lock to guard some of the profiling data here and {@link ProcessProfileRecord}.
+ *
+ * <p>
+ * The function suffix with this lock would be "-LPf" (Locked with Profiler lock).
+ * </p>
+ */
+ final Object mProfilerLock = new Object();
+
+ /**
* Observe DeviceConfig changes to the PSS calculation interval
*/
private final DeviceConfig.OnPropertiesChangedListener mPssDelayConfigListener =
@@ -359,7 +415,7 @@ public class AppProfiler {
private void collectPssInBackground() {
long start = SystemClock.uptimeMillis();
MemInfoReader memInfo = null;
- synchronized (mService) {
+ synchronized (mProfilerLock) {
if (mFullPssPending) {
mFullPssPending = false;
memInfo = new MemInfoReader();
@@ -404,65 +460,67 @@ public class AppProfiler {
int num = 0;
long[] tmp = new long[3];
do {
- ProcessRecord proc;
+ ProcessProfileRecord profile;
int procState;
int statType;
int pid = -1;
long lastPssTime;
- synchronized (mService) {
- if (mPendingPssProcesses.size() <= 0) {
+ synchronized (mProfilerLock) {
+ if (mPendingPssProfiles.size() <= 0) {
if (mTestPssMode || DEBUG_PSS) {
Slog.d(TAG_PSS,
"Collected pss of " + num + " processes in "
+ (SystemClock.uptimeMillis() - start) + "ms");
}
- mPendingPssProcesses.clear();
+ mPendingPssProfiles.clear();
return;
}
- proc = mPendingPssProcesses.remove(0);
- procState = proc.pssProcState;
- statType = proc.pssStatType;
- lastPssTime = proc.lastPssTime;
+ profile = mPendingPssProfiles.remove(0);
+ procState = profile.getPssProcState();
+ statType = profile.getPssStatType();
+ lastPssTime = profile.getLastPssTime();
long now = SystemClock.uptimeMillis();
- if (proc.thread != null && procState == proc.setProcState
+ if (profile.getThread() != null && procState == profile.getSetProcState()
&& (lastPssTime + ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE) < now) {
- pid = proc.pid;
+ pid = profile.getPid();
} else {
- abortNextPssTime(proc.procStateMemTracker);
+ profile.abortNextPssTime();
if (DEBUG_PSS) {
Slog.d(TAG_PSS, "Skipped pss collection of " + pid
+ ": still need "
+ (lastPssTime + ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE - now)
+ "ms until safe");
}
- proc = null;
+ profile = null;
pid = 0;
}
}
- if (proc != null) {
+ if (profile != null) {
long startTime = SystemClock.currentThreadTimeMillis();
// skip background PSS calculation of apps that are capturing
// camera imagery
- final boolean usingCamera = mService.isCameraActiveForUid(proc.uid);
+ final boolean usingCamera = mService.isCameraActiveForUid(profile.mApp.uid);
long pss = usingCamera ? 0 : Debug.getPss(pid, tmp, null);
long endTime = SystemClock.currentThreadTimeMillis();
- synchronized (mService) {
- if (pss != 0 && proc.thread != null && proc.setProcState == procState
- && proc.pid == pid && proc.lastPssTime == lastPssTime) {
+ synchronized (mProfilerLock) {
+ if (pss != 0 && profile.getThread() != null
+ && profile.getSetProcState() == procState
+ && profile.getPid() == pid && profile.getLastPssTime() == lastPssTime) {
num++;
- commitNextPssTime(proc.procStateMemTracker);
- recordPssSampleLocked(proc, procState, pss, tmp[0], tmp[1], tmp[2],
+ profile.commitNextPssTime();
+ recordPssSampleLPf(profile, procState, pss, tmp[0], tmp[1], tmp[2],
statType, endTime - startTime, SystemClock.uptimeMillis());
} else {
- abortNextPssTime(proc.procStateMemTracker);
+ profile.abortNextPssTime();
if (DEBUG_PSS) {
Slog.d(TAG_PSS, "Skipped pss collection of " + pid
- + ": " + (proc.thread == null ? "NO_THREAD " : "")
+ + ": " + (profile.getThread() == null ? "NO_THREAD " : "")
+ (usingCamera ? "CAMERA " : "")
- + (proc.pid != pid ? "PID_CHANGED " : "")
+ + (profile.getPid() != pid ? "PID_CHANGED " : "")
+ " initState=" + procState + " curState="
- + proc.setProcState + " "
- + (proc.lastPssTime != lastPssTime ? "TIME_CHANGED" : ""));
+ + profile.getSetProcState() + " "
+ + (profile.getLastPssTime() != lastPssTime
+ ? "TIME_CHANGED" : ""));
}
}
}
@@ -470,73 +528,61 @@ public class AppProfiler {
} while (true);
}
- private static void commitNextPssTime(ProcStateMemTracker tracker) {
- if (tracker.mPendingMemState >= 0) {
- tracker.mHighestMem[tracker.mPendingMemState] = tracker.mPendingHighestMemState;
- tracker.mScalingFactor[tracker.mPendingMemState] = tracker.mPendingScalingFactor;
- tracker.mTotalHighestMem = tracker.mPendingHighestMemState;
- tracker.mPendingMemState = -1;
- }
- }
-
- private static void abortNextPssTime(ProcStateMemTracker tracker) {
- tracker.mPendingMemState = -1;
- }
-
- @GuardedBy("mService")
- void updateNextPssTimeLocked(int procState, ProcessRecord app, long now, boolean forceUpdate) {
+ @GuardedBy("mProfilerLock")
+ void updateNextPssTimeLPf(int procState, ProcessProfileRecord profile, long now,
+ boolean forceUpdate) {
if (!forceUpdate) {
- if (now <= app.nextPssTime
- && now <= Math.max(app.lastPssTime + ProcessList.PSS_MAX_INTERVAL,
- app.lastStateTime + ProcessList.minTimeFromStateChange(mTestPssMode))) {
+ if (now <= profile.getNextPssTime() && now <= Math.max(profile.getLastPssTime()
+ + ProcessList.PSS_MAX_INTERVAL, profile.getLastStateTime()
+ + ProcessList.minTimeFromStateChange(mTestPssMode))) {
// update is not due, ignore it.
return;
}
- if (!requestPssLocked(app, app.setProcState)) {
+ if (!requestPssLPf(profile, procState)) {
return;
}
}
- app.nextPssTime = ProcessList.computeNextPssTime(procState, app.procStateMemTracker,
- mTestPssMode, mService.mAtmInternal.isSleeping(), now);
+ profile.setNextPssTime(profile.computeNextPssTime(procState,
+ mTestPssMode, mService.mAtmInternal.isSleeping(), now));
}
/**
* Record new PSS sample for a process.
*/
- @GuardedBy("mService")
- private void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss,
+ @GuardedBy("mProfilerLock")
+ private void recordPssSampleLPf(ProcessProfileRecord profile, int procState, long pss, long uss,
long swapPss, long rss, int statType, long pssDuration, long now) {
- EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024,
+ final ProcessRecord proc = profile.mApp;
+ EventLogTags.writeAmPss(
+ profile.getPid(), proc.uid, proc.processName, pss * 1024, uss * 1024,
swapPss * 1024, rss * 1024, statType, procState, pssDuration);
- proc.lastPssTime = now;
- synchronized (mService.mProcessStats.mLock) {
- proc.baseProcessTracker.addPss(
- pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList);
- }
- for (int ipkg = proc.pkgList.mPkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ profile.setLastPssTime(now);
+ profile.addPss(pss, uss, rss, true, statType, pssDuration);
+ proc.getPkgList().forEachPackageProcessStats(holder -> {
FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
proc.info.uid,
holder.state.getName(),
holder.state.getPackage(),
- pss, uss, rss, statType, pssDuration,
+ pss, uss, rss,
+ statType, pssDuration,
holder.appVersion);
- }
+ });
if (DEBUG_PSS) {
Slog.d(TAG_PSS,
- "pss of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
+ "pss of " + proc.toShortString() + ": " + pss
+ + " lastPss=" + profile.getLastPss()
+ " state=" + ProcessList.makeProcStateString(procState));
}
- if (proc.initialIdlePss == 0) {
- proc.initialIdlePss = pss;
+ if (profile.getInitialIdlePss() == 0) {
+ profile.setInitialIdlePss(pss);
}
- proc.lastPss = pss;
- proc.lastSwapPss = swapPss;
+ profile.setLastPss(pss);
+ profile.setLastSwapPss(swapPss);
if (procState >= ActivityManager.PROCESS_STATE_HOME) {
- proc.lastCachedPss = pss;
- proc.lastCachedSwapPss = swapPss;
+ profile.setLastCachedPss(pss);
+ profile.setLastCachedSwapPss(swapPss);
}
- proc.mLastRss = rss;
+ profile.setLastRss(rss);
final SparseArray<Pair<Long, String>> watchUids =
mMemWatchProcesses.getMap().get(proc.processName);
@@ -551,7 +597,8 @@ public class AppProfiler {
}
}
if (check != null) {
- if ((pss * 1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+ if ((pss * 1024) >= check && profile.getThread() != null
+ && mMemWatchDumpProcName == null) {
boolean isDebuggable = Build.IS_DEBUGGABLE;
if (!isDebuggable) {
if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
@@ -560,7 +607,7 @@ public class AppProfiler {
}
if (isDebuggable) {
Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
- startHeapDumpLocked(proc, false);
+ startHeapDumpLPf(profile, false);
} else {
Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check
+ ", but debugging not enabled");
@@ -570,12 +617,13 @@ public class AppProfiler {
}
private final class RecordPssRunnable implements Runnable {
- private final ProcessRecord mProc;
+ private final ProcessProfileRecord mProfile;
private final Uri mDumpUri;
private final ContentResolver mContentResolver;
- RecordPssRunnable(ProcessRecord proc, Uri dumpUri, ContentResolver contentResolver) {
- mProc = proc;
+ RecordPssRunnable(ProcessProfileRecord profile, Uri dumpUri,
+ ContentResolver contentResolver) {
+ mProfile = profile;
mDumpUri = dumpUri;
mContentResolver = contentResolver;
}
@@ -583,12 +631,12 @@ public class AppProfiler {
@Override
public void run() {
try (ParcelFileDescriptor fd = mContentResolver.openFileDescriptor(mDumpUri, "rw")) {
- IApplicationThread thread = mProc.thread;
+ IApplicationThread thread = mProfile.getThread();
if (thread != null) {
try {
if (DEBUG_PSS) {
Slog.d(TAG_PSS, "Requesting dump heap from "
- + mProc + " to " + mDumpUri.getPath());
+ + mProfile.mApp + " to " + mDumpUri.getPath());
}
thread.dumpHeap(/* managed= */ true,
/* mallocInfo= */ false, /* runGc= */ false,
@@ -601,16 +649,17 @@ public class AppProfiler {
Slog.e(TAG, "Failed to dump heap", e);
// Need to clear the heap dump variables, otherwise no further heap dumps will be
// attempted.
- abortHeapDump(mProc.processName);
+ abortHeapDump(mProfile.mApp.processName);
}
}
}
- @GuardedBy("mService")
- void startHeapDumpLocked(ProcessRecord proc, boolean isUserInitiated) {
+ @GuardedBy("mProfilerLock")
+ void startHeapDumpLPf(ProcessProfileRecord profile, boolean isUserInitiated) {
+ final ProcessRecord proc = profile.mApp;
mMemWatchDumpProcName = proc.processName;
mMemWatchDumpUri = makeHeapDumpUri(proc.processName);
- mMemWatchDumpPid = proc.pid;
+ mMemWatchDumpPid = profile.getPid();
mMemWatchDumpUid = proc.uid;
mMemWatchIsUserInitiated = isUserInitiated;
Context ctx;
@@ -621,11 +670,11 @@ public class AppProfiler {
throw new RuntimeException("android package not found.");
}
BackgroundThread.getHandler().post(
- new RecordPssRunnable(proc, mMemWatchDumpUri, ctx.getContentResolver()));
+ new RecordPssRunnable(profile, mMemWatchDumpUri, ctx.getContentResolver()));
}
void dumpHeapFinished(String path, int callerPid) {
- synchronized (mService) {
+ synchronized (mProfilerLock) {
if (callerPid != mMemWatchDumpPid) {
Slog.w(TAG, "dumpHeapFinished: Calling pid " + Binder.getCallingPid()
+ " does not match last pid " + mMemWatchDumpPid);
@@ -651,7 +700,7 @@ public class AppProfiler {
final long memLimit;
final String reportPackage;
final boolean isUserInitiated;
- synchronized (mService) {
+ synchronized (mProfilerLock) {
uid = mMemWatchDumpUid;
procName = mMemWatchDumpProcName;
Pair<Long, String> val = mMemWatchProcesses.get(procName, uid);
@@ -695,7 +744,7 @@ public class AppProfiler {
void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
String reportPackage) {
- synchronized (mService) {
+ synchronized (mProfilerLock) {
if (maxMemSize > 0) {
mMemWatchProcesses.put(processName, uid, new Pair(maxMemSize, reportPackage));
} else {
@@ -717,7 +766,7 @@ public class AppProfiler {
void handleAbortDumpHeap(String procName) {
if (procName != null) {
- synchronized (mService) {
+ synchronized (mProfilerLock) {
if (procName.equals(mMemWatchDumpProcName)) {
mMemWatchDumpProcName = null;
mMemWatchDumpUri = null;
@@ -736,24 +785,24 @@ public class AppProfiler {
/**
* Schedule PSS collection of a process.
*/
- @GuardedBy("mService")
- private boolean requestPssLocked(ProcessRecord proc, int procState) {
- if (mPendingPssProcesses.contains(proc)) {
+ @GuardedBy("mProfilerLock")
+ private boolean requestPssLPf(ProcessProfileRecord profile, int procState) {
+ if (mPendingPssProfiles.contains(profile)) {
return false;
}
- if (mPendingPssProcesses.size() == 0) {
+ if (mPendingPssProfiles.size() == 0) {
final long deferral = (mPssDeferralTime > 0 && mActivityStartingNesting.get() > 0)
? mPssDeferralTime : 0;
if (DEBUG_PSS && deferral > 0) {
- Slog.d(TAG_PSS, "requestPssLocked() deferring PSS request by "
+ Slog.d(TAG_PSS, "requestPssLPf() deferring PSS request by "
+ deferral + " ms");
}
mBgHandler.sendEmptyMessageDelayed(BgHandler.COLLECT_PSS_BG_MSG, deferral);
}
- if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of: " + proc);
- proc.pssProcState = procState;
- proc.pssStatType = ProcessStats.ADD_PSS_INTERNAL_SINGLE;
- mPendingPssProcesses.add(proc);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of: " + profile.mApp);
+ profile.setPssProcState(procState);
+ profile.setPssStatType(ProcessStats.ADD_PSS_INTERNAL_SINGLE);
+ mPendingPssProfiles.add(profile);
return true;
}
@@ -761,9 +810,9 @@ public class AppProfiler {
* Re-defer a posted PSS collection pass, if one exists. Assumes deferral is
* currently active policy when called.
*/
- @GuardedBy("mService")
- private void deferPssIfNeededLocked() {
- if (mPendingPssProcesses.size() > 0) {
+ @GuardedBy("mProfilerLock")
+ private void deferPssIfNeededLPf() {
+ if (mPendingPssProfiles.size() > 0) {
mBgHandler.removeMessages(BgHandler.COLLECT_PSS_BG_MSG);
mBgHandler.sendEmptyMessageDelayed(BgHandler.COLLECT_PSS_BG_MSG, mPssDeferralTime);
}
@@ -774,7 +823,9 @@ public class AppProfiler {
if (DEBUG_PSS) {
Slog.d(TAG_PSS, "Deferring PSS collection for activity start");
}
- deferPssIfNeededLocked();
+ synchronized (mProfilerLock) {
+ deferPssIfNeededLPf();
+ }
mActivityStartingNesting.getAndIncrement();
mBgHandler.sendEmptyMessageDelayed(BgHandler.STOP_DEFERRING_PSS_MSG, mPssDeferralTime);
}
@@ -803,40 +854,45 @@ public class AppProfiler {
*/
@GuardedBy("mService")
void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
- if (!always) {
- if (now < (mLastFullPssTime
- + (memLowered ? mService.mConstants.FULL_PSS_LOWERED_INTERVAL
- : mService.mConstants.FULL_PSS_MIN_INTERVAL))) {
- return;
+ synchronized (mProfilerLock) {
+ if (!always) {
+ if (now < (mLastFullPssTime
+ + (memLowered ? mService.mConstants.FULL_PSS_LOWERED_INTERVAL
+ : mService.mConstants.FULL_PSS_MIN_INTERVAL))) {
+ return;
+ }
}
- }
- if (DEBUG_PSS) {
- Slog.d(TAG_PSS, "Requesting pss of all procs! memLowered=" + memLowered);
- }
- mLastFullPssTime = now;
- mFullPssPending = true;
- for (int i = mPendingPssProcesses.size() - 1; i >= 0; i--) {
- abortNextPssTime(mPendingPssProcesses.get(i).procStateMemTracker);
- }
- mPendingPssProcesses.ensureCapacity(mService.mProcessList.getLruSizeLocked());
- mPendingPssProcesses.clear();
- for (int i = mService.mProcessList.getLruSizeLocked() - 1; i >= 0; i--) {
- ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
- if (app.thread == null || app.getCurProcState() == PROCESS_STATE_NONEXISTENT) {
- continue;
+ if (DEBUG_PSS) {
+ Slog.d(TAG_PSS, "Requesting pss of all procs! memLowered=" + memLowered);
}
- if (memLowered || (always && now
- > app.lastStateTime + ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
- || now > (app.lastStateTime + ProcessList.PSS_ALL_INTERVAL)) {
- app.pssProcState = app.setProcState;
- app.pssStatType = always ? ProcessStats.ADD_PSS_INTERNAL_ALL_POLL
- : ProcessStats.ADD_PSS_INTERNAL_ALL_MEM;
- updateNextPssTimeLocked(app.getCurProcState(), app, now, true);
- mPendingPssProcesses.add(app);
+ mLastFullPssTime = now;
+ mFullPssPending = true;
+ for (int i = mPendingPssProfiles.size() - 1; i >= 0; i--) {
+ mPendingPssProfiles.get(i).abortNextPssTime();
+ }
+ mPendingPssProfiles.ensureCapacity(mService.mProcessList.getLruSizeLocked());
+ mPendingPssProfiles.clear();
+ for (int i = mService.mProcessList.getLruSizeLocked() - 1; i >= 0; i--) {
+ ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
+ final ProcessProfileRecord profile = app.mProfile;
+ if (profile.getThread() == null
+ || profile.getSetProcState() == PROCESS_STATE_NONEXISTENT) {
+ return;
+ }
+ final long lastStateTime = profile.getLastStateTime();
+ if (memLowered || (always
+ && now > lastStateTime + ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
+ || now > (lastStateTime + ProcessList.PSS_ALL_INTERVAL)) {
+ profile.setPssProcState(profile.getSetProcState());
+ profile.setPssStatType(always ? ProcessStats.ADD_PSS_INTERNAL_ALL_POLL
+ : ProcessStats.ADD_PSS_INTERNAL_ALL_MEM);
+ updateNextPssTimeLPf(profile.getSetProcState(), profile, now, true);
+ mPendingPssProfiles.add(profile);
+ }
+ }
+ if (!mBgHandler.hasMessages(BgHandler.COLLECT_PSS_BG_MSG)) {
+ mBgHandler.sendEmptyMessage(BgHandler.COLLECT_PSS_BG_MSG);
}
- }
- if (!mBgHandler.hasMessages(BgHandler.COLLECT_PSS_BG_MSG)) {
- mBgHandler.sendEmptyMessage(BgHandler.COLLECT_PSS_BG_MSG);
}
}
@@ -851,8 +907,7 @@ public class AppProfiler {
}
}
- @GuardedBy("mService")
- boolean getTestPssModeLocked() {
+ boolean getTestPssMode() {
return mTestPssMode;
}
@@ -969,14 +1024,16 @@ public class AppProfiler {
if (factor < minFactor) factor = minFactor;
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
for (int i = 0; i < numOfLru; i++) {
- ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
+ final ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
+ final ProcessProfileRecord profile = app.mProfile;
+ final int trimMemoryLevel = profile.getTrimMemoryLevel();
if (allChanged || app.procStateChanged) {
mService.setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
- if (app.trimMemoryLevel < curLevel && app.thread != null) {
+ if (trimMemoryLevel < curLevel && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
Slog.v(TAG_OOM_ADJ,
@@ -987,7 +1044,7 @@ public class AppProfiler {
} catch (RemoteException e) {
}
}
- app.trimMemoryLevel = curLevel;
+ profile.setTrimMemoryLevel(curLevel);
step++;
if (step >= factor) {
step = 0;
@@ -1002,7 +1059,7 @@ public class AppProfiler {
}
} else if (app.getCurProcState() == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
&& !app.killedByAm) {
- if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
+ if (trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
@@ -1015,15 +1072,15 @@ public class AppProfiler {
} catch (RemoteException e) {
}
}
- app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+ profile.setTrimMemoryLevel(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} else {
if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- || app.systemNoUi) && app.hasPendingUiClean()) {
+ || app.systemNoUi) && profile.hasPendingUiClean()) {
// If this application is now in the background and it
// had done UI, then give it the special trim level to
// have it free UI resources.
final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
- if (app.trimMemoryLevel < level && app.thread != null) {
+ if (trimMemoryLevel < level && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
Slog.v(TAG_OOM_ADJ, "Trimming memory of bg-ui "
@@ -1033,9 +1090,9 @@ public class AppProfiler {
} catch (RemoteException e) {
}
}
- app.setPendingUiClean(false);
+ profile.setPendingUiClean(false);
}
- if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
+ if (trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
Slog.v(TAG_OOM_ADJ, "Trimming memory of fg " + app.processName
@@ -1045,7 +1102,7 @@ public class AppProfiler {
} catch (RemoteException e) {
}
}
- app.trimMemoryLevel = fgTrimLevel;
+ profile.setTrimMemoryLevel(fgTrimLevel);
}
}
} else {
@@ -1054,14 +1111,15 @@ public class AppProfiler {
mLowRamStartTime = 0;
}
for (int i = 0; i < numOfLru; i++) {
- ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
+ final ProcessRecord app = mService.mProcessList.mLruProcesses.get(i);
+ final ProcessProfileRecord profile = app.mProfile;
if (allChanged || app.procStateChanged) {
mService.setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- || app.systemNoUi) && app.hasPendingUiClean()) {
- if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
+ || app.systemNoUi) && profile.hasPendingUiClean()) {
+ if (profile.getTrimMemoryLevel() < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
&& app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
@@ -1074,9 +1132,9 @@ public class AppProfiler {
} catch (RemoteException e) {
}
}
- app.setPendingUiClean(false);
+ profile.setPendingUiClean(false);
}
- app.trimMemoryLevel = 0;
+ profile.setTrimMemoryLevel(0);
}
}
return allChanged;
@@ -1087,25 +1145,459 @@ public class AppProfiler {
return mLowRamTimeSinceLastIdle + (mLowRamStartTime > 0 ? (now - mLowRamStartTime) : 0);
}
+ /**
+ * Ask a given process to GC right now.
+ */
+ @GuardedBy("mProfilerLock")
+ private void performAppGcLPf(ProcessRecord app) {
+ try {
+ final ProcessProfileRecord profile = app.mProfile;
+ profile.setLastRequestedGc(SystemClock.uptimeMillis());
+ IApplicationThread thread = profile.getThread();
+ if (thread != null) {
+ if (profile.getReportLowMemory()) {
+ profile.setReportLowMemory(false);
+ thread.scheduleLowMemory();
+ } else {
+ thread.processInBackground();
+ }
+ }
+ } catch (Exception e) {
+ // whatever.
+ }
+ }
+
+ /**
+ * Perform GCs on all processes that are waiting for it, but only
+ * if things are idle.
+ */
+ @GuardedBy("mProfilerLock")
+ private void performAppGcsLPf() {
+ if (mProcessesToGc.size() <= 0) {
+ return;
+ }
+ while (mProcessesToGc.size() > 0) {
+ final ProcessRecord proc = mProcessesToGc.remove(0);
+ final ProcessProfileRecord profile = proc.mProfile;
+ if (profile.getCurRawAdj() > ProcessList.PERCEPTIBLE_APP_ADJ
+ || profile.getReportLowMemory()) {
+ if ((profile.getLastRequestedGc() + mService.mConstants.GC_MIN_INTERVAL)
+ <= SystemClock.uptimeMillis()) {
+ // To avoid spamming the system, we will GC processes one
+ // at a time, waiting a few seconds between each.
+ performAppGcLPf(proc);
+ scheduleAppGcsLPf();
+ return;
+ } else {
+ // It hasn't been long enough since we last GCed this
+ // process... put it in the list to wait for its time.
+ addProcessToGcListLPf(proc);
+ break;
+ }
+ }
+ }
+
+ scheduleAppGcsLPf();
+ }
+
+ /**
+ * If all looks good, perform GCs on all processes waiting for them.
+ */
@GuardedBy("mService")
- private void stopProfilerLocked(ProcessRecord proc, int profileType) {
+ final void performAppGcsIfAppropriateLocked() {
+ synchronized (mProfilerLock) {
+ if (mService.canGcNowLocked()) {
+ performAppGcsLPf();
+ return;
+ }
+ // Still not idle, wait some more.
+ scheduleAppGcsLPf();
+ }
+ }
+
+ /**
+ * Schedule the execution of all pending app GCs.
+ */
+ @GuardedBy("mProfilerLock")
+ final void scheduleAppGcsLPf() {
+ mService.mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
+
+ if (mProcessesToGc.size() > 0) {
+ // Schedule a GC for the time to the next process.
+ ProcessRecord proc = mProcessesToGc.get(0);
+ Message msg = mService.mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
+
+ long when = proc.mProfile.getLastRequestedGc() + mService.mConstants.GC_MIN_INTERVAL;
+ long now = SystemClock.uptimeMillis();
+ if (when < (now + mService.mConstants.GC_TIMEOUT)) {
+ when = now + mService.mConstants.GC_TIMEOUT;
+ }
+ mService.mHandler.sendMessageAtTime(msg, when);
+ }
+ }
+
+ /**
+ * Add a process to the array of processes waiting to be GCed. Keeps the
+ * list in sorted order by the last GC time. The process can't already be
+ * on the list.
+ */
+ @GuardedBy("mProfilerLock")
+ private void addProcessToGcListLPf(ProcessRecord proc) {
+ boolean added = false;
+ for (int i = mProcessesToGc.size() - 1; i >= 0; i--) {
+ if (mProcessesToGc.get(i).mProfile.getLastRequestedGc()
+ < proc.mProfile.getLastRequestedGc()) {
+ added = true;
+ mProcessesToGc.add(i + 1, proc);
+ break;
+ }
+ }
+ if (!added) {
+ mProcessesToGc.add(0, proc);
+ }
+ }
+
+ @GuardedBy("mService")
+ final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
+ // If there are no longer any background processes running,
+ // and the app that died was not running instrumentation,
+ // then tell everyone we are now low on memory.
+ if (!mService.mProcessList.haveBackgroundProcessLocked()) {
+ boolean doReport = Build.IS_DEBUGGABLE;
+ final long now = SystemClock.uptimeMillis();
+ if (doReport) {
+ if (now < (mLastMemUsageReportTime + 5 * 60 * 1000)) {
+ doReport = false;
+ } else {
+ mLastMemUsageReportTime = now;
+ }
+ }
+ final int lruSize = mService.mProcessList.getLruSizeLocked();
+ final ArrayList<ProcessMemInfo> memInfos = doReport
+ ? new ArrayList<ProcessMemInfo>(lruSize) : null;
+ EventLogTags.writeAmLowMemory(lruSize);
+ for (int i = lruSize - 1; i >= 0; i--) {
+ ProcessRecord rec = mService.mProcessList.mLruProcesses.get(i);
+ if (rec == dyingProc || rec.thread == null) {
+ return;
+ }
+ if (memInfos != null) {
+ memInfos.add(new ProcessMemInfo(rec.processName, rec.pid,
+ rec.setAdj, rec.setProcState,
+ rec.adjType, rec.makeAdjReason()));
+ }
+ final ProcessProfileRecord profile = rec.mProfile;
+ if ((profile.getLastLowMemory() + mService.mConstants.GC_MIN_INTERVAL) <= now) {
+ // The low memory report is overriding any current
+ // state for a GC request. Make sure to do
+ // heavy/important/visible/foreground processes first.
+ synchronized (mProfilerLock) {
+ if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ profile.setLastRequestedGc(0);
+ } else {
+ profile.setLastRequestedGc(profile.getLastLowMemory());
+ }
+ profile.setReportLowMemory(true);
+ profile.setLastLowMemory(now);
+ mProcessesToGc.remove(rec);
+ addProcessToGcListLPf(rec);
+ }
+ }
+ }
+ if (doReport) {
+ Message msg = mService.mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
+ mService.mHandler.sendMessage(msg);
+ }
+ }
+ synchronized (mProfilerLock) {
+ scheduleAppGcsLPf();
+ }
+ }
+
+ void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
+ final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
+ for (int i = 0, size = memInfos.size(); i < size; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ infoMap.put(mi.pid, mi);
+ }
+ updateCpuStatsNow();
+ long[] memtrackTmp = new long[1];
+ long[] swaptrackTmp = new long[2];
+ // Get a list of Stats that have vsize > 0
+ final List<ProcessCpuTracker.Stats> stats = getCpuStats(st -> st.vsize > 0);
+ final int statsCount = stats.size();
+ for (int i = 0; i < statsCount; i++) {
+ ProcessCpuTracker.Stats st = stats.get(i);
+ long pss = Debug.getPss(st.pid, swaptrackTmp, memtrackTmp);
+ if (pss > 0) {
+ if (infoMap.indexOfKey(st.pid) < 0) {
+ ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+ ProcessList.NATIVE_ADJ, -1, "native", null);
+ mi.pss = pss;
+ mi.swapPss = swaptrackTmp[1];
+ mi.memtrack = memtrackTmp[0];
+ memInfos.add(mi);
+ }
+ }
+ }
+
+ long totalPss = 0;
+ long totalSwapPss = 0;
+ long totalMemtrack = 0;
+ for (int i = 0, size = memInfos.size(); i < size; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ if (mi.pss == 0) {
+ mi.pss = Debug.getPss(mi.pid, swaptrackTmp, memtrackTmp);
+ mi.swapPss = swaptrackTmp[1];
+ mi.memtrack = memtrackTmp[0];
+ }
+ totalPss += mi.pss;
+ totalSwapPss += mi.swapPss;
+ totalMemtrack += mi.memtrack;
+ }
+ Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+ @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+ if (lhs.oomAdj != rhs.oomAdj) {
+ return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+ }
+ if (lhs.pss != rhs.pss) {
+ return lhs.pss < rhs.pss ? 1 : -1;
+ }
+ return 0;
+ }
+ });
+
+ StringBuilder tag = new StringBuilder(128);
+ StringBuilder stack = new StringBuilder(128);
+ tag.append("Low on memory -- ");
+ appendMemBucket(tag, totalPss, "total", false);
+ appendMemBucket(stack, totalPss, "total", true);
+
+ StringBuilder fullNativeBuilder = new StringBuilder(1024);
+ StringBuilder shortNativeBuilder = new StringBuilder(1024);
+ StringBuilder fullJavaBuilder = new StringBuilder(1024);
+
+ boolean firstLine = true;
+ int lastOomAdj = Integer.MIN_VALUE;
+ long extraNativeRam = 0;
+ long extraNativeMemtrack = 0;
+ long cachedPss = 0;
+ for (int i = 0, size = memInfos.size(); i < size; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+
+ if (mi.oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ cachedPss += mi.pss;
+ }
+
+ if (mi.oomAdj != ProcessList.NATIVE_ADJ
+ && (mi.oomAdj < ProcessList.SERVICE_ADJ
+ || mi.oomAdj == ProcessList.HOME_APP_ADJ
+ || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+ if (lastOomAdj != mi.oomAdj) {
+ lastOomAdj = mi.oomAdj;
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ tag.append(" / ");
+ }
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+ if (firstLine) {
+ stack.append(":");
+ firstLine = false;
+ }
+ stack.append("\n\t at ");
+ } else {
+ stack.append("$");
+ }
+ } else {
+ tag.append(" ");
+ stack.append("$");
+ }
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ appendMemBucket(tag, mi.pss, mi.name, false);
+ }
+ appendMemBucket(stack, mi.pss, mi.name, true);
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+ && ((i + 1) >= size || memInfos.get(i + 1).oomAdj != lastOomAdj)) {
+ stack.append("(");
+ for (int k = 0; k < DUMP_MEM_OOM_ADJ.length; k++) {
+ if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+ stack.append(DUMP_MEM_OOM_LABEL[k]);
+ stack.append(":");
+ stack.append(DUMP_MEM_OOM_ADJ[k]);
+ }
+ }
+ stack.append(")");
+ }
+ }
+
+ appendMemInfo(fullNativeBuilder, mi);
+ if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
+ // The short form only has native processes that are >= 512K.
+ if (mi.pss >= 512) {
+ appendMemInfo(shortNativeBuilder, mi);
+ } else {
+ extraNativeRam += mi.pss;
+ extraNativeMemtrack += mi.memtrack;
+ }
+ } else {
+ // Short form has all other details, but if we have collected RAM
+ // from smaller native processes let's dump a summary of that.
+ if (extraNativeRam > 0) {
+ appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
+ -1, extraNativeRam, extraNativeMemtrack, "(Other native)");
+ shortNativeBuilder.append('\n');
+ extraNativeRam = 0;
+ }
+ appendMemInfo(fullJavaBuilder, mi);
+ }
+ }
+
+ fullJavaBuilder.append(" ");
+ ProcessList.appendRamKb(fullJavaBuilder, totalPss);
+ fullJavaBuilder.append(": TOTAL");
+ if (totalMemtrack > 0) {
+ fullJavaBuilder.append(" (");
+ fullJavaBuilder.append(stringifyKBSize(totalMemtrack));
+ fullJavaBuilder.append(" memtrack)");
+ }
+ fullJavaBuilder.append("\n");
+
+ MemInfoReader memInfo = new MemInfoReader();
+ memInfo.readMemInfo();
+ final long[] infos = memInfo.getRawInfo();
+
+ StringBuilder memInfoBuilder = new StringBuilder(1024);
+ Debug.getMemInfo(infos);
+ memInfoBuilder.append(" MemInfo: ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SLAB])).append(" slab, ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SHMEM])).append(" shmem, ");
+ memInfoBuilder.append(stringifyKBSize(
+ infos[Debug.MEMINFO_VM_ALLOC_USED])).append(" vm alloc, ");
+ memInfoBuilder.append(stringifyKBSize(
+ infos[Debug.MEMINFO_PAGE_TABLES])).append(" page tables ");
+ memInfoBuilder.append(stringifyKBSize(
+ infos[Debug.MEMINFO_KERNEL_STACK])).append(" kernel stack\n");
+ memInfoBuilder.append(" ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_BUFFERS])).append(" buffers, ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_CACHED])).append(" cached, ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_MAPPED])).append(" mapped, ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_FREE])).append(" free\n");
+ if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
+ memInfoBuilder.append(" ZRAM: ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_ZRAM_TOTAL]));
+ memInfoBuilder.append(" RAM, ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SWAP_TOTAL]));
+ memInfoBuilder.append(" swap total, ");
+ memInfoBuilder.append(stringifyKBSize(infos[Debug.MEMINFO_SWAP_FREE]));
+ memInfoBuilder.append(" swap free\n");
+ }
+ final long[] ksm = getKsmInfo();
+ if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
+ || ksm[KSM_VOLATILE] != 0) {
+ memInfoBuilder.append(" KSM: ");
+ memInfoBuilder.append(stringifyKBSize(ksm[KSM_SHARING]));
+ memInfoBuilder.append(" saved from shared ");
+ memInfoBuilder.append(stringifyKBSize(ksm[KSM_SHARED]));
+ memInfoBuilder.append("\n ");
+ memInfoBuilder.append(stringifyKBSize(ksm[KSM_UNSHARED]));
+ memInfoBuilder.append(" unshared; ");
+ memInfoBuilder.append(stringifyKBSize(ksm[KSM_VOLATILE]));
+ memInfoBuilder.append(" volatile\n");
+ }
+ memInfoBuilder.append(" Free RAM: ");
+ memInfoBuilder.append(stringifyKBSize(cachedPss + memInfo.getCachedSizeKb()
+ + memInfo.getFreeSizeKb()));
+ memInfoBuilder.append("\n");
+ long kernelUsed = memInfo.getKernelUsedSizeKb();
+ final long ionHeap = Debug.getIonHeapsSizeKb();
+ final long ionPool = Debug.getIonPoolsSizeKb();
+ if (ionHeap >= 0 && ionPool >= 0) {
+ final long ionMapped = Debug.getIonMappedSizeKb();
+ final long ionUnmapped = ionHeap - ionMapped;
+ memInfoBuilder.append(" ION: ");
+ memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
+ memInfoBuilder.append("\n");
+ // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
+ // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
+ kernelUsed += ionHeap;
+ }
+ final long gpuUsage = Debug.getGpuTotalUsageKb();
+ if (gpuUsage >= 0) {
+ memInfoBuilder.append(" GPU: ");
+ memInfoBuilder.append(stringifyKBSize(gpuUsage));
+ memInfoBuilder.append("\n");
+ }
+ memInfoBuilder.append(" Used RAM: ");
+ memInfoBuilder.append(stringifyKBSize(
+ totalPss - cachedPss + kernelUsed));
+ memInfoBuilder.append("\n");
+ memInfoBuilder.append(" Lost RAM: ");
+ memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb()
+ - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+ - kernelUsed - memInfo.getZramTotalSizeKb()));
+ memInfoBuilder.append("\n");
+ Slog.i(TAG, "Low on memory:");
+ Slog.i(TAG, shortNativeBuilder.toString());
+ Slog.i(TAG, fullJavaBuilder.toString());
+ Slog.i(TAG, memInfoBuilder.toString());
+
+ StringBuilder dropBuilder = new StringBuilder(1024);
+ dropBuilder.append("Low on memory:");
+ dropBuilder.append(stack);
+ dropBuilder.append('\n');
+ dropBuilder.append(fullNativeBuilder);
+ dropBuilder.append(fullJavaBuilder);
+ dropBuilder.append('\n');
+ dropBuilder.append(memInfoBuilder);
+ dropBuilder.append('\n');
+ StringWriter catSw = new StringWriter();
+ synchronized (mService) {
+ PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+ String[] emptyArgs = new String[] { };
+ catPw.println();
+ mService.mProcessList.dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null, -1);
+ catPw.println();
+ mService.mServices.newServiceDumperLocked(null, catPw, emptyArgs, 0,
+ false, null).dumpLocked();
+ catPw.println();
+ mService.mAtmInternal.dump(
+ DUMP_ACTIVITIES_CMD, null, catPw, emptyArgs, 0, false, false, null);
+ catPw.flush();
+ }
+ dropBuilder.append(catSw.toString());
+ FrameworkStatsLog.write(FrameworkStatsLog.LOW_MEM_REPORTED);
+ mService.addErrorToDropBox("lowmem", null, "system_server", null,
+ null, null, tag.toString(), dropBuilder.toString(), null, null);
+ synchronized (mService) {
+ long now = SystemClock.uptimeMillis();
+ if (mLastMemUsageReportTime < now) {
+ mLastMemUsageReportTime = now;
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ private void stopProfilerLPf(ProcessRecord proc, int profileType) {
if (proc == null || proc == mProfileData.getProfileProc()) {
proc = mProfileData.getProfileProc();
profileType = mProfileType;
- clearProfilerLocked();
+ clearProfilerLPf();
}
if (proc == null) {
return;
}
+ final IApplicationThread thread = proc.mProfile.getThread();
+ if (thread == null) {
+ return;
+ }
try {
- proc.thread.profilerControl(false, null, profileType);
+ thread.profilerControl(false, null, profileType);
} catch (RemoteException e) {
throw new IllegalStateException("Process disappeared");
}
}
- @GuardedBy("mService")
- void clearProfilerLocked() {
+ @GuardedBy("mProfilerLock")
+ void clearProfilerLPf() {
if (mProfileData.getProfilerInfo() != null
&& mProfileData.getProfilerInfo().profileFd != null) {
try {
@@ -1118,22 +1610,22 @@ public class AppProfiler {
mProfileData.setProfilerInfo(null);
}
- @GuardedBy("mService")
- void clearProfilerLocked(ProcessRecord app) {
+ @GuardedBy("mProfilerLock")
+ void clearProfilerLPf(ProcessRecord app) {
if (mProfileData.getProfileProc() == null
|| mProfileData.getProfilerInfo() == null
|| mProfileData.getProfileProc() != app) {
return;
}
- clearProfilerLocked();
+ clearProfilerLPf();
}
- @GuardedBy("mService")
- boolean profileControlLocked(ProcessRecord proc, boolean start,
+ @GuardedBy("mProfilerLock")
+ boolean profileControlLPf(ProcessRecord proc, boolean start,
ProfilerInfo profilerInfo, int profileType) {
try {
if (start) {
- stopProfilerLocked(null, 0);
+ stopProfilerLPf(null, 0);
mService.setProfileApp(proc.info, proc.processName, profilerInfo);
mProfileData.setProfileProc(proc);
mProfileType = profileType;
@@ -1144,7 +1636,7 @@ public class AppProfiler {
fd = null;
}
profilerInfo.profileFd = fd;
- proc.thread.profilerControl(start, profilerInfo, profileType);
+ proc.mProfile.getThread().profilerControl(start, profilerInfo, profileType);
fd = null;
try {
mProfileData.getProfilerInfo().profileFd.close();
@@ -1160,7 +1652,7 @@ public class AppProfiler {
profilerInfo = null;
}
} else {
- stopProfilerLocked(proc, profileType);
+ stopProfilerLPf(proc, profileType);
if (profilerInfo != null && profilerInfo.profileFd != null) {
try {
profilerInfo.profileFd.close();
@@ -1182,8 +1674,8 @@ public class AppProfiler {
}
}
- @GuardedBy("mService")
- void setProfileAppLocked(String processName, ProfilerInfo profilerInfo) {
+ @GuardedBy("mProfilerLock")
+ void setProfileAppLPf(String processName, ProfilerInfo profilerInfo) {
mProfileData.setProfileApp(processName);
if (mProfileData.getProfilerInfo() != null) {
@@ -1198,13 +1690,13 @@ public class AppProfiler {
mProfileType = 0;
}
- @GuardedBy("mService")
- void setProfileProcLocked(ProcessRecord proc) {
+ @GuardedBy("mProfilerLock")
+ void setProfileProcLPf(ProcessRecord proc) {
mProfileData.setProfileProc(proc);
}
- @GuardedBy("mService")
- void setAgentAppLocked(@NonNull String packageName, @Nullable String agent) {
+ @GuardedBy("mProfilerLock")
+ void setAgentAppLPf(@NonNull String packageName, @Nullable String agent) {
if (agent == null) {
if (mAppAgentMap != null) {
mAppAgentMap.remove(packageName);
@@ -1226,8 +1718,7 @@ public class AppProfiler {
}
}
- @GuardedBy("mService")
- void updateCpuStatsLocked() {
+ void updateCpuStats() {
final long now = SystemClock.uptimeMillis();
if (mLastCpuTime.get() >= now - MONITOR_CPU_MIN_TIME) {
return;
@@ -1301,17 +1792,18 @@ public class AppProfiler {
totalUTime += st.rel_utime;
totalSTime += st.rel_stime;
if (pr != null) {
- BatteryStatsImpl.Uid.Proc ps = pr.curProcBatteryStats;
+ final ProcessProfileRecord profile = pr.mProfile;
+ BatteryStatsImpl.Uid.Proc ps = profile.getCurProcBatteryStats();
if (ps == null || !ps.isActive()) {
- pr.curProcBatteryStats = ps = bstats.getProcessStatsLocked(
+ profile.setCurProcBatteryStats(
+ ps = bstats.getProcessStatsLocked(
pr.info.uid, pr.processName,
- elapsedRealtime, uptime);
+ elapsedRealtime, uptime));
}
ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
- pr.curCpuTime += st.rel_utime + st.rel_stime;
- if (pr.lastCpuTime == 0) {
- pr.lastCpuTime = pr.curCpuTime;
- }
+ final long curCpuTime = profile.mCurCpuTime.addAndGet(
+ st.rel_utime + st.rel_stime);
+ profile.mLastCpuTime.compareAndSet(0, curCpuTime);
} else {
BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
if (ps == null || !ps.isActive()) {
@@ -1483,44 +1975,46 @@ public class AppProfiler {
ProfilerInfo profilerInfo = null;
String preBindAgent = null;
final String processName = app.processName;
- if (mProfileData.getProfileApp() != null
- && mProfileData.getProfileApp().equals(processName)) {
- mProfileData.setProfileProc(app);
- if (mProfileData.getProfilerInfo() != null) {
- // Send a profiler info object to the app if either a file is given, or
- // an agent should be loaded at bind-time.
- boolean needsInfo = mProfileData.getProfilerInfo().profileFile != null
- || mProfileData.getProfilerInfo().attachAgentDuringBind;
- profilerInfo = needsInfo
- ? new ProfilerInfo(mProfileData.getProfilerInfo()) : null;
- if (mProfileData.getProfilerInfo().agent != null) {
- preBindAgent = mProfileData.getProfilerInfo().agent;
+ synchronized (mProfilerLock) {
+ if (mProfileData.getProfileApp() != null
+ && mProfileData.getProfileApp().equals(processName)) {
+ mProfileData.setProfileProc(app);
+ if (mProfileData.getProfilerInfo() != null) {
+ // Send a profiler info object to the app if either a file is given, or
+ // an agent should be loaded at bind-time.
+ boolean needsInfo = mProfileData.getProfilerInfo().profileFile != null
+ || mProfileData.getProfilerInfo().attachAgentDuringBind;
+ profilerInfo = needsInfo
+ ? new ProfilerInfo(mProfileData.getProfilerInfo()) : null;
+ if (mProfileData.getProfilerInfo().agent != null) {
+ preBindAgent = mProfileData.getProfilerInfo().agent;
+ }
}
+ } else if (instr != null && instr.mProfileFile != null) {
+ profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false,
+ null, false);
}
- } else if (instr != null && instr.mProfileFile != null) {
- profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false,
- null, false);
- }
- if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
- // We need to do a debuggable check here. See setAgentApp for why the check is
- // postponed to here.
- if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- String agent = mAppAgentMap.get(processName);
- // Do not overwrite already requested agent.
- if (profilerInfo == null) {
- profilerInfo = new ProfilerInfo(null, null, 0, false, false,
- mAppAgentMap.get(processName), true);
- } else if (profilerInfo.agent == null) {
- profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true);
+ if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
+ // We need to do a debuggable check here. See setAgentApp for why the check is
+ // postponed to here.
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ String agent = mAppAgentMap.get(processName);
+ // Do not overwrite already requested agent.
+ if (profilerInfo == null) {
+ profilerInfo = new ProfilerInfo(null, null, 0, false, false,
+ mAppAgentMap.get(processName), true);
+ } else if (profilerInfo.agent == null) {
+ profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true);
+ }
}
}
- }
- if (profilerInfo != null && profilerInfo.profileFd != null) {
- profilerInfo.profileFd = profilerInfo.profileFd.dup();
- if (TextUtils.equals(mProfileData.getProfileApp(), processName)
- && mProfileData.getProfilerInfo() != null) {
- clearProfilerLocked();
+ if (profilerInfo != null && profilerInfo.profileFd != null) {
+ profilerInfo.profileFd = profilerInfo.profileFd.dup();
+ if (TextUtils.equals(mProfileData.getProfileApp(), processName)
+ && mProfileData.getProfilerInfo() != null) {
+ clearProfilerLPf();
+ }
}
}
@@ -1566,19 +2060,25 @@ public class AppProfiler {
@GuardedBy("mService")
void onCleanupApplicationRecordLocked(ProcessRecord app) {
- mPendingPssProcesses.remove(app);
- abortNextPssTime(app.procStateMemTracker);
+ synchronized (mProfilerLock) {
+ final ProcessProfileRecord profile = app.mProfile;
+ mProcessesToGc.remove(app);
+ mPendingPssProfiles.remove(profile);
+ profile.abortNextPssTime();
+ }
}
@GuardedBy("mService")
void onAppDiedLocked(ProcessRecord app) {
- if (mProfileData.getProfileProc() == app) {
- clearProfilerLocked();
+ synchronized (mProfilerLock) {
+ if (mProfileData.getProfileProc() == app) {
+ clearProfilerLPf();
+ }
}
}
- @GuardedBy("mService")
- boolean dumpMemWatchProcessesLocked(PrintWriter pw, boolean needSep) {
+ @GuardedBy("mProfilerLock")
+ boolean dumpMemWatchProcessesLPf(PrintWriter pw, boolean needSep) {
if (mMemWatchProcesses.getMap().size() > 0) {
pw.println(" Mem watch processes:");
final ArrayMap<String, SparseArray<Pair<Long, String>>> procs =
@@ -1669,8 +2169,8 @@ public class AppProfiler {
+ " mLastNumProcesses=" + mLastNumProcesses);
}
- @GuardedBy("mService")
- void writeMemWatchProcessToProtoLocked(ProtoOutputStream proto) {
+ @GuardedBy("mProfilerLock")
+ void writeMemWatchProcessToProtoLPf(ProtoOutputStream proto) {
if (mMemWatchProcesses.getMap().size() > 0) {
final long token = proto.start(
ActivityManagerServiceDumpProcessesProto.MEM_WATCH_PROCESSES);
@@ -1753,4 +2253,55 @@ public class AppProfiler {
report.append(mProcessCpuTracker.printCurrentState(time));
}
}
+
+ @GuardedBy("mProfilerLock")
+ void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
+ if (mProcessesToGc.size() > 0) {
+ long now = SystemClock.uptimeMillis();
+ for (int i = 0, size = mProcessesToGc.size(); i < size; i++) {
+ ProcessRecord r = mProcessesToGc.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+ continue;
+ }
+ final long token = proto.start(fieldId);
+ final ProcessProfileRecord profile = r.mProfile;
+ r.dumpDebug(proto, ProcessToGcProto.PROC);
+ proto.write(ProcessToGcProto.REPORT_LOW_MEMORY, profile.getReportLowMemory());
+ proto.write(ProcessToGcProto.NOW_UPTIME_MS, now);
+ proto.write(ProcessToGcProto.LAST_GCED_MS, profile.getLastRequestedGc());
+ proto.write(ProcessToGcProto.LAST_LOW_MEMORY_MS, profile.getLastLowMemory());
+ proto.end(token);
+ }
+ }
+ }
+
+ @GuardedBy("mProfilerLock")
+ boolean dumpProcessesToGc(PrintWriter pw, boolean needSep, String dumpPackage) {
+ if (mProcessesToGc.size() > 0) {
+ boolean printed = false;
+ long now = SystemClock.uptimeMillis();
+ for (int i = 0, size = mProcessesToGc.size(); i < size; i++) {
+ ProcessRecord proc = mProcessesToGc.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(proc.info.packageName)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" Processes that are waiting to GC:");
+ printed = true;
+ }
+ pw.print(" Process "); pw.println(proc);
+ final ProcessProfileRecord profile = proc.mProfile;
+ pw.print(" lowMem="); pw.print(profile.getReportLowMemory());
+ pw.print(", last gced=");
+ pw.print(now - profile.getLastRequestedGc());
+ pw.print(" ms ago, last lowMem=");
+ pw.print(now - profile.getLastLowMemory());
+ pw.println(" ms ago");
+
+ }
+ }
+ return needSep;
+ }
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index d2ee69e0e00d..4de12183e403 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -849,7 +849,7 @@ public final class BroadcastQueue {
private boolean requestStartTargetPermissionsReviewIfNeededLocked(
BroadcastRecord receiverRecord, String receivingPackageName,
final int receivingUserId) {
- if (!mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ if (!mService.getPackageManagerInternal().isPermissionsReviewRequired(
receivingPackageName, receivingUserId)) {
return true;
}
@@ -922,7 +922,7 @@ public final class BroadcastQueue {
Slog.v(TAG, "Broadcast temp whitelist uid=" + uid + " duration=" + duration
+ " type=" + type + " : " + b.toString());
}
- mService.tempWhitelistUidLocked(uid, duration, b.toString(), type);
+ mService.tempAllowlistUidLocked(uid, duration, b.toString(), type);
}
/**
@@ -969,7 +969,7 @@ public final class BroadcastQueue {
+ mParallelBroadcasts.size() + " parallel broadcasts; "
+ mDispatcher.describeStateLocked());
- mService.updateCpuStatsLocked();
+ mService.updateCpuStats();
if (fromMsg) {
mBroadcastsScheduled = false;
@@ -1050,7 +1050,9 @@ public final class BroadcastQueue {
if (r == null) {
// No more broadcasts are deliverable right now, so all done!
mDispatcher.scheduleDeferralCheckLocked(false);
- mService.scheduleAppGcsLocked();
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ mService.mAppProfiler.scheduleAppGcsLPf();
+ }
if (looped && !skipOomAdj) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
diff --git a/services/core/java/com/android/server/am/CacheOomRanker.java b/services/core/java/com/android/server/am/CacheOomRanker.java
index 26cfd62d40ad..45ce4c5021bb 100644
--- a/services/core/java/com/android/server/am/CacheOomRanker.java
+++ b/services/core/java/com/android/server/am/CacheOomRanker.java
@@ -60,6 +60,9 @@ public class CacheOomRanker {
private final Object mPhenotypeFlagLock = new Object();
+ private final ActivityManagerService mService;
+ private final Object mProfilerLock;
+
@GuardedBy("mPhenotypeFlagLock")
private boolean mUseOomReRanking = DEFAULT_USE_OOM_RE_RANKING;
// Weight to apply to the LRU ordering.
@@ -101,6 +104,11 @@ public class CacheOomRanker {
}
};
+ CacheOomRanker(final ActivityManagerService service) {
+ mService = service;
+ mProfilerLock = service.mAppProfiler.mProfilerLock;
+ }
+
/** Load settings from device config and register a listener for changes. */
public void init(Executor executor) {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -223,7 +231,9 @@ public class CacheOomRanker {
addToScore(scoredProcessRecords, lruWeight);
}
if (rssWeight > 0.0f) {
- Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR);
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR);
+ }
addToScore(scoredProcessRecords, rssWeight);
}
if (usesWeight > 0.0f) {
@@ -297,7 +307,7 @@ public class CacheOomRanker {
@Override
public int compare(RankedProcessRecord o1, RankedProcessRecord o2) {
// High RSS first to match least recently used.
- return Long.compare(o2.proc.mLastRss, o1.proc.mLastRss);
+ return Long.compare(o2.proc.mProfile.getLastRss(), o1.proc.mProfile.getLastRss());
}
}
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index 6d9d3fbe41bd..e6cd509f50dc 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -128,7 +128,7 @@ final class ConnectionRecord {
&& association == null && binding.service.app != null
&& (binding.service.appInfo.uid != clientUid
|| !binding.service.processName.equals(clientProcessName))) {
- ProcessStats.ProcessStateHolder holder = binding.service.app.pkgList.get(
+ ProcessStats.ProcessStateHolder holder = binding.service.app.getPkgList().get(
binding.service.instanceName.getPackageName());
if (holder == null) {
Slog.wtf(TAG_AM, "No package in referenced service "
diff --git a/services/core/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java
index be49ce4b02ce..efee4321fd9f 100644
--- a/services/core/java/com/android/server/am/ContentProviderConnection.java
+++ b/services/core/java/com/android/server/am/ContentProviderConnection.java
@@ -16,6 +16,9 @@
package com.android.server.am;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+
import android.os.Binder;
import android.os.SystemClock;
import android.util.Slog;
@@ -25,9 +28,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.AssociationState;
import com.android.internal.app.procstats.ProcessStats;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-
/**
* Represents a link between a content provider and client.
*/
@@ -71,7 +71,7 @@ public final class ContentProviderConnection extends Binder {
&& association == null && provider.proc != null
&& (provider.appInfo.uid != client.uid
|| !provider.info.processName.equals(client.processName))) {
- ProcessStats.ProcessStateHolder holder = provider.proc.pkgList.get(
+ ProcessStats.ProcessStateHolder holder = provider.proc.getPkgList().get(
provider.name.getPackageName());
if (holder == null) {
Slog.wtf(TAG_AM, "No package in referenced provider "
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 89ed42377b07..478c512338f0 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -1214,9 +1214,8 @@ public class ContentProviderHelper {
final ProcessRecord app = apps.valueAt(iApp);
if (app.userId != userId || app.thread == null || app.unlocked) continue;
- for (int iPkg = 0, numPkgs = app.pkgList.size(); iPkg < numPkgs; iPkg++) {
+ app.getPkgList().forEachPackage(pkgName -> {
try {
- final String pkgName = app.pkgList.keyAt(iPkg);
final PackageInfo pkgInfo = AppGlobals.getPackageManager()
.getPackageInfo(pkgName, matchFlags, userId);
if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
@@ -1243,7 +1242,7 @@ public class ContentProviderHelper {
}
} catch (RemoteException ignored) {
}
- }
+ });
}
}
}
@@ -1430,13 +1429,14 @@ public class ContentProviderHelper {
return mService.validateAssociationAllowedLocked(cpi.packageName,
cpi.applicationInfo.uid, null, callingUid) ? null : "<null>";
}
- for (int i = callingApp.pkgList.size() - 1; i >= 0; i--) {
- if (!mService.validateAssociationAllowedLocked(callingApp.pkgList.keyAt(i),
+ final String r = callingApp.getPkgList().forEachPackage(pkgName -> {
+ if (!mService.validateAssociationAllowedLocked(pkgName,
callingApp.uid, cpi.packageName, cpi.applicationInfo.uid)) {
return cpi.packageName;
}
- }
- return null;
+ return null;
+ });
+ return r;
}
ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId, int pmFlags) {
@@ -1531,7 +1531,7 @@ public class ContentProviderHelper {
private boolean requestTargetProviderPermissionsReviewIfNeededLocked(ProviderInfo cpi,
ProcessRecord r, final int userId, Context context) {
- if (!mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ if (!mService.getPackageManagerInternal().isPermissionsReviewRequired(
cpi.packageName, userId)) {
return true;
}
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index fb8b5d480b27..59a19398420d 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -343,7 +343,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
&& mAssociation == null && provider.proc != null
&& (provider.appInfo.uid != mOwningUid
|| !provider.info.processName.equals(mOwningProcessName))) {
- ProcessStats.ProcessStateHolder holder = provider.proc.pkgList.get(
+ ProcessStats.ProcessStateHolder holder = provider.proc.getPkgList().get(
provider.name.getPackageName());
if (holder == null) {
Slog.wtf(TAG_AM, "No package in referenced provider "
diff --git a/services/core/java/com/android/server/am/FgsStartTempAllowList.java b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
index 3aca4cfd0162..4d8749c05294 100644
--- a/services/core/java/com/android/server/am/FgsStartTempAllowList.java
+++ b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
@@ -70,4 +70,8 @@ final class FgsStartTempAllowList {
return true;
}
}
+
+ void remove(int uid) {
+ mTempAllowListFgs.delete(uid);
+ }
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index de7931535297..5e146e16deb0 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -65,10 +65,10 @@ import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
import static com.android.server.am.ActivityManagerService.TAG_LRU;
import static com.android.server.am.ActivityManagerService.TAG_OOM_ADJ;
-import static com.android.server.am.ActivityManagerService.TAG_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
import static com.android.server.am.AppProfiler.TAG_PSS;
+import static com.android.server.am.ProcessList.TAG_PROCESS_OBSERVERS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import android.app.ActivityManager;
@@ -131,7 +131,7 @@ public final class OomAdjuster {
static final String OOM_ADJ_REASON_GET_PROVIDER = OOM_ADJ_REASON_METHOD + "_getProvider";
static final String OOM_ADJ_REASON_REMOVE_PROVIDER = OOM_ADJ_REASON_METHOD + "_removeProvider";
static final String OOM_ADJ_REASON_UI_VISIBILITY = OOM_ADJ_REASON_METHOD + "_uiVisibility";
- static final String OOM_ADJ_REASON_WHITELIST = OOM_ADJ_REASON_METHOD + "_whitelistChange";
+ static final String OOM_ADJ_REASON_ALLOWLIST = OOM_ADJ_REASON_METHOD + "_allowlistChange";
static final String OOM_ADJ_REASON_PROCESS_BEGIN = OOM_ADJ_REASON_METHOD + "_processBegin";
static final String OOM_ADJ_REASON_PROCESS_END = OOM_ADJ_REASON_METHOD + "_processEnd";
@@ -337,7 +337,7 @@ public final class OomAdjuster {
mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
mConstants = mService.mConstants;
mCachedAppOptimizer = new CachedAppOptimizer(mService);
- mCacheOomRanker = new CacheOomRanker();
+ mCacheOomRanker = new CacheOomRanker(service);
mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> {
final int pid = msg.arg1;
@@ -394,7 +394,7 @@ public final class OomAdjuster {
final ProcessRecord app = processes.get(i);
boolean includeWarmPkg = false;
for (int j = warmServices.size() - 1; j >= 0; j--) {
- if (app.pkgList.containsKey(warmServices.valueAt(j).getPackageName())) {
+ if (app.getPkgList().containsKey(warmServices.valueAt(j).getPackageName())) {
includeWarmPkg = true;
break;
}
@@ -422,7 +422,7 @@ public final class OomAdjuster {
if (oomAdjAll && mConstants.OOMADJ_UPDATE_QUICK) {
return updateOomAdjLocked(app, oomAdjReason);
}
- final ProcessRecord TOP_APP = mService.getTopAppLocked();
+ final ProcessRecord topApp = mService.getTopApp();
final boolean wasCached = app.isCached();
mAdjSeq++;
@@ -435,7 +435,7 @@ public final class OomAdjuster {
? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;
// Check if this process is in the pending list too, remove from pending list if so.
mPendingProcessSet.remove(app);
- boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
+ boolean success = updateOomAdjLocked(app, cachedAdj, topApp, false,
SystemClock.uptimeMillis());
if (oomAdjAll
&& (wasCached != app.isCached() || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
@@ -488,7 +488,7 @@ public final class OomAdjuster {
if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
&& (uidRec.setProcState != uidRec.getCurProcState()
|| uidRec.setCapability != uidRec.curCapability
- || uidRec.setWhitelist != uidRec.curWhitelist)) {
+ || uidRec.mSetAllowlist != uidRec.mCurAllowlist)) {
ActiveUids uids = mTmpUidRecords;
uids.clear();
uids.put(uidRec.uid, uidRec);
@@ -505,7 +505,7 @@ public final class OomAdjuster {
*/
@GuardedBy("mService")
void updateOomAdjLocked(String oomAdjReason) {
- final ProcessRecord topApp = mService.getTopAppLocked();
+ final ProcessRecord topApp = mService.getTopApp();
// Clear any pending ones because we are doing a full update now.
mPendingProcessSet.clear();
mService.mAppProfiler.mHasPreviousProcess = mService.mAppProfiler.mHasHomeProcess = false;
@@ -527,7 +527,7 @@ public final class OomAdjuster {
return true;
}
- final ProcessRecord topApp = mService.getTopAppLocked();
+ final ProcessRecord topApp = mService.getTopApp();
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
mService.mOomAdjProfiler.oomAdjStarted();
@@ -676,7 +676,7 @@ public final class OomAdjuster {
if (mPendingProcessSet.isEmpty()) {
return;
}
- final ProcessRecord topApp = mService.getTopAppLocked();
+ final ProcessRecord topApp = mService.getTopApp();
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
mService.mOomAdjProfiler.oomAdjStarted();
@@ -1112,19 +1112,19 @@ public final class OomAdjuster {
if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
&& (uidRec.setProcState != uidRec.getCurProcState()
|| uidRec.setCapability != uidRec.curCapability
- || uidRec.setWhitelist != uidRec.curWhitelist)) {
+ || uidRec.mSetAllowlist != uidRec.mCurAllowlist)) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
+ ": proc state from " + uidRec.setProcState + " to "
+ uidRec.getCurProcState() + ", capability from "
+ uidRec.setCapability + " to " + uidRec.curCapability
- + ", whitelist from " + uidRec.setWhitelist
- + " to " + uidRec.curWhitelist);
+ + ", allowlist from " + uidRec.mSetAllowlist
+ + " to " + uidRec.mCurAllowlist);
if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
- && !uidRec.curWhitelist) {
+ && !uidRec.mCurAllowlist) {
// UID is now in the background (and not on the temp allowlist). Was it
// previously in the foreground (or on the temp allowlist)?
if (!ActivityManager.isProcStateBackground(uidRec.setProcState)
- || uidRec.setWhitelist) {
+ || uidRec.mSetAllowlist) {
uidRec.lastBackgroundTime = nowElapsed;
if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
// Note: the background settle time is in elapsed realtime, while
@@ -1156,7 +1156,7 @@ public final class OomAdjuster {
}
uidRec.setProcState = uidRec.getCurProcState();
uidRec.setCapability = uidRec.curCapability;
- uidRec.setWhitelist = uidRec.curWhitelist;
+ uidRec.mSetAllowlist = uidRec.mCurAllowlist;
uidRec.setIdle = uidRec.idle;
mService.mAtmInternal.onUidProcStateChanged(uidRec.uid, uidRec.setProcState);
mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
@@ -1353,7 +1353,7 @@ public final class OomAdjuster {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- mService.reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app);
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app);
}
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
@@ -1379,7 +1379,7 @@ public final class OomAdjuster {
app.systemNoUi = false;
}
if (!app.systemNoUi) {
- if (mService.mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
+ if (mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE) {
// screen on, promote UI
app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
@@ -1912,7 +1912,7 @@ public final class OomAdjuster {
clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
app.bumpAllowStartFgsState(
PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
- } else if (mService.mWakefulness
+ } else if (mService.mWakefulness.get()
== PowerManagerInternal.WAKEFULNESS_AWAKE
&& (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
!= 0) {
@@ -2197,7 +2197,8 @@ public final class OomAdjuster {
// is large we want to force it down since we would prefer to
// keep launcher over it.
if (!mService.mAppProfiler.isLastMemoryLevelNormal()
- && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
+ && app.mProfile.getLastPss()
+ >= mProcessList.getCachedRestoreThresholdKb()) {
app.serviceHighRam = true;
app.serviceb = true;
//Slog.i(TAG, "ADJ " + app + " high ram!");
@@ -2228,7 +2229,7 @@ public final class OomAdjuster {
// Put bound foreground services in a special sched group for additional
// restrictions on screen off
if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
- && mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) {
+ && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE) {
if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
}
@@ -2324,11 +2325,13 @@ public final class OomAdjuster {
}
/** Inform the oomadj observer of changes to oomadj. Used by tests. */
- @GuardedBy("mService")
void reportOomAdjMessageLocked(String tag, String msg) {
Slog.d(tag, msg);
- if (mService.mCurOomAdjObserver != null) {
- mService.mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
+ synchronized (mService.mOomAdjObserverLock) {
+ if (mService.mCurOomAdjObserver != null) {
+ mService.mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg)
+ .sendToTarget();
+ }
}
}
@@ -2361,7 +2364,7 @@ public final class OomAdjuster {
&& app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
mCachedAppOptimizer.compactAppFull(app);
}
- } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
+ } else if (mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
&& app.setAdj < ProcessList.FOREGROUND_APP_ADJ
// Because these can fire independent of oom_adj/procstate changes, we need
// to throttle the actual dispatch of these requests in addition to the
@@ -2369,7 +2372,7 @@ public final class OomAdjuster {
// and in CachedAppOptimizer.
&& mCachedAppOptimizer.shouldCompactPersistent(app, now)) {
mCachedAppOptimizer.compactAppPersistent(app);
- } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
+ } else if (mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
&& app.getCurProcState()
== ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& mCachedAppOptimizer.shouldCompactBFGS(app, now)) {
@@ -2511,18 +2514,22 @@ public final class OomAdjuster {
}
}
}
+ boolean forceUpdatePssTime = false;
if (app.setProcState == PROCESS_STATE_NONEXISTENT
|| ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
app.lastStateTime = now;
- mService.mAppProfiler.updateNextPssTimeLocked(app.getCurProcState(), app, now, true);
+ forceUpdatePssTime = true;
if (DEBUG_PSS) {
Slog.d(TAG_PSS, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
+ ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
- + (app.nextPssTime - now) + ": " + app);
+ + (app.mProfile.getNextPssTime() - now) + ": " + app);
}
- } else {
- mService.mAppProfiler.updateNextPssTimeLocked(app.getCurProcState(), app, now, false);
+ }
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ app.mProfile.updateProcState(app);
+ mService.mAppProfiler.updateNextPssTimeLPf(
+ app.getCurProcState(), app.mProfile, now, forceUpdatePssTime);
}
if (app.setProcState != app.getCurProcState()) {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
@@ -2538,7 +2545,7 @@ public final class OomAdjuster {
// arbitrary amounts of battery power. Note its current CPU time to later know to
// kill it if it is not behaving well.
app.setWhenUnimportant(now);
- app.lastCpuTime = 0;
+ app.mProfile.mLastCpuTime.set(0);
}
// Inform UsageStats of important process state change
// Must be called before updating setProcState
@@ -2576,7 +2583,7 @@ public final class OomAdjuster {
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Changes in " + app + ": " + changes);
ActivityManagerService.ProcessChangeItem item =
- mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
+ mProcessList.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
item.changes |= changes;
item.foregroundActivities = app.repForegroundActivities;
item.capability = app.setCapability;
@@ -2730,27 +2737,27 @@ public final class OomAdjuster {
}
@GuardedBy("mService")
- final void setAppIdTempWhitelistStateLocked(int uid, boolean onWhitelist) {
+ void setAppIdTempAllowlistStateLocked(int uid, boolean onAllowlist) {
boolean changed = false;
for (int i = mActiveUids.size() - 1; i >= 0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
- if (uidRec.uid == uid && uidRec.curWhitelist != onWhitelist) {
- uidRec.curWhitelist = onWhitelist;
+ if (uidRec.uid == uid && uidRec.mCurAllowlist != onAllowlist) {
+ uidRec.mCurAllowlist = onAllowlist;
changed = true;
}
}
if (changed) {
- updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST);
+ updateOomAdjLocked(OOM_ADJ_REASON_ALLOWLIST);
}
}
@GuardedBy("mService")
- final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
+ void setUidTempAllowlistStateLocked(int uid, boolean onAllowlist) {
boolean changed = false;
final UidRecord uidRec = mActiveUids.get(uid);
- if (uidRec != null && uidRec.curWhitelist != onWhitelist) {
- uidRec.curWhitelist = onWhitelist;
- updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST);
+ if (uidRec != null && uidRec.mCurAllowlist != onAllowlist) {
+ uidRec.mCurAllowlist = onAllowlist;
+ updateOomAdjLocked(OOM_ADJ_REASON_ALLOWLIST);
}
}
diff --git a/services/core/java/com/android/server/am/PackageList.java b/services/core/java/com/android/server/am/PackageList.java
new file mode 100644
index 000000000000..978bcb7afee4
--- /dev/null
+++ b/services/core/java/com/android/server/am/PackageList.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.pm.VersionedPackage;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.procstats.ProcessStats;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * List of packages running in the process, self locked.
+ */
+final class PackageList {
+ private final ProcessRecord mProcess;
+
+ private final ArrayMap<String, ProcessStats.ProcessStateHolder> mPkgList = new ArrayMap<>();
+
+ PackageList(final ProcessRecord app) {
+ mProcess = app;
+ }
+
+ ProcessStats.ProcessStateHolder put(String key, ProcessStats.ProcessStateHolder value) {
+ synchronized (this) {
+ mProcess.getWindowProcessController().addPackage(key);
+ return mPkgList.put(key, value);
+ }
+ }
+
+ void clear() {
+ synchronized (this) {
+ mPkgList.clear();
+ mProcess.getWindowProcessController().clearPackageList();
+ }
+ }
+
+ int size() {
+ synchronized (this) {
+ return mPkgList.size();
+ }
+ }
+
+ boolean containsKey(Object key) {
+ synchronized (this) {
+ return mPkgList.containsKey(key);
+ }
+ }
+
+ ProcessStats.ProcessStateHolder get(String pkgName) {
+ synchronized (this) {
+ return mPkgList.get(pkgName);
+ }
+ }
+
+ void forEachPackage(Consumer<String> callback) {
+ synchronized (this) {
+ for (int i = 0, size = mPkgList.size(); i < size; i++) {
+ callback.accept(mPkgList.keyAt(i));
+ }
+ }
+ }
+
+ void forEachPackage(BiConsumer<String, ProcessStats.ProcessStateHolder> callback) {
+ synchronized (this) {
+ for (int i = 0, size = mPkgList.size(); i < size; i++) {
+ callback.accept(mPkgList.keyAt(i), mPkgList.valueAt(i));
+ }
+ }
+ }
+
+ <R> R forEachPackage(Function<String, R> callback) {
+ synchronized (this) {
+ for (int i = 0, size = mPkgList.size(); i < size; i++) {
+ R r = callback.apply(mPkgList.keyAt(i));
+ if (r != null) {
+ return r;
+ }
+ }
+ }
+ return null;
+ }
+
+ void forEachPackageProcessStats(Consumer<ProcessStats.ProcessStateHolder> callback) {
+ synchronized (this) {
+ for (int i = 0, size = mPkgList.size(); i < size; i++) {
+ callback.accept(mPkgList.valueAt(i));
+ }
+ }
+ }
+
+ @GuardedBy("this")
+ ArrayMap<String, ProcessStats.ProcessStateHolder> getPackageListLocked() {
+ return mPkgList;
+ }
+
+ String[] getPackageList() {
+ synchronized (this) {
+ int size = mPkgList.size();
+ if (size == 0) {
+ return null;
+ }
+ final String[] list = new String[size];
+ for (int i = 0; i < size; i++) {
+ list[i] = mPkgList.keyAt(i);
+ }
+ return list;
+ }
+ }
+
+ List<VersionedPackage> getPackageListWithVersionCode() {
+ synchronized (this) {
+ int size = mPkgList.size();
+ if (size == 0) {
+ return null;
+ }
+ List<VersionedPackage> list = new ArrayList<>();
+ for (int i = 0; i < size; i++) {
+ list.add(new VersionedPackage(mPkgList.keyAt(i), mPkgList.valueAt(i).appVersion));
+ }
+ return list;
+ }
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ synchronized (this) {
+ pw.print(prefix); pw.print("packageList={");
+ for (int i = 0, size = mPkgList.size(); i < size; i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(mPkgList.keyAt(i));
+ }
+ pw.println("}");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/PendingTempWhitelists.java b/services/core/java/com/android/server/am/PendingTempAllowlists.java
index 50d58f02baa7..75935c4f22fa 100644
--- a/services/core/java/com/android/server/am/PendingTempWhitelists.java
+++ b/services/core/java/com/android/server/am/PendingTempAllowlists.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -11,49 +11,49 @@
* 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.am;
import android.util.SparseArray;
-/** Whitelists of uids to temporarily bypass Power Save mode. */
-final class PendingTempWhitelists {
+/** Allowlists of uids to temporarily bypass Power Save mode. */
+final class PendingTempAllowlists {
private ActivityManagerService mService;
- private final SparseArray<ActivityManagerService.PendingTempWhitelist> mPendingTempWhitelist =
+ private final SparseArray<ActivityManagerService.PendingTempAllowlist> mPendingTempAllowlist =
new SparseArray<>();
- PendingTempWhitelists(ActivityManagerService service) {
+ PendingTempAllowlists(ActivityManagerService service) {
mService = service;
}
- void put(int uid, ActivityManagerService.PendingTempWhitelist value) {
- mPendingTempWhitelist.put(uid, value);
+ void put(int uid, ActivityManagerService.PendingTempAllowlist value) {
+ mPendingTempAllowlist.put(uid, value);
mService.mAtmInternal.onUidAddedToPendingTempAllowlist(uid, value.tag);
}
void removeAt(int index) {
- final int uid = mPendingTempWhitelist.keyAt(index);
- mPendingTempWhitelist.removeAt(index);
+ final int uid = mPendingTempAllowlist.keyAt(index);
+ mPendingTempAllowlist.removeAt(index);
mService.mAtmInternal.onUidRemovedFromPendingTempAllowlist(uid);
}
- ActivityManagerService.PendingTempWhitelist get(int uid) {
- return mPendingTempWhitelist.get(uid);
+ ActivityManagerService.PendingTempAllowlist get(int uid) {
+ return mPendingTempAllowlist.get(uid);
}
int size() {
- return mPendingTempWhitelist.size();
+ return mPendingTempAllowlist.size();
}
- ActivityManagerService.PendingTempWhitelist valueAt(int index) {
- return mPendingTempWhitelist.valueAt(index);
+ ActivityManagerService.PendingTempAllowlist valueAt(int index) {
+ return mPendingTempAllowlist.valueAt(index);
}
int indexOfKey(int key) {
- return mPendingTempWhitelist.indexOfKey(key);
+ return mPendingTempAllowlist.indexOfKey(key);
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2273779c2127..a768532a9260 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -34,10 +34,14 @@ import static android.os.Process.startWebView;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
+import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESS_DIED_UI_MSG;
import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_DELAY_MS;
import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_MSG;
import static com.android.server.am.ActivityManagerService.PERSISTENT_MASK;
@@ -59,6 +63,7 @@ import android.app.ApplicationExitInfo;
import android.app.ApplicationExitInfo.Reason;
import android.app.ApplicationExitInfo.SubReason;
import android.app.IApplicationThread;
+import android.app.IProcessObserver;
import android.app.IUidObserver;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
@@ -86,6 +91,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -97,18 +103,20 @@ import android.system.Os;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.EventLog;
import android.util.LongSparseArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ProcessMap;
-import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -117,6 +125,7 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerService.ProcessChangeItem;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -134,6 +143,8 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -145,6 +156,8 @@ import java.util.Set;
public final class ProcessList {
static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
+ static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
+
// A system property to control if app data isolation is enabled.
static final String ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
"persist.zygote.app_data_isolation";
@@ -416,7 +429,7 @@ public final class ProcessList {
private boolean mVoldAppDataIsolationEnabled = false;
- private ArrayList<String> mAppDataIsolationWhitelistedApps;
+ private ArrayList<String> mAppDataIsolationAllowlistedApps;
/**
* Temporary to avoid allocations. Protected by main lock.
@@ -643,6 +656,25 @@ public final class ProcessList {
*/
final ArrayList<ProcessRecord> mRemovedProcesses = new ArrayList<ProcessRecord>();
+ // Self locked with the inner lock within the RemoteCallbackList
+ private final RemoteCallbackList<IProcessObserver> mProcessObservers =
+ new RemoteCallbackList<>();
+
+ // No lock is needed as it's accessed from single thread only
+ private ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
+
+ @GuardedBy("mProcessChangeLock")
+ private final ArrayList<ProcessChangeItem> mPendingProcessChanges = new ArrayList<>();
+
+ @GuardedBy("mProcessChangeLock")
+ final ArrayList<ProcessChangeItem> mAvailProcessChanges = new ArrayList<>();
+
+ /**
+ * A dedicated lock for dispatching the process changes as it occurs frequently
+ */
+ private final Object mProcessChangeLock = new Object();
+
+
/**
* All of the applications we currently have running organized by name.
* The keys are strings of the application package name (as
@@ -723,7 +755,7 @@ public final class ProcessList {
SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
- mAppDataIsolationWhitelistedApps = new ArrayList<>(
+ mAppDataIsolationAllowlistedApps = new ArrayList<>(
SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
if (sKillHandler == null) {
@@ -1523,47 +1555,34 @@ public final class ProcessList {
ProcessRecord proc = mProcessNames.get(processName, uid);
if (false && proc != null && !keepIfLarge
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
- && proc.lastCachedPss >= 4000) {
+ && proc.mProfile.getLastCachedPss() >= 4000) {
// Turn this condition on to cause killing to happen regularly, for testing.
- synchronized (mService.mProcessStats.mLock) {
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(
- proc.pkgList.mPkgList, proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
- }
- }
+ final long lastCachedPss;
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ proc.mProfile.reportCachedKill();
+ lastCachedPss = proc.mProfile.getLastCachedPss();
}
- proc.kill(Long.toString(proc.lastCachedPss) + "k from cached",
+ proc.kill(Long.toString(lastCachedPss) + "k from cached",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_LARGE_CACHED,
true);
} else if (proc != null && !keepIfLarge
&& !mService.mAppProfiler.isLastMemoryLevelNormal()
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
- if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc
- .lastCachedPss);
- if (proc.lastCachedPss >= getCachedRestoreThresholdKb()) {
- synchronized (mService.mProcessStats.mLock) {
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList,
- proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
- }
- }
+ final long lastCachedPss;
+ boolean doKilling = false;
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ lastCachedPss = proc.mProfile.getLastCachedPss();
+ if (lastCachedPss >= getCachedRestoreThresholdKb()) {
+ proc.mProfile.reportCachedKill();
+ doKilling = true;
}
- proc.kill(Long.toString(proc.lastCachedPss) + "k from cached",
+ }
+ if (DEBUG_PSS) {
+ Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + lastCachedPss);
+ }
+ if (doKilling) {
+ proc.kill(Long.toString(lastCachedPss) + "k from cached",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_LARGE_CACHED,
true);
@@ -1770,7 +1789,7 @@ public final class ProcessList {
mService.mProcessesOnHold.remove(app);
checkSlow(startTime, "startProcess: starting to update cpu stats");
- mService.updateCpuStatsLocked();
+ mService.updateCpuStats();
checkSlow(startTime, "startProcess: done updating cpu stats");
try {
@@ -1873,10 +1892,16 @@ public final class ProcessList {
mService.mNativeDebuggingApp = null;
}
- if (app.info.isEmbeddedDexUsed()
- || (app.info.isPrivilegedApp()
- && DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet()))) {
+ if (app.info.isEmbeddedDexUsed()) {
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
+ } else if (app.info.isPrivilegedApp()) {
+ final PackageList pkgList = app.getPkgList();
+ synchronized (pkgList) {
+ if (DexManager.isPackageSelectedToRunOob(
+ pkgList.getPackageListLocked().keySet())) {
+ runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
+ }
+ }
}
if (!disableHiddenApiChecks && !mService.mHiddenApiBlacklist.isDisabled()) {
@@ -2240,7 +2265,7 @@ public final class ProcessList {
}
Map<String, Pair<String, Long>> pkgDataInfoMap;
- Map<String, Pair<String, Long>> whitelistedAppDataInfoMap;
+ Map<String, Pair<String, Long>> allowlistedAppDataInfoMap;
boolean bindMountAppStorageDirs = false;
boolean bindMountAppsData = mAppDataIsolationEnabled
&& (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid))
@@ -2248,7 +2273,7 @@ public final class ProcessList {
// Get all packages belongs to the same shared uid. sharedPackages is empty array
// if it doesn't have shared uid.
- final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
+ final PackageManagerInternal pmInt = mService.getPackageManagerInternal();
final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
app.info.packageName, app.userId);
final String[] targetPackagesList = sharedPackages.length == 0
@@ -2261,16 +2286,16 @@ public final class ProcessList {
bindMountAppsData = false;
}
- // Remove all packages in pkgDataInfoMap from mAppDataIsolationWhitelistedApps, so
+ // Remove all packages in pkgDataInfoMap from mAppDataIsolationAllowlistedApps, so
// it won't be mounted twice.
- final Set<String> whitelistedApps = new ArraySet<>(mAppDataIsolationWhitelistedApps);
+ final Set<String> allowlistedApps = new ArraySet<>(mAppDataIsolationAllowlistedApps);
for (String pkg : targetPackagesList) {
- whitelistedApps.remove(pkg);
+ allowlistedApps.remove(pkg);
}
- whitelistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
- whitelistedApps.toArray(new String[0]), uid);
- if (whitelistedAppDataInfoMap == null) {
+ allowlistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
+ allowlistedApps.toArray(new String[0]), uid);
+ if (allowlistedAppDataInfoMap == null) {
// TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
// tmp free pass.
bindMountAppsData = false;
@@ -2295,7 +2320,7 @@ public final class ProcessList {
// since it has no access to them anyway.
if (app.isolated) {
pkgDataInfoMap = null;
- whitelistedAppDataInfoMap = null;
+ allowlistedAppDataInfoMap = null;
}
final Process.ProcessStartResult startResult;
@@ -2314,7 +2339,7 @@ public final class ProcessList {
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
- app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
+ app.mDisabledCompatChanges, pkgDataInfoMap, allowlistedAppDataInfoMap,
false, false,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
@@ -2323,7 +2348,7 @@ public final class ProcessList {
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
- whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
+ allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
}
checkSlow(startTime, "startProcess: returned from zygote!");
@@ -2373,7 +2398,7 @@ public final class ProcessList {
// if it had been bad.
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + processName);
- mService.mAppErrors.resetProcessCrashTimeLocked(processName, info.uid);
+ mService.mAppErrors.resetProcessCrashTime(processName, info.uid);
if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
@@ -2421,7 +2446,7 @@ public final class ProcessList {
if (!app.killed
|| mService.mAppProfiler.isLastMemoryLevelNormal()
|| app.setProcState < ActivityManager.PROCESS_STATE_CACHED_EMPTY
- || app.lastCachedPss < getCachedRestoreThresholdKb()) {
+ || app.mProfile.getLastCachedPss() < getCachedRestoreThresholdKb()) {
// Throw a wtf if it's not killed, or killed but not because the system was in
// memory pressure + the app was in "cch-empty" and used large amount of memory
Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process");
@@ -2736,7 +2761,7 @@ public final class ProcessList {
if (userId != UserHandle.USER_ALL && app.userId != userId) {
continue;
}
- if (!app.pkgList.containsKey(packageName) && !isDep) {
+ if (!app.getPkgList().containsKey(packageName) && !isDep) {
continue;
}
}
@@ -2797,7 +2822,7 @@ public final class ProcessList {
mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
mService.mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
- mService.getPackageManagerInternalLocked().removeIsolatedUid(app.uid);
+ mService.getPackageManagerInternal().removeIsolatedUid(app.uid);
}
}
boolean willRestart = false;
@@ -2847,10 +2872,10 @@ public final class ProcessList {
// This is the first appearance of the uid, report it now!
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Creating new process uid: " + uidRec);
- if (Arrays.binarySearch(mService.mDeviceIdleTempWhitelist,
+ if (Arrays.binarySearch(mService.mDeviceIdleTempAllowlist,
UserHandle.getAppId(proc.uid)) >= 0
- || mService.mPendingTempWhitelist.indexOfKey(proc.uid) >= 0) {
- uidRec.setWhitelist = uidRec.curWhitelist = true;
+ || mService.mPendingTempAllowlist.indexOfKey(proc.uid) >= 0) {
+ uidRec.mSetAllowlist = uidRec.mCurAllowlist = true;
}
uidRec.updateHasInternetPermission();
mActiveUids.put(proc.uid, uidRec);
@@ -2904,7 +2929,7 @@ public final class ProcessList {
uid = isolatedUid;
}
mAppExitInfoTracker.mIsolatedUidRecords.addIsolatedUid(uid, info.uid);
- mService.getPackageManagerInternalLocked().addIsolatedUid(uid, info.uid);
+ mService.getPackageManagerInternal().addIsolatedUid(uid, info.uid);
// Register the isolated UID with this application so BatteryStats knows to
// attribute resource usage to the application.
@@ -2964,6 +2989,7 @@ public final class ProcessList {
UidRecord.CHANGE_GONE);
EventLogTags.writeAmUidStopped(uid);
mActiveUids.remove(uid);
+ mService.mFgsStartTempAllowList.remove(record.info.uid);
mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT,
ActivityManager.PROCESS_CAPABILITY_NONE);
}
@@ -3582,14 +3608,14 @@ public final class ProcessList {
if (app.hasActivities()) {
outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES;
}
- outInfo.lastTrimLevel = app.trimMemoryLevel;
+ outInfo.lastTrimLevel = app.mProfile.getTrimMemoryLevel();
int adj = app.curAdj;
int procState = app.getCurProcState();
outInfo.importance = procStateToImportance(procState, adj, outInfo,
clientTargetSdk);
outInfo.importanceReasonCode = app.adjTypeCode;
outInfo.processState = app.getCurProcState();
- outInfo.isFocused = (app == mService.getTopAppLocked());
+ outInfo.isFocused = (app == mService.getTopApp());
outInfo.lastActivityTime = app.lastActivityTime;
}
@@ -3653,6 +3679,729 @@ public final class ProcessList {
pw.println("):");
}
+ void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc, String prefix) {
+ pw.print(prefix);
+ pw.print('#');
+ if (index < 10) {
+ pw.print(' ');
+ }
+ pw.print(index);
+ pw.print(": ");
+ pw.print(makeOomAdjString(proc.setAdj, false));
+ pw.print(' ');
+ pw.print(makeProcStateString(proc.getCurProcState()));
+ pw.print(' ');
+ ActivityManager.printCapabilitiesSummary(pw, proc.curCapability);
+ pw.print(' ');
+ pw.print(proc.toShortString());
+ if (proc.hasActivitiesOrRecentTasks() || proc.hasClientActivities()
+ || proc.treatLikeActivity) {
+ pw.print(" act:");
+ boolean printed = false;
+ if (proc.hasActivities()) {
+ pw.print("activities");
+ printed = true;
+ }
+ if (proc.hasRecentTasks()) {
+ if (printed) {
+ pw.print("|");
+ }
+ pw.print("recents");
+ printed = true;
+ }
+ if (proc.hasClientActivities()) {
+ if (printed) {
+ pw.print("|");
+ }
+ pw.print("client");
+ printed = true;
+ }
+ if (proc.treatLikeActivity) {
+ if (printed) {
+ pw.print("|");
+ }
+ pw.print("treated");
+ }
+ }
+ pw.println();
+ }
+
+ boolean dumpLruLocked(PrintWriter pw, String dumpPackage, String prefix) {
+ final int lruSize = mLruProcesses.size();
+ final String innerPrefix;
+ if (prefix == null) {
+ pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)");
+ innerPrefix = " ";
+ } else {
+ boolean haveAny = false;
+ for (int i = lruSize - 1; i >= 0; i--) {
+ final ProcessRecord r = mLruProcesses.get(i);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ haveAny = true;
+ break;
+ }
+ if (!haveAny) {
+ return false;
+ }
+ pw.print(prefix);
+ pw.println("Raw LRU list (dumpsys activity lru):");
+ innerPrefix = prefix + " ";
+ }
+ int i;
+ boolean first = true;
+ for (i = lruSize - 1; i >= mLruProcessActivityStart; i--) {
+ final ProcessRecord r = mLruProcesses.get(i);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ if (first) {
+ pw.print(innerPrefix);
+ pw.println("Activities:");
+ first = false;
+ }
+ dumpLruEntryLocked(pw, i, r, innerPrefix);
+ }
+ first = true;
+ for (; i >= mLruProcessServiceStart; i--) {
+ final ProcessRecord r = mLruProcesses.get(i);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ if (first) {
+ pw.print(innerPrefix);
+ pw.println("Services:");
+ first = false;
+ }
+ dumpLruEntryLocked(pw, i, r, innerPrefix);
+ }
+ first = true;
+ for (; i >= 0; i--) {
+ final ProcessRecord r = mLruProcesses.get(i);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ if (first) {
+ pw.print(innerPrefix);
+ pw.println("Other:");
+ first = false;
+ }
+ dumpLruEntryLocked(pw, i, r, innerPrefix);
+ }
+ return true;
+ }
+
+ @GuardedBy("mService")
+ void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
+ boolean needSep = false;
+ int numPers = 0;
+
+ pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
+
+ if (dumpAll || dumpPackage != null) {
+ final int numOfNames = mProcessNames.getMap().size();
+ for (int ip = 0; ip < numOfNames; ip++) {
+ SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip);
+ for (int ia = 0, size = procs.size(); ia < size; ia++) {
+ ProcessRecord r = procs.valueAt(ia);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ if (!needSep) {
+ pw.println(" All known processes:");
+ needSep = true;
+ }
+ pw.print(r.isPersistent() ? " *PERS*" : " *APP*");
+ pw.print(" UID "); pw.print(procs.keyAt(ia));
+ pw.print(" "); pw.println(r);
+ r.dump(pw, " ");
+ if (r.isPersistent()) {
+ numPers++;
+ }
+ }
+ }
+ }
+
+ if (mIsolatedProcesses.size() > 0) {
+ boolean printed = false;
+ for (int i = 0, size = mIsolatedProcesses.size(); i < size; i++) {
+ ProcessRecord r = mIsolatedProcesses.valueAt(i);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ pw.println(" Isolated process list (sorted by uid):");
+ printed = true;
+ needSep = true;
+ }
+ pw.print(" Isolated #"); pw.print(i); pw.print(": ");
+ pw.println(r);
+ }
+ }
+
+ needSep = mService.dumpActiveInstruments(pw, dumpPackage, needSep);
+
+ if (dumpOomLocked(fd, pw, needSep, args, opti, dumpAll, dumpPackage, false)) {
+ needSep = true;
+ }
+
+ if (mActiveUids.size() > 0) {
+ needSep |= mActiveUids.dump(pw, dumpPackage, dumpAppId,
+ "UID states:", needSep);
+ }
+
+ if (dumpAll) {
+ needSep |= mService.mUidObserverController.dumpValidateUids(pw,
+ dumpPackage, dumpAppId, "UID validation:", needSep);
+ }
+
+ if (needSep) {
+ pw.println();
+ }
+ if (dumpLruLocked(pw, dumpPackage, " ")) {
+ needSep = true;
+ }
+
+ if (getLruSizeLocked() > 0) {
+ if (needSep) {
+ pw.println();
+ }
+ dumpLruListHeaderLocked(pw);
+ dumpProcessOomList(pw, mService, mLruProcesses, " ", "Proc", "PERS", false,
+ dumpPackage);
+ needSep = true;
+ }
+
+ mService.dumpOtherProcessesInfoLocked(fd, pw, dumpAll, dumpPackage, dumpAppId, numPers,
+ needSep);
+ }
+
+ @GuardedBy("this")
+ void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) {
+ int numPers = 0;
+
+ final int numOfNames = mProcessNames.getMap().size();
+ for (int ip = 0; ip < numOfNames; ip++) {
+ SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip);
+ for (int ia = 0, size = procs.size(); ia < size; ia++) {
+ ProcessRecord r = procs.valueAt(ia);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.PROCS,
+ mLruProcesses.indexOf(r)
+ );
+ if (r.isPersistent()) {
+ numPers++;
+ }
+ }
+ }
+
+ for (int i = 0, size = mIsolatedProcesses.size(); i < size; i++) {
+ ProcessRecord r = mIsolatedProcesses.valueAt(i);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS,
+ mLruProcesses.indexOf(r)
+ );
+ }
+
+ final int dumpAppId = mService.getAppId(dumpPackage);
+ mActiveUids.dumpProto(proto, dumpPackage, dumpAppId,
+ ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
+
+ if (getLruSizeLocked() > 0) {
+ long lruToken = proto.start(ActivityManagerServiceDumpProcessesProto.LRU_PROCS);
+ int total = getLruSizeLocked();
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.SIZE, total);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_ACT_AT,
+ total - mLruProcessActivityStart);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_SVC_AT,
+ total - mLruProcessServiceStart);
+ writeProcessOomListToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.LruProcesses.LIST, mService,
+ mLruProcesses, false, dumpPackage);
+ proto.end(lruToken);
+ }
+
+ mService.writeOtherProcessesInfoToProtoLocked(proto, dumpPackage, dumpAppId, numPers);
+ }
+
+ private static ArrayList<Pair<ProcessRecord, Integer>> sortProcessOomList(
+ List<ProcessRecord> origList, String dumpPackage) {
+ ArrayList<Pair<ProcessRecord, Integer>> list =
+ new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
+ for (int i = 0, size = origList.size(); i < size; i++) {
+ ProcessRecord r = origList.get(i);
+ if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) {
+ continue;
+ }
+ list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i));
+ }
+
+ Comparator<Pair<ProcessRecord, Integer>> comparator =
+ new Comparator<Pair<ProcessRecord, Integer>>() {
+ @Override
+ public int compare(Pair<ProcessRecord, Integer> object1,
+ Pair<ProcessRecord, Integer> object2) {
+ if (object1.first.setAdj != object2.first.setAdj) {
+ return object1.first.setAdj > object2.first.setAdj ? -1 : 1;
+ }
+ if (object1.first.setProcState != object2.first.setProcState) {
+ return object1.first.setProcState > object2.first.setProcState ? -1 : 1;
+ }
+ if (object1.second.intValue() != object2.second.intValue()) {
+ return object1.second.intValue() > object2.second.intValue() ? -1 : 1;
+ }
+ return 0;
+ }
+ };
+
+ Collections.sort(list, comparator);
+ return list;
+ }
+
+ private static boolean writeProcessOomListToProto(ProtoOutputStream proto, long fieldId,
+ ActivityManagerService service, List<ProcessRecord> origList,
+ boolean inclDetails, String dumpPackage) {
+ ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
+ if (list.isEmpty()) return false;
+
+ final long curUptime = SystemClock.uptimeMillis();
+
+ for (int i = list.size() - 1; i >= 0; i--) {
+ ProcessRecord r = list.get(i).first;
+ long token = proto.start(fieldId);
+ String oomAdj = makeOomAdjString(r.setAdj, true);
+ proto.write(ProcessOomProto.PERSISTENT, r.isPersistent());
+ proto.write(ProcessOomProto.NUM, (origList.size() - 1) - list.get(i).second);
+ proto.write(ProcessOomProto.OOM_ADJ, oomAdj);
+ int schedGroup = ProcessOomProto.SCHED_GROUP_UNKNOWN;
+ switch (r.setSchedGroup) {
+ case SCHED_GROUP_BACKGROUND:
+ schedGroup = ProcessOomProto.SCHED_GROUP_BACKGROUND;
+ break;
+ case SCHED_GROUP_DEFAULT:
+ schedGroup = ProcessOomProto.SCHED_GROUP_DEFAULT;
+ break;
+ case SCHED_GROUP_TOP_APP:
+ schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP;
+ break;
+ case SCHED_GROUP_TOP_APP_BOUND:
+ schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP_BOUND;
+ break;
+ }
+ if (schedGroup != ProcessOomProto.SCHED_GROUP_UNKNOWN) {
+ proto.write(ProcessOomProto.SCHED_GROUP, schedGroup);
+ }
+ if (r.hasForegroundActivities()) {
+ proto.write(ProcessOomProto.ACTIVITIES, true);
+ } else if (r.hasForegroundServices()) {
+ proto.write(ProcessOomProto.SERVICES, true);
+ }
+ proto.write(ProcessOomProto.STATE,
+ makeProcStateProtoEnum(r.getCurProcState()));
+ proto.write(ProcessOomProto.TRIM_MEMORY_LEVEL, r.mProfile.getTrimMemoryLevel());
+ r.dumpDebug(proto, ProcessOomProto.PROC);
+ proto.write(ProcessOomProto.ADJ_TYPE, r.adjType);
+ if (r.adjSource != null || r.adjTarget != null) {
+ if (r.adjTarget instanceof ComponentName) {
+ ComponentName cn = (ComponentName) r.adjTarget;
+ cn.dumpDebug(proto, ProcessOomProto.ADJ_TARGET_COMPONENT_NAME);
+ } else if (r.adjTarget != null) {
+ proto.write(ProcessOomProto.ADJ_TARGET_OBJECT, r.adjTarget.toString());
+ }
+ if (r.adjSource instanceof ProcessRecord) {
+ ProcessRecord p = (ProcessRecord) r.adjSource;
+ p.dumpDebug(proto, ProcessOomProto.ADJ_SOURCE_PROC);
+ } else if (r.adjSource != null) {
+ proto.write(ProcessOomProto.ADJ_SOURCE_OBJECT, r.adjSource.toString());
+ }
+ }
+ if (inclDetails) {
+ long detailToken = proto.start(ProcessOomProto.DETAIL);
+ proto.write(ProcessOomProto.Detail.MAX_ADJ, r.maxAdj);
+ proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, r.getCurRawAdj());
+ proto.write(ProcessOomProto.Detail.SET_RAW_ADJ, r.setRawAdj);
+ proto.write(ProcessOomProto.Detail.CUR_ADJ, r.curAdj);
+ proto.write(ProcessOomProto.Detail.SET_ADJ, r.setAdj);
+ proto.write(ProcessOomProto.Detail.CURRENT_STATE,
+ makeProcStateProtoEnum(r.getCurProcState()));
+ proto.write(ProcessOomProto.Detail.SET_STATE,
+ makeProcStateProtoEnum(r.setProcState));
+ proto.write(ProcessOomProto.Detail.LAST_PSS, DebugUtils.sizeValueToString(
+ r.mProfile.getLastPss() * 1024, new StringBuilder()));
+ proto.write(ProcessOomProto.Detail.LAST_SWAP_PSS, DebugUtils.sizeValueToString(
+ r.mProfile.getLastSwapPss() * 1024, new StringBuilder()));
+ proto.write(ProcessOomProto.Detail.LAST_CACHED_PSS, DebugUtils.sizeValueToString(
+ r.mProfile.getLastCachedPss() * 1024, new StringBuilder()));
+ proto.write(ProcessOomProto.Detail.CACHED, r.isCached());
+ proto.write(ProcessOomProto.Detail.EMPTY, r.empty);
+ proto.write(ProcessOomProto.Detail.HAS_ABOVE_CLIENT, r.hasAboveClient);
+
+ if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
+ long lastCpuTime = r.mProfile.mLastCpuTime.get();
+ if (lastCpuTime != 0) {
+ long uptimeSince = curUptime - service.mLastPowerCheckUptime;
+ long timeUsed = r.mProfile.mCurCpuTime.get() - lastCpuTime;
+ long cpuTimeToken = proto.start(ProcessOomProto.Detail.SERVICE_RUN_TIME);
+ proto.write(ProcessOomProto.Detail.CpuRunTime.OVER_MS, uptimeSince);
+ proto.write(ProcessOomProto.Detail.CpuRunTime.USED_MS, timeUsed);
+ proto.write(ProcessOomProto.Detail.CpuRunTime.ULTILIZATION,
+ (100.0 * timeUsed) / uptimeSince);
+ proto.end(cpuTimeToken);
+ }
+ }
+ proto.end(detailToken);
+ }
+ proto.end(token);
+ }
+
+ return true;
+ }
+
+ private static boolean dumpProcessOomList(PrintWriter pw,
+ ActivityManagerService service, List<ProcessRecord> origList,
+ String prefix, String normalLabel, String persistentLabel,
+ boolean inclDetails, String dumpPackage) {
+
+ ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
+ if (list.isEmpty()) return false;
+
+ final long curUptime = SystemClock.uptimeMillis();
+ final long uptimeSince = curUptime - service.mLastPowerCheckUptime;
+
+ for (int i = list.size() - 1; i >= 0; i--) {
+ ProcessRecord r = list.get(i).first;
+ String oomAdj = makeOomAdjString(r.setAdj, false);
+ char schedGroup;
+ switch (r.setSchedGroup) {
+ case SCHED_GROUP_BACKGROUND:
+ schedGroup = 'b';
+ break;
+ case SCHED_GROUP_DEFAULT:
+ schedGroup = 'F';
+ break;
+ case SCHED_GROUP_TOP_APP:
+ schedGroup = 'T';
+ break;
+ case SCHED_GROUP_RESTRICTED:
+ schedGroup = 'R';
+ break;
+ case SCHED_GROUP_TOP_APP_BOUND:
+ schedGroup = 'B';
+ break;
+ default:
+ schedGroup = '?';
+ break;
+ }
+ char foreground;
+ if (r.hasForegroundActivities()) {
+ foreground = 'A';
+ } else if (r.hasForegroundServices()) {
+ foreground = 'S';
+ } else {
+ foreground = ' ';
+ }
+ String procState = makeProcStateString(r.getCurProcState());
+ pw.print(prefix);
+ pw.print(r.isPersistent() ? persistentLabel : normalLabel);
+ pw.print(" #");
+ int num = (origList.size() - 1) - list.get(i).second;
+ if (num < 10) pw.print(' ');
+ pw.print(num);
+ pw.print(": ");
+ pw.print(oomAdj);
+ pw.print(' ');
+ pw.print(schedGroup);
+ pw.print('/');
+ pw.print(foreground);
+ pw.print('/');
+ pw.print(procState);
+ pw.print(' ');
+ ActivityManager.printCapabilitiesSummary(pw, r.curCapability);
+ pw.print(' ');
+ pw.print(" t:");
+ if (r.mProfile.getTrimMemoryLevel() < 10) pw.print(' ');
+ pw.print(r.mProfile.getTrimMemoryLevel());
+ pw.print(' ');
+ pw.print(r.toShortString());
+ pw.print(" (");
+ pw.print(r.adjType);
+ pw.println(')');
+ if (r.adjSource != null || r.adjTarget != null) {
+ pw.print(prefix);
+ pw.print(" ");
+ if (r.adjTarget instanceof ComponentName) {
+ pw.print(((ComponentName) r.adjTarget).flattenToShortString());
+ } else if (r.adjTarget != null) {
+ pw.print(r.adjTarget.toString());
+ } else {
+ pw.print("{null}");
+ }
+ pw.print("<=");
+ if (r.adjSource instanceof ProcessRecord) {
+ pw.print("Proc{");
+ pw.print(((ProcessRecord) r.adjSource).toShortString());
+ pw.println("}");
+ } else if (r.adjSource != null) {
+ pw.println(r.adjSource.toString());
+ } else {
+ pw.println("{null}");
+ }
+ }
+ if (inclDetails) {
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print("oom: max="); pw.print(r.maxAdj);
+ pw.print(" curRaw="); pw.print(r.getCurRawAdj());
+ pw.print(" setRaw="); pw.print(r.setRawAdj);
+ pw.print(" cur="); pw.print(r.curAdj);
+ pw.print(" set="); pw.println(r.setAdj);
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print("state: cur="); pw.print(
+ makeProcStateString(r.getCurProcState()));
+ pw.print(" set="); pw.print(makeProcStateString(r.setProcState));
+ pw.print(" lastPss=");
+ DebugUtils.printSizeValue(pw, r.mProfile.getLastPss() * 1024);
+ pw.print(" lastSwapPss=");
+ DebugUtils.printSizeValue(pw, r.mProfile.getLastSwapPss() * 1024);
+ pw.print(" lastCachedPss=");
+ DebugUtils.printSizeValue(pw, r.mProfile.getLastCachedPss() * 1024);
+ pw.println();
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print("cached="); pw.print(r.isCached());
+ pw.print(" empty="); pw.print(r.empty);
+ pw.print(" hasAboveClient="); pw.println(r.hasAboveClient);
+
+ if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
+ long lastCpuTime = r.mProfile.mLastCpuTime.get();
+ if (lastCpuTime != 0) {
+ long timeUsed = r.mProfile.mCurCpuTime.get() - lastCpuTime;
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print("run cpu over ");
+ TimeUtils.formatDuration(uptimeSince, pw);
+ pw.print(" used ");
+ TimeUtils.formatDuration(timeUsed, pw);
+ pw.print(" (");
+ pw.print((timeUsed * 100) / uptimeSince);
+ pw.println("%)");
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ private void printOomLevel(PrintWriter pw, String name, int adj) {
+ pw.print(" ");
+ if (adj >= 0) {
+ pw.print(' ');
+ if (adj < 10) pw.print(' ');
+ } else {
+ if (adj > -10) pw.print(' ');
+ }
+ pw.print(adj);
+ pw.print(": ");
+ pw.print(name);
+ pw.print(" (");
+ pw.print(ActivityManagerService.stringifySize(getMemLevel(adj), 1024));
+ pw.println(")");
+ }
+
+ boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String[] args,
+ int opti, boolean dumpAll, String dumpPackage, boolean inclGc) {
+ if (getLruSizeLocked() > 0) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" OOM levels:");
+ printOomLevel(pw, "SYSTEM_ADJ", SYSTEM_ADJ);
+ printOomLevel(pw, "PERSISTENT_PROC_ADJ", PERSISTENT_PROC_ADJ);
+ printOomLevel(pw, "PERSISTENT_SERVICE_ADJ", PERSISTENT_SERVICE_ADJ);
+ printOomLevel(pw, "FOREGROUND_APP_ADJ", FOREGROUND_APP_ADJ);
+ printOomLevel(pw, "VISIBLE_APP_ADJ", VISIBLE_APP_ADJ);
+ printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", PERCEPTIBLE_APP_ADJ);
+ printOomLevel(pw, "PERCEPTIBLE_LOW_APP_ADJ", PERCEPTIBLE_LOW_APP_ADJ);
+ printOomLevel(pw, "BACKUP_APP_ADJ", BACKUP_APP_ADJ);
+ printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", HEAVY_WEIGHT_APP_ADJ);
+ printOomLevel(pw, "SERVICE_ADJ", SERVICE_ADJ);
+ printOomLevel(pw, "HOME_APP_ADJ", HOME_APP_ADJ);
+ printOomLevel(pw, "PREVIOUS_APP_ADJ", PREVIOUS_APP_ADJ);
+ printOomLevel(pw, "SERVICE_B_ADJ", SERVICE_B_ADJ);
+ printOomLevel(pw, "CACHED_APP_MIN_ADJ", CACHED_APP_MIN_ADJ);
+ printOomLevel(pw, "CACHED_APP_MAX_ADJ", CACHED_APP_MAX_ADJ);
+
+ if (needSep) pw.println();
+ pw.print(" Process OOM control ("); pw.print(getLruSizeLocked());
+ pw.print(" total, non-act at ");
+ pw.print(getLruSizeLocked() - mLruProcessActivityStart);
+ pw.print(", non-svc at ");
+ pw.print(getLruSizeLocked() - mLruProcessServiceStart);
+ pw.println("):");
+ dumpProcessOomList(pw, mService, mLruProcesses, " ", "Proc", "PERS", true,
+ dumpPackage);
+ needSep = true;
+ }
+
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ mService.mAppProfiler.dumpProcessesToGc(pw, needSep, dumpPackage);
+ }
+
+ pw.println();
+ mService.mAtmInternal.dumpForOom(pw);
+
+ return true;
+ }
+
+ void registerProcessObserver(IProcessObserver observer) {
+ mProcessObservers.register(observer);
+ }
+
+ void unregisterProcessObserver(IProcessObserver observer) {
+ mProcessObservers.unregister(observer);
+ }
+
+ void dispatchProcessesChanged() {
+ int numOfChanges;
+ synchronized (mProcessChangeLock) {
+ numOfChanges = mPendingProcessChanges.size();
+ if (mActiveProcessChanges.length < numOfChanges) {
+ mActiveProcessChanges = new ProcessChangeItem[numOfChanges];
+ }
+ mPendingProcessChanges.toArray(mActiveProcessChanges);
+ mPendingProcessChanges.clear();
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS,
+ "*** Delivering " + numOfChanges + " process changes");
+ }
+ }
+
+ int i = mProcessObservers.beginBroadcast();
+ while (i > 0) {
+ i--;
+ final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
+ if (observer != null) {
+ try {
+ for (int j = 0; j < numOfChanges; j++) {
+ ProcessChangeItem item = mActiveProcessChanges[j];
+ if ((item.changes & ProcessChangeItem.CHANGE_ACTIVITIES) != 0) {
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS,
+ "ACTIVITIES CHANGED pid=" + item.pid + " uid="
+ + item.uid + ": " + item.foregroundActivities);
+ }
+ observer.onForegroundActivitiesChanged(item.pid, item.uid,
+ item.foregroundActivities);
+ }
+ if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) {
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS,
+ "FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid="
+ + item.uid + ": " + item.foregroundServiceTypes);
+ }
+ observer.onForegroundServicesChanged(item.pid, item.uid,
+ item.foregroundServiceTypes);
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mProcessObservers.finishBroadcast();
+
+ synchronized (mProcessChangeLock) {
+ for (int j = 0; j < numOfChanges; j++) {
+ mAvailProcessChanges.add(mActiveProcessChanges[j]);
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ ProcessChangeItem enqueueProcessChangeItemLocked(int pid, int uid) {
+ synchronized (mProcessChangeLock) {
+ int i = mPendingProcessChanges.size() - 1;
+ ActivityManagerService.ProcessChangeItem item = null;
+ while (i >= 0) {
+ item = mPendingProcessChanges.get(i);
+ if (item.pid == pid) {
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "Re-using existing item: " + item);
+ }
+ break;
+ }
+ i--;
+ }
+
+ if (i < 0) {
+ // No existing item in pending changes; need a new one.
+ final int num = mAvailProcessChanges.size();
+ if (num > 0) {
+ item = mAvailProcessChanges.remove(num - 1);
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "Retrieving available item: " + item);
+ }
+ } else {
+ item = new ActivityManagerService.ProcessChangeItem();
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "Allocating new item: " + item);
+ }
+ }
+ item.changes = 0;
+ item.pid = pid;
+ item.uid = uid;
+ if (mPendingProcessChanges.size() == 0) {
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "*** Enqueueing dispatch processes changed!");
+ }
+ mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
+ .sendToTarget();
+ }
+ mPendingProcessChanges.add(item);
+ }
+
+ return item;
+ }
+ }
+
+ @GuardedBy("mService")
+ void scheduleDispatchProcessDiedLocked(int pid, int uid) {
+ synchronized (mProcessChangeLock) {
+ for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
+ ProcessChangeItem item = mPendingProcessChanges.get(i);
+ if (pid > 0 && item.pid == pid) {
+ mPendingProcessChanges.remove(i);
+ mAvailProcessChanges.add(item);
+ }
+ }
+ mService.mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, pid, uid,
+ null).sendToTarget();
+ }
+ }
+
+ void dispatchProcessDied(int pid, int uid) {
+ int i = mProcessObservers.beginBroadcast();
+ while (i > 0) {
+ i--;
+ final IProcessObserver observer = mProcessObservers.getBroadcastItem(i);
+ if (observer != null) {
+ try {
+ observer.onProcessDied(pid, uid);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mProcessObservers.finishBroadcast();
+ }
+
@GuardedBy("mService")
ArrayList<ProcessRecord> collectProcessesLocked(int start, boolean allPkgs, String[] args) {
ArrayList<ProcessRecord> procs;
@@ -3668,8 +4417,8 @@ public final class ProcessList {
ProcessRecord proc = mLruProcesses.get(i);
if (proc.pid > 0 && proc.pid == pid) {
procs.add(proc);
- } else if (allPkgs && proc.pkgList != null
- && proc.pkgList.containsKey(args[start])) {
+ } else if (allPkgs && proc.getPkgList() != null
+ && proc.getPkgList().containsKey(args[start])) {
procs.add(proc);
} else if (proc.processName.equals(args[start])) {
procs.add(proc);
@@ -3697,27 +4446,23 @@ public final class ProcessList {
continue;
}
- final int packageCount = app.pkgList.size();
- for (int j = 0; j < packageCount; j++) {
- final String packageName = app.pkgList.keyAt(j);
- if (!updateFrameworkRes && !packagesToUpdate.contains(packageName)) {
- continue;
- }
- try {
- final ApplicationInfo ai = AppGlobals.getPackageManager()
- .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
- if (ai == null) {
- continue;
- }
- app.thread.scheduleApplicationInfoChanged(ai);
- if (ai.packageName.equals(app.info.packageName)) {
- app.info = ai;
+ app.getPkgList().forEachPackage(packageName -> {
+ if (updateFrameworkRes && packagesToUpdate.contains(packageName)) {
+ try {
+ final ApplicationInfo ai = AppGlobals.getPackageManager()
+ .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
+ if (ai != null) {
+ app.thread.scheduleApplicationInfoChanged(ai);
+ if (ai.packageName.equals(app.info.packageName)) {
+ app.info = ai;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s",
+ packageName, app));
}
- } catch (RemoteException e) {
- Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s",
- packageName, app));
}
- }
+ });
}
}
@@ -4103,7 +4848,7 @@ public final class ProcessList {
boolean diff = mIdle != idle;
mIdle = idle;
if (diff && idle) {
- synchronized (this) {
+ synchronized (mService) {
if (mWorkItems.size() > 0) {
mHandler.sendEmptyMessage(H.MSG_DEVICE_IDLE);
}
@@ -4176,13 +4921,14 @@ public final class ProcessList {
return true;
}
- final int pkgSize = app.pkgList.size();
- for (int ip = 0; ip < pkgSize; ip++) {
- if (mService.mConstants.IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.contains(
- app.pkgList.keyAt(ip))) {
+ if (app.getPkgList().forEachPackage(pkgName -> {
+ if (mService.mConstants.IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.contains(pkgName)) {
// One of the packages in this process is exempted
- return true;
+ return Boolean.TRUE;
}
+ return null;
+ }) != null) {
+ return true;
}
if (mService.mConstants.IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.contains(
diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java
new file mode 100644
index 000000000000..cf309f4c8e3d
--- /dev/null
+++ b/services/core/java/com/android/server/am/ProcessProfileRecord.java
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.app.ActivityManager.processStateAmToProto;
+
+import android.app.IApplicationThread;
+import android.content.pm.ApplicationInfo;
+import android.os.Debug;
+import android.os.SystemClock;
+import android.util.DebugUtils;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.procstats.ProcessState;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.am.ProcessList.ProcStateMemTracker;
+
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Profiling info of the process, such as PSS, cpu, etc.
+ */
+final class ProcessProfileRecord {
+ final ProcessRecord mApp;
+
+ private final ActivityManagerService mService;
+
+ final Object mProfilerLock;
+
+ @GuardedBy("mProfilerLock")
+ private final ProcessList.ProcStateMemTracker mProcStateMemTracker =
+ new ProcessList.ProcStateMemTracker();
+
+ /**
+ * Stats of pss, cpu, etc.
+ */
+ @GuardedBy("mService.mProcessStats.mLock")
+ private ProcessState mBaseProcessTracker;
+
+ /**
+ * Last time we retrieved PSS data.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastPssTime;
+
+ /**
+ * Next time we want to request PSS data.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mNextPssTime;
+
+ /**
+ * Initial memory pss of process for idle maintenance.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mInitialIdlePss;
+
+ /**
+ * Last computed memory pss.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastPss;
+
+ /**
+ * Last computed SwapPss.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastSwapPss;
+
+ /**
+ * Last computed pss when in cached state.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastCachedPss;
+
+ /**
+ * Last computed SwapPss when in cached state.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastCachedSwapPss;
+
+ /**
+ * Last computed memory rss.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastRss;
+
+ /**
+ * Cache of last retrieve memory info, to throttle how frequently apps can request it.
+ */
+ @GuardedBy("mProfilerLock")
+ private Debug.MemoryInfo mLastMemInfo;
+
+ /**
+ * Cache of last retrieve memory uptime, to throttle how frequently apps can request it.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastMemInfoTime;
+
+ /**
+ * Currently requesting pss for.
+ */
+ @GuardedBy("mProfilerLock")
+ private int mPssProcState = PROCESS_STATE_NONEXISTENT;
+
+ /**
+ * The type of stat collection that we are currently requesting.
+ */
+ @GuardedBy("mProfilerLock")
+ private int mPssStatType;
+
+ /**
+ * How long proc has run CPU at last check.
+ */
+ final AtomicLong mLastCpuTime = new AtomicLong(0);
+
+ /**
+ * How long proc has run CPU most recently.
+ */
+ final AtomicLong mCurCpuTime = new AtomicLong(0);
+
+ /**
+ * Last selected memory trimming level.
+ */
+ @GuardedBy("mService")
+ private int mTrimMemoryLevel;
+
+ /**
+ * Want to clean up resources from showing UI?
+ */
+ @GuardedBy("mService")
+ private boolean mPendingUiClean;
+
+ /**
+ * Pointer to the battery stats of this process.
+ */
+ private BatteryStatsImpl.Uid.Proc mCurProcBatteryStats;
+
+ /**
+ * When we last asked the app to do a gc.
+ */
+ @GuardedBy("mProfilerLock")
+ private long mLastRequestedGc;
+
+ /**
+ * When we last told the app that memory is low.
+ */
+ @GuardedBy("mService")
+ private long mLastLowMemory;
+
+ /**
+ * Set to true when waiting to report low mem.
+ */
+ @GuardedBy("mProfilerLock")
+ private boolean mReportLowMemory;
+
+ // ========================================================================
+ // Local copies of some process info, to avoid holding global AMS lock
+ @GuardedBy("mProfilerLock")
+ private int mPid;
+
+ @GuardedBy("mProfilerLock")
+ private IApplicationThread mThread;
+
+ @GuardedBy("mProfilerLock")
+ private int mSetProcState;
+
+ @GuardedBy("mProfilerLock")
+ private int mSetAdj;
+
+ @GuardedBy("mProfilerLock")
+ private int mCurRawAdj;
+
+ @GuardedBy("mProfilerLock")
+ private long mLastStateTime;
+
+ ProcessProfileRecord(final ProcessRecord app) {
+ mApp = app;
+ mService = app.mService;
+ mProfilerLock = mService.mAppProfiler.mProfilerLock;
+ }
+
+ void init(long now) {
+ mLastPssTime = mNextPssTime = now;
+ }
+
+ @GuardedBy("mService.mProcessStats.mLock")
+ ProcessState getBaseProcessTracker() {
+ return mBaseProcessTracker;
+ }
+
+ @GuardedBy("mService.mProcessStats.mLock")
+ void setBaseProcessTracker(ProcessState baseProcessTracker) {
+ mBaseProcessTracker = baseProcessTracker;
+ }
+
+ void onProcessActive(IApplicationThread thread, ProcessStatsService tracker) {
+ if (mThread == null) {
+ synchronized (mProfilerLock) {
+ synchronized (tracker.mLock) {
+ final ProcessState origBase = getBaseProcessTracker();
+ final PackageList pkgList = mApp.getPkgList();
+ if (origBase != null) {
+ synchronized (pkgList) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
+ pkgList.getPackageListLocked());
+ pkgList.forEachPackage((pkgName, holder) ->
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ mApp.uid, mApp.processName, pkgName,
+ processStateAmToProto(ProcessStats.STATE_NOTHING),
+ holder.appVersion)
+ );
+ }
+ origBase.makeInactive();
+ }
+ final ApplicationInfo info = mApp.info;
+ final ProcessState baseProcessTracker = tracker.getProcessStateLocked(
+ info.packageName, info.uid, info.longVersionCode, mApp.processName);
+ setBaseProcessTracker(baseProcessTracker);
+ baseProcessTracker.makeActive();
+ pkgList.forEachPackage((pkgName, holder) -> {
+ if (holder.state != null && holder.state != origBase) {
+ holder.state.makeInactive();
+ }
+ tracker.updateProcessStateHolderLocked(holder, pkgName, mApp.info.uid,
+ mApp.info.longVersionCode, mApp.processName);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
+ });
+ mThread = thread;
+ }
+ }
+ } else {
+ synchronized (mProfilerLock) {
+ mThread = thread;
+ }
+ }
+ }
+
+ void onProcessInactive(ProcessStatsService tracker) {
+ synchronized (mProfilerLock) {
+ synchronized (tracker.mLock) {
+ final ProcessState origBase = getBaseProcessTracker();
+ if (origBase != null) {
+ final PackageList pkgList = mApp.getPkgList();
+ synchronized (pkgList) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
+ pkgList.getPackageListLocked());
+ pkgList.forEachPackage((pkgName, holder) ->
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ mApp.uid, mApp.processName, pkgName,
+ processStateAmToProto(ProcessStats.STATE_NOTHING),
+ holder.appVersion)
+ );
+ }
+ origBase.makeInactive();
+ setBaseProcessTracker(null);
+ pkgList.forEachPackageProcessStats(holder -> {
+ if (holder.state != null && holder.state != origBase) {
+ holder.state.makeInactive();
+ }
+ holder.pkg = null;
+ holder.state = null;
+ });
+ }
+ mThread = null;
+ }
+ }
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastPssTime() {
+ return mLastPssTime;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastPssTime(long lastPssTime) {
+ mLastPssTime = lastPssTime;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getNextPssTime() {
+ return mNextPssTime;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setNextPssTime(long nextPssTime) {
+ mNextPssTime = nextPssTime;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getInitialIdlePss() {
+ return mInitialIdlePss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setInitialIdlePss(long initialIdlePss) {
+ mInitialIdlePss = initialIdlePss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastPss() {
+ return mLastPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastPss(long lastPss) {
+ mLastPss = lastPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastCachedPss() {
+ return mLastCachedPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastCachedPss(long lastCachedPss) {
+ mLastCachedPss = lastCachedPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastSwapPss() {
+ return mLastSwapPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastSwapPss(long lastSwapPss) {
+ mLastSwapPss = lastSwapPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastCachedSwapPss() {
+ return mLastCachedSwapPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastCachedSwapPss(long lastCachedSwapPss) {
+ mLastCachedSwapPss = lastCachedSwapPss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastRss() {
+ return mLastRss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastRss(long lastRss) {
+ mLastRss = lastRss;
+ }
+
+ @GuardedBy("mProfilerLock")
+ Debug.MemoryInfo getLastMemInfo() {
+ return mLastMemInfo;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastMemInfo(Debug.MemoryInfo lastMemInfo) {
+ mLastMemInfo = lastMemInfo;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastMemInfoTime() {
+ return mLastMemInfoTime;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastMemInfoTime(long lastMemInfoTime) {
+ mLastMemInfoTime = lastMemInfoTime;
+ }
+
+ @GuardedBy("mProfilerLock")
+ int getPssProcState() {
+ return mPssProcState;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setPssProcState(int pssProcState) {
+ mPssProcState = pssProcState;
+ }
+
+ @GuardedBy("mProfilerLock")
+ int getPssStatType() {
+ return mPssStatType;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setPssStatType(int pssStatType) {
+ mPssStatType = pssStatType;
+ }
+
+ @GuardedBy("mService")
+ int getTrimMemoryLevel() {
+ return mTrimMemoryLevel;
+ }
+
+ @GuardedBy("mService")
+ void setTrimMemoryLevel(int trimMemoryLevel) {
+ mTrimMemoryLevel = trimMemoryLevel;
+ }
+
+ @GuardedBy("mService")
+ boolean hasPendingUiClean() {
+ return mPendingUiClean;
+ }
+
+ @GuardedBy("mService")
+ void setPendingUiClean(boolean pendingUiClean) {
+ mPendingUiClean = pendingUiClean;
+ mApp.getWindowProcessController().setPendingUiClean(pendingUiClean);
+ }
+
+ BatteryStatsImpl.Uid.Proc getCurProcBatteryStats() {
+ return mCurProcBatteryStats;
+ }
+
+ void setCurProcBatteryStats(BatteryStatsImpl.Uid.Proc curProcBatteryStats) {
+ mCurProcBatteryStats = curProcBatteryStats;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastRequestedGc() {
+ return mLastRequestedGc;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setLastRequestedGc(long lastRequestedGc) {
+ mLastRequestedGc = lastRequestedGc;
+ }
+
+ @GuardedBy("mService")
+ long getLastLowMemory() {
+ return mLastLowMemory;
+ }
+
+ @GuardedBy("mService")
+ void setLastLowMemory(long lastLowMemory) {
+ mLastLowMemory = lastLowMemory;
+ }
+
+ @GuardedBy("mProfilerLock")
+ boolean getReportLowMemory() {
+ return mReportLowMemory;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setReportLowMemory(boolean reportLowMemory) {
+ mReportLowMemory = reportLowMemory;
+ }
+
+ void addPss(long pss, long uss, long rss, boolean always, int type, long duration) {
+ synchronized (mService.mProcessStats.mLock) {
+ final ProcessState tracker = mBaseProcessTracker;
+ if (tracker != null) {
+ final PackageList pkgList = mApp.getPkgList();
+ synchronized (pkgList) {
+ tracker.addPss(pss, uss, rss, always, type, duration,
+ pkgList.getPackageListLocked());
+ }
+ }
+ }
+ }
+
+ void reportExcessiveCpu() {
+ synchronized (mService.mProcessStats.mLock) {
+ final ProcessState tracker = mBaseProcessTracker;
+ if (tracker != null) {
+ final PackageList pkgList = mApp.getPkgList();
+ synchronized (pkgList) {
+ tracker.reportExcessiveCpu(pkgList.getPackageListLocked());
+ }
+ }
+ }
+ }
+
+ void reportCachedKill() {
+ synchronized (mService.mProcessStats.mLock) {
+ final ProcessState tracker = mBaseProcessTracker;
+ if (tracker != null) {
+ final PackageList pkgList = mApp.getPkgList();
+ synchronized (pkgList) {
+ tracker.reportCachedKill(pkgList.getPackageListLocked(), mLastCachedPss);
+ pkgList.forEachPackageProcessStats(holder ->
+ FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
+ mApp.info.uid,
+ holder.state.getName(),
+ holder.state.getPackage(),
+ mLastCachedPss,
+ holder.appVersion)
+ );
+ }
+ }
+ }
+ }
+
+ void setProcessTrackerState(int procState, int memFactor, long now) {
+ synchronized (mService.mProcessStats.mLock) {
+ final ProcessState tracker = mBaseProcessTracker;
+ if (tracker != null) {
+ if (procState != PROCESS_STATE_NONEXISTENT) {
+ final PackageList pkgList = mApp.getPkgList();
+ synchronized (pkgList) {
+ tracker.setState(procState, memFactor, now,
+ pkgList.getPackageListLocked());
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mProfilerLock")
+ void commitNextPssTime() {
+ commitNextPssTime(mProcStateMemTracker);
+ }
+
+ @GuardedBy("mProfilerLock")
+ void abortNextPssTime() {
+ abortNextPssTime(mProcStateMemTracker);
+ }
+
+ @GuardedBy("mProfilerLock")
+ long computeNextPssTime(int procState, boolean test, boolean sleeping, long now) {
+ return ProcessList.computeNextPssTime(procState, mProcStateMemTracker, test, sleeping, now);
+ }
+
+ private static void commitNextPssTime(ProcStateMemTracker tracker) {
+ if (tracker.mPendingMemState >= 0) {
+ tracker.mHighestMem[tracker.mPendingMemState] = tracker.mPendingHighestMemState;
+ tracker.mScalingFactor[tracker.mPendingMemState] = tracker.mPendingScalingFactor;
+ tracker.mTotalHighestMem = tracker.mPendingHighestMemState;
+ tracker.mPendingMemState = -1;
+ }
+ }
+
+ private static void abortNextPssTime(ProcStateMemTracker tracker) {
+ tracker.mPendingMemState = -1;
+ }
+
+ @GuardedBy("mProfilerLock")
+ int getPid() {
+ return mPid;
+ }
+
+ @GuardedBy("mProfilerLock")
+ void setPid(int pid) {
+ mPid = pid;
+ }
+
+ @GuardedBy("mProfilerLock")
+ IApplicationThread getThread() {
+ return mThread;
+ }
+
+ @GuardedBy("mProfilerLock")
+ int getSetProcState() {
+ return mSetProcState;
+ }
+
+ @GuardedBy("mProfilerLock")
+ int getSetAdj() {
+ return mSetAdj;
+ }
+
+ @GuardedBy("mProfilerLock")
+ int getCurRawAdj() {
+ return mCurRawAdj;
+ }
+
+ @GuardedBy("mProfilerLock")
+ long getLastStateTime() {
+ return mLastStateTime;
+ }
+
+ @GuardedBy({"mService", "mProfilerLock"})
+ void updateProcState(ProcessRecord app) {
+ mSetProcState = app.getCurProcState();
+ mSetAdj = app.curAdj;
+ mCurRawAdj = app.getCurRawAdj();
+ mLastStateTime = app.lastStateTime;
+ }
+
+ @GuardedBy("mService")
+ void dumpPss(PrintWriter pw, String prefix, long nowUptime) {
+ synchronized (mProfilerLock) {
+ pw.print(" lastPssTime=");
+ TimeUtils.formatDuration(mLastPssTime, nowUptime, pw);
+ pw.print(" pssProcState=");
+ pw.print(mPssProcState);
+ pw.print(" pssStatType=");
+ pw.print(mPssStatType);
+ pw.print(" nextPssTime=");
+ TimeUtils.formatDuration(mNextPssTime, nowUptime, pw);
+ pw.println();
+ pw.print(prefix);
+ pw.print("lastPss=");
+ DebugUtils.printSizeValue(pw, mLastPss * 1024);
+ pw.print(" lastSwapPss=");
+ DebugUtils.printSizeValue(pw, mLastSwapPss * 1024);
+ pw.print(" lastCachedPss=");
+ DebugUtils.printSizeValue(pw, mLastCachedPss * 1024);
+ pw.print(" lastCachedSwapPss=");
+ DebugUtils.printSizeValue(pw, mLastCachedSwapPss * 1024);
+ pw.print(" lastRss=");
+ DebugUtils.printSizeValue(pw, mLastRss * 1024);
+ pw.print(" trimMemoryLevel=");
+ pw.println(mTrimMemoryLevel);
+ pw.println();
+ pw.print(prefix); pw.print("procStateMemTracker: ");
+ mProcStateMemTracker.dumpLine(pw);
+ pw.print(prefix);
+ pw.print("lastRequestedGc=");
+ TimeUtils.formatDuration(mLastRequestedGc, nowUptime, pw);
+ pw.print(" lastLowMemory=");
+ TimeUtils.formatDuration(mLastLowMemory, nowUptime, pw);
+ pw.print(" reportLowMemory=");
+ pw.println(mReportLowMemory);
+ }
+ }
+
+ void dumpCputime(PrintWriter pw, String prefix) {
+ final long lastCpuTime = mLastCpuTime.get();
+ pw.print(prefix);
+ pw.print("lastCpuTime=");
+ pw.print(lastCpuTime);
+ if (lastCpuTime > 0) {
+ pw.print(" timeUsed=");
+ TimeUtils.formatDuration(mCurCpuTime.get() - lastCpuTime, pw);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 63195d35b049..f7e87ef94939 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -52,7 +52,6 @@ import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.content.res.CompatibilityInfo;
import android.os.Binder;
-import android.os.Debug;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
@@ -74,7 +73,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessState;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.Zygote;
import com.android.internal.util.FrameworkStatsLog;
@@ -96,9 +94,9 @@ import java.util.function.Consumer;
* is currently running.
*/
class ProcessRecord implements WindowProcessListener {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM;
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM;
- private final ActivityManagerService mService; // where we came from
+ final ActivityManagerService mService; // where we came from
volatile ApplicationInfo info; // all about the first app in the process
final ProcessInfo processInfo; // if non-null, process-specific manifest info
final boolean isolated; // true if this is a special isolated process
@@ -106,51 +104,17 @@ class ProcessRecord implements WindowProcessListener {
final int uid; // uid of process; may be different from 'info' if isolated
final int userId; // user of process.
final String processName; // name of the process
- // List of packages running in the process
- final PackageList pkgList = new PackageList();
- final class PackageList {
- final ArrayMap<String, ProcessStats.ProcessStateHolder> mPkgList = new ArrayMap<>();
- ProcessStats.ProcessStateHolder put(String key, ProcessStats.ProcessStateHolder value) {
- mWindowProcessController.addPackage(key);
- return mPkgList.put(key, value);
- }
-
- void clear() {
- mPkgList.clear();
- mWindowProcessController.clearPackageList();
- }
-
- int size() {
- return mPkgList.size();
- }
-
- String keyAt(int index) {
- return mPkgList.keyAt(index);
- }
-
- public ProcessStats.ProcessStateHolder valueAt(int index) {
- return mPkgList.valueAt(index);
- }
-
- ProcessStats.ProcessStateHolder get(String pkgName) {
- return mPkgList.get(pkgName);
- }
-
- boolean containsKey(Object key) {
- return mPkgList.containsKey(key);
- }
- }
+ /**
+ * List of packages running in the process
+ */
+ private final PackageList mPkgList = new PackageList(this);
- final ProcessList.ProcStateMemTracker procStateMemTracker
- = new ProcessList.ProcStateMemTracker();
UidRecord uidRecord; // overall state of process's uid.
ArraySet<String> pkgDeps; // additional packages we have a dependency on
IApplicationThread thread; // the actual proc... may be null only if
// 'persistent' is true (in which case we
// are in the process of launching the app)
- ProcessState baseProcessTracker;
- BatteryStatsImpl.Uid.Proc curProcBatteryStats;
int pid; // The process of this application; 0 if none
String procStatFile; // path to /proc/<pid>/stat
int[] gids; // The gids this process was launched with
@@ -158,14 +122,7 @@ class ProcessRecord implements WindowProcessListener {
String instructionSet; // The instruction set this process was launched with
boolean starting; // True if the process is being started
long lastActivityTime; // For managing the LRU list
- long lastPssTime; // Last time we retrieved PSS data
- long nextPssTime; // Next time we want to request PSS data
long lastStateTime; // Last time setProcState changed
- long initialIdlePss; // Initial memory pss of process for idle maintenance.
- long lastPss; // Last computed memory pss.
- long lastSwapPss; // Last computed SwapPss.
- long lastCachedPss; // Last computed pss when in cached state.
- long lastCachedSwapPss; // Last computed SwapPss when in cached state.
int maxAdj; // Maximum OOM adjustment for this process
private int mCurRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
@@ -184,13 +141,10 @@ class ProcessRecord implements WindowProcessListener {
boolean shouldNotFreeze; // True if a process has a WPRI binding from an unfrozen process
private int mCurSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
- int trimMemoryLevel; // Last selected memory trimming level
private int mCurProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
private int mRepProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
private int mCurRawProcState = PROCESS_STATE_NONEXISTENT; // Temp state during computation
int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker
- int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for
- int pssStatType; // The type of stat collection that we are currently requesting
int savedPriority; // Previous priority value if we're switching to non-SCHED_OTHER
int renderThreadTid; // TID for RenderThread
ServiceRecord connectionService; // Service that applied current connectionGroup/Importance
@@ -226,7 +180,6 @@ class ProcessRecord implements WindowProcessListener {
// performance, as well as oom adj score will be set to
// ProcessList#VISIBLE_APP_ADJ at minimum to reduce the chance
// of the process getting killed.
- private boolean mPendingUiClean; // Want to clean up resources from showing UI?
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean treatLikeActivity; // Bound using BIND_TREAT_LIKE_ACTIVITY
boolean bad; // True if disabled in the bad process list
@@ -250,13 +203,8 @@ class ProcessRecord implements WindowProcessListener {
private boolean mUsingWrapper; // Set to true when process was launched with a wrapper attached
final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
private long mWhenUnimportant; // When (uptime) the process last became unimportant
- long lastCpuTime; // How long proc has run CPU at last check
- long curCpuTime; // How long proc has run CPU most recently
- long lastRequestedGc; // When we last asked the app to do a gc
- long lastLowMemory; // When we last told the app that memory is low
long lastProviderTime; // The last time someone else was using a provider in this process.
long lastTopTime; // The last time the process was in the TOP state or greater.
- boolean reportLowMemory; // Set to true when waiting to report low mem
boolean empty; // Is this an empty background process?
private boolean mCached; // Is this a cached process?
String adjType; // Debugging: primary thing impacting oom_adj.
@@ -267,11 +215,6 @@ class ProcessRecord implements WindowProcessListener {
Runnable crashHandler; // Optional local handler to be invoked in the process crash.
boolean bindMountPending; // True if Android/obb and Android/data need to be bind mount .
- // Cache of last retrieve memory info and uptime, to throttle how frequently
- // apps can requyest it.
- Debug.MemoryInfo lastMemInfo;
- long lastMemInfoTime;
-
// Controller for error dialogs
private final ErrorDialogController mDialogController = new ErrorDialogController();
// Controller for driving the process state on the window manager side.
@@ -323,8 +266,8 @@ class ProcessRecord implements WindowProcessListener {
// Process is currently hosting a backup agent for backup or restore
public boolean inFullBackup;
- // App is allowed to manage whitelists such as temporary Power Save mode whitelist.
- boolean whitelistManager;
+ // App is allowed to manage allowlists such as temporary Power Save mode allowlist.
+ boolean mAllowlistManager;
// Params used in starting this process.
HostingRecord hostingRecord;
@@ -335,8 +278,6 @@ class ProcessRecord implements WindowProcessListener {
// set of disabled compat changes for the process (all others are enabled)
long[] mDisabledCompatChanges;
- long mLastRss; // Last computed memory rss.
-
// The precede instance of the process, which would exist when the previous process is killed
// but not fully dead yet; in this case, the new instance of the process should be held until
// this precede instance is fully dead.
@@ -389,6 +330,11 @@ class ProcessRecord implements WindowProcessListener {
// another process through service binding.
boolean mAllowStartFgs;
+ /**
+ * Profiling info of the process, such as PSS, cpu, etc.
+ */
+ final ProcessProfileRecord mProfile;
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startTime) {
this.startUid = startUid;
@@ -439,11 +385,7 @@ class ProcessRecord implements WindowProcessListener {
pw.print(prefix); pw.print("dir="); pw.print(info.sourceDir);
pw.print(" publicDir="); pw.print(info.publicSourceDir);
pw.print(" data="); pw.println(info.dataDir);
- pw.print(prefix); pw.print("packageList={");
- for (int i=0; i<pkgList.size(); i++) {
- if (i > 0) pw.print(", ");
- pw.print(pkgList.keyAt(i));
- }
+ mPkgList.dump(pw, prefix);
pw.println("}");
if (pkgDeps != null) {
pw.print(prefix); pw.print("packageDependencies={");
@@ -462,21 +404,7 @@ class ProcessRecord implements WindowProcessListener {
pw.println(starting);
pw.print(prefix); pw.print("lastActivityTime=");
TimeUtils.formatDuration(lastActivityTime, nowUptime, pw);
- pw.print(" lastPssTime=");
- TimeUtils.formatDuration(lastPssTime, nowUptime, pw);
- pw.print(" pssStatType="); pw.print(pssStatType);
- pw.print(" nextPssTime=");
- TimeUtils.formatDuration(nextPssTime, nowUptime, pw);
- pw.println();
- pw.print(prefix); pw.print("lastPss="); DebugUtils.printSizeValue(pw, lastPss * 1024);
- pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, lastSwapPss * 1024);
- pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss * 1024);
- pw.print(" lastCachedSwapPss="); DebugUtils.printSizeValue(pw,
- lastCachedSwapPss * 1024);
- pw.print(" lastRss="); DebugUtils.printSizeValue(pw, mLastRss * 1024);
pw.println();
- pw.print(prefix); pw.print("procStateMemTracker: ");
- procStateMemTracker.dumpLine(pw);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.println(lruSeq);
pw.print(prefix); pw.print("oom adj: max="); pw.print(maxAdj);
@@ -489,10 +417,8 @@ class ProcessRecord implements WindowProcessListener {
pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup);
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
pw.print(" systemNoUi="); pw.print(systemNoUi);
- pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
pw.print(prefix); pw.print("curProcState="); pw.print(getCurProcState());
pw.print(" mRepProcState="); pw.print(mRepProcState);
- pw.print(" pssProcState="); pw.print(pssProcState);
pw.print(" setProcState="); pw.print(setProcState);
pw.print(" lastStateTime=");
TimeUtils.formatDuration(lastStateTime, nowUptime, pw);
@@ -507,11 +433,11 @@ class ProcessRecord implements WindowProcessListener {
if (mAllowStartFgs) {
pw.print(prefix); pw.print("allowStartFgs="); pw.println(mAllowStartFgs);
}
- if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
+ if (hasShownUi || mProfile.hasPendingUiClean() || hasAboveClient || treatLikeActivity) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
- pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
- pw.print(" hasAboveClient="); pw.print(hasAboveClient);
- pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
+ pw.print(" pendingUiClean="); pw.print(mProfile.hasPendingUiClean());
+ pw.print(" hasAboveClient="); pw.print(hasAboveClient);
+ pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
}
pw.print(prefix); pw.print("cached="); pw.print(mCached);
pw.print(" empty="); pw.println(empty);
@@ -521,7 +447,7 @@ class ProcessRecord implements WindowProcessListener {
}
if (notCachedSinceIdle) {
pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
- pw.print(" initialIdlePss="); pw.println(initialIdlePss);
+ pw.print(" initialIdlePss="); pw.println(mProfile.getInitialIdlePss());
}
if (connectionService != null || connectionGroup != 0) {
pw.print(prefix); pw.print("connectionGroup="); pw.print(connectionGroup);
@@ -579,20 +505,12 @@ class ProcessRecord implements WindowProcessListener {
pw.print(prefix); pw.print("mountMode="); pw.println(
DebugUtils.valueToString(Zygote.class, "MOUNT_EXTERNAL_", mountMode));
if (setProcState > ActivityManager.PROCESS_STATE_SERVICE) {
- pw.print(prefix); pw.print("lastCpuTime="); pw.print(lastCpuTime);
- if (lastCpuTime > 0) {
- pw.print(" timeUsed=");
- TimeUtils.formatDuration(curCpuTime - lastCpuTime, pw);
- }
- pw.print(" whenUnimportant=");
- TimeUtils.formatDuration(mWhenUnimportant - nowUptime, pw);
- pw.println();
- }
- pw.print(prefix); pw.print("lastRequestedGc=");
- TimeUtils.formatDuration(lastRequestedGc, nowUptime, pw);
- pw.print(" lastLowMemory=");
- TimeUtils.formatDuration(lastLowMemory, nowUptime, pw);
- pw.print(" reportLowMemory="); pw.println(reportLowMemory);
+ mProfile.dumpCputime(pw, prefix);
+ pw.print(" whenUnimportant=");
+ TimeUtils.formatDuration(mWhenUnimportant - nowUptime, pw);
+ pw.println();
+ }
+ mProfile.dumpPss(pw, prefix, nowUptime);
if (killed || killedByAm || waitingToKill != null) {
pw.print(prefix); pw.print("killed="); pw.print(killed);
pw.print(" killedByAm="); pw.print(killedByAm);
@@ -614,8 +532,8 @@ class ProcessRecord implements WindowProcessListener {
}
pw.println();
}
- if (whitelistManager) {
- pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
+ if (mAllowlistManager) {
+ pw.print(prefix); pw.print("allowlistManager="); pw.println(mAllowlistManager);
}
if (isolatedEntryPoint != null || isolatedEntryPointArgs != null) {
pw.print(prefix); pw.print("isolatedEntryPoint="); pw.println(isolatedEntryPoint);
@@ -699,53 +617,33 @@ class ProcessRecord implements WindowProcessListener {
curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ;
mPersistent = false;
removed = false;
- freezeUnfreezeTime = lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
+ mProfile = new ProcessProfileRecord(this);
+ final long now = SystemClock.uptimeMillis();
+ freezeUnfreezeTime = lastStateTime = now;
+ mProfile.init(now);
mWindowProcessController = new WindowProcessController(
mService.mActivityTaskManager, info, processName, uid, userId, this, this);
- pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
+ mPkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
setAllowStartFgsByPermission();
}
+ PackageList getPkgList() {
+ return mPkgList;
+ }
+
public void setPid(int _pid) {
pid = _pid;
mWindowProcessController.setPid(pid);
procStatFile = null;
shortStringName = null;
stringName = null;
+ synchronized (mProfile.mProfilerLock) {
+ mProfile.setPid(pid);
+ }
}
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
- if (thread == null) {
- synchronized (tracker.mLock) {
- final ProcessState origBase = baseProcessTracker;
- if (origBase != null) {
- origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
- pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
- }
- origBase.makeInactive();
- }
- baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
- info.longVersionCode, processName);
- baseProcessTracker.makeActive();
- for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != origBase) {
- holder.state.makeInactive();
- }
- tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid,
- info.longVersionCode, processName);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
- }
- }
- }
- }
+ mProfile.onProcessActive(thread, tracker);
thread = _thread;
mWindowProcessController.setThread(thread);
}
@@ -753,32 +651,7 @@ class ProcessRecord implements WindowProcessListener {
public void makeInactive(ProcessStatsService tracker) {
thread = null;
mWindowProcessController.setThread(null);
- synchronized (tracker.mLock) {
- final ProcessState origBase = baseProcessTracker;
- if (origBase != null) {
- if (origBase != null) {
- origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
- pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
- }
- origBase.makeInactive();
- }
- baseProcessTracker = null;
- for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != origBase) {
- holder.state.makeInactive();
- }
- holder.pkg = null;
- holder.state = null;
- }
- }
- }
+ mProfile.onProcessInactive(tracker);
}
/**
@@ -1080,22 +953,25 @@ class ProcessRecord implements WindowProcessListener {
* Return true if package has been added false if not
*/
public boolean addPackage(String pkg, long versionCode, ProcessStatsService tracker) {
- if (!pkgList.containsKey(pkg)) {
- synchronized (tracker.mLock) {
- ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
- versionCode);
- if (baseProcessTracker != null) {
- tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
- processName);
- pkgList.put(pkg, holder);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
+ synchronized (tracker.mLock) {
+ synchronized (mPkgList) {
+ if (!mPkgList.containsKey(pkg)) {
+ ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
+ versionCode);
+ final ProcessState baseProcessTracker = mProfile.getBaseProcessTracker();
+ if (baseProcessTracker != null) {
+ tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
+ processName);
+ mPkgList.put(pkg, holder);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
+ } else {
+ mPkgList.put(pkg, holder);
}
- } else {
- pkgList.put(pkg, holder);
+ return true;
}
}
- return true;
}
return false;
}
@@ -1114,12 +990,12 @@ class ProcessRecord implements WindowProcessListener {
mRepProcState = newState;
setCurProcState(newState);
setCurRawProcState(newState);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
+ getPkgList().forEachPackage((pkgName, holder) ->
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgName,
ActivityManager.processStateAmToProto(mRepProcState),
- pkgList.valueAt(ipkg).appVersion);
- }
+ holder.appVersion)
+ );
}
}
@@ -1127,66 +1003,51 @@ class ProcessRecord implements WindowProcessListener {
* Delete all packages from list except the package indicated in info
*/
public void resetPackageList(ProcessStatsService tracker) {
- final int N = pkgList.size();
synchronized (tracker.mLock) {
- if (baseProcessTracker != null) {
- long now = SystemClock.uptimeMillis();
- baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), now, pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
- }
- if (N != 1) {
- for (int i = 0; i < N; i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != baseProcessTracker) {
- holder.state.makeInactive();
+ final ProcessState baseProcessTracker = mProfile.getBaseProcessTracker();
+ synchronized (mPkgList) {
+ final int numOfPkgs = mPkgList.size();
+ if (baseProcessTracker != null) {
+ long now = SystemClock.uptimeMillis();
+ baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), now, mPkgList.getPackageListLocked());
+ mPkgList.forEachPackage((pkgName, holder) ->
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgName,
+ ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+ holder.appVersion)
+ );
+ if (numOfPkgs != 1) {
+ mPkgList.forEachPackageProcessStats(holder -> {
+ if (holder.state != null && holder.state != baseProcessTracker) {
+ holder.state.makeInactive();
+ }
+ });
+ mPkgList.clear();
+ ProcessStats.ProcessStateHolder holder =
+ new ProcessStats.ProcessStateHolder(info.longVersionCode);
+ tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
+ info.longVersionCode, processName);
+ mPkgList.put(info.packageName, holder);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
}
-
- }
- pkgList.clear();
- ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
- info.longVersionCode);
- tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
- info.longVersionCode, processName);
- pkgList.put(info.packageName, holder);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
}
+ } else if (numOfPkgs != 1) {
+ mPkgList.clear();
+ mPkgList.put(info.packageName,
+ new ProcessStats.ProcessStateHolder(info.longVersionCode));
}
- } else if (N != 1) {
- pkgList.clear();
- pkgList.put(info.packageName,
- new ProcessStats.ProcessStateHolder(info.longVersionCode));
}
}
}
- public String[] getPackageList() {
- int size = pkgList.size();
- if (size == 0) {
- return null;
- }
- String list[] = new String[size];
- for (int i=0; i<pkgList.size(); i++) {
- list[i] = pkgList.keyAt(i);
- }
- return list;
+ String[] getPackageList() {
+ return mPkgList.getPackageList();
}
- public List<VersionedPackage> getPackageListWithVersionCode() {
- int size = pkgList.size();
- if (size == 0) {
- return null;
- }
- List<VersionedPackage> list = new ArrayList<>();
- for (int i = 0; i < pkgList.size(); i++) {
- list.add(new VersionedPackage(pkgList.keyAt(i), pkgList.valueAt(i).appVersion));
- }
- return list;
+ List<VersionedPackage> getPackageListWithVersionCode() {
+ return mPkgList.getPackageListWithVersionCode();
}
WindowProcessController getWindowProcessController() {
@@ -1221,12 +1082,12 @@ class ProcessRecord implements WindowProcessListener {
void setReportedProcState(int repProcState) {
mRepProcState = repProcState;
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
+ getPkgList().forEachPackage((pkgName, holder) ->
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgName,
ActivityManager.processStateAmToProto(mRepProcState),
- pkgList.valueAt(ipkg).appVersion);
- }
+ holder.appVersion)
+ );
mWindowProcessController.setReportedProcState(repProcState);
}
@@ -1469,8 +1330,8 @@ class ProcessRecord implements WindowProcessListener {
@Override
public void clearProfilerIfNeeded() {
- synchronized (mService) {
- mService.mAppProfiler.clearProfilerLocked();
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ mService.mAppProfiler.clearProfilerLPf();
}
}
@@ -1484,15 +1345,10 @@ class ProcessRecord implements WindowProcessListener {
@Override
public void setPendingUiClean(boolean pendingUiClean) {
synchronized (mService) {
- mPendingUiClean = pendingUiClean;
- mWindowProcessController.setPendingUiClean(pendingUiClean);
+ mProfile.setPendingUiClean(pendingUiClean);
}
}
- boolean hasPendingUiClean() {
- return mPendingUiClean;
- }
-
@Override
public void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
synchronized (mService) {
@@ -1541,7 +1397,9 @@ class ProcessRecord implements WindowProcessListener {
synchronized (mService) {
waitingToKill = null;
if (setProfileProc) {
- mService.mAppProfiler.setProfileProcLocked(this);
+ synchronized (mService.mAppProfiler.mProfilerLock) {
+ mService.mAppProfiler.setProfileProcLPf(this);
+ }
}
if (packageName != null) {
addPackage(packageName, versionCode, mService.mProcessStats);
@@ -1698,7 +1556,7 @@ class ProcessRecord implements WindowProcessListener {
// Check if package is still being loaded
boolean isPackageLoading = false;
final PackageManagerInternal packageManagerInternal =
- mService.getPackageManagerInternalLocked();
+ mService.getPackageManagerInternal();
if (aInfo != null && aInfo.packageName != null) {
IncrementalStatesInfo incrementalStatesInfo =
packageManagerInternal.getIncrementalStatesInfo(
@@ -2104,7 +1962,7 @@ class ProcessRecord implements WindowProcessListener {
if (!mAllowStartFgs) {
// uid is on DeviceIdleController's user/system allowlist
// or AMS's FgsStartTempAllowList.
- mAllowStartFgs = mService.isWhitelistedForFgsStartLocked(info.uid);
+ mAllowStartFgs = mService.isAllowlistedForFgsStartLocked(info.uid);
}
}
diff --git a/services/core/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
index 783f150a5e94..22e7faa4bad9 100644
--- a/services/core/java/com/android/server/am/StrictModeViolationDialog.java
+++ b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
@@ -49,8 +49,8 @@ final class StrictModeViolationDialog extends BaseErrorDialog {
mProc = app;
mResult = result;
CharSequence name;
- if ((app.pkgList.size() == 1) &&
- (name=context.getPackageManager().getApplicationLabel(app.info)) != null) {
+ if ((app.getPkgList().size() == 1)
+ && (name = context.getPackageManager().getApplicationLabel(app.info)) != null) {
setMessage(res.getString(
com.android.internal.R.string.smv_application,
name.toString(), app.info.processName));
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index f1945ede7237..36d22bf0f5da 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -41,8 +41,8 @@ public final class UidRecord {
long lastBackgroundTime;
boolean ephemeral;
boolean foregroundServices;
- boolean curWhitelist;
- boolean setWhitelist;
+ boolean mCurAllowlist;
+ boolean mSetAllowlist;
boolean idle;
boolean setIdle;
int numProcs;
@@ -157,7 +157,7 @@ public final class UidRecord {
proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(mCurProcState));
proto.write(UidRecordProto.EPHEMERAL, ephemeral);
proto.write(UidRecordProto.FG_SERVICES, foregroundServices);
- proto.write(UidRecordProto.WHILELIST, curWhitelist);
+ proto.write(UidRecordProto.WHILELIST, mCurAllowlist);
ProtoUtils.toDuration(proto, UidRecordProto.LAST_BACKGROUND_TIME,
lastBackgroundTime, SystemClock.elapsedRealtime());
proto.write(UidRecordProto.IDLE, idle);
@@ -191,8 +191,8 @@ public final class UidRecord {
if (foregroundServices) {
sb.append(" fgServices");
}
- if (curWhitelist) {
- sb.append(" whitelist");
+ if (mCurAllowlist) {
+ sb.append(" allowlist");
}
if (lastBackgroundTime > 0) {
sb.append(" bg:");
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 3bbc8373cef3..6dd78e77aafb 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -118,6 +118,7 @@ import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
/**
* Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
@@ -1458,7 +1459,7 @@ class UserController implements Handler.Callback {
t.traceBegin("updateConfigurationAndProfileIds");
if (foreground) {
// Make sure the old user is no longer considering the display to be on.
- mInjector.reportGlobalUsageEventLocked(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
+ mInjector.reportGlobalUsageEvent(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
boolean userSwitchUiEnabled;
synchronized (mLock) {
mCurrentUserId = userId;
@@ -3045,7 +3046,7 @@ class UserController implements Handler.Callback {
d.show();
}
- void reportGlobalUsageEventLocked(int event) {
+ void reportGlobalUsageEvent(int event) {
mService.reportGlobalUsageEvent(event);
}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 508bb01e50a8..fded85cd9126 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -20,6 +20,7 @@ import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.EXTRA_REMOVED_FOR_ALL_USERS;
import static android.content.Intent.EXTRA_REPLACING;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
@@ -46,6 +47,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -55,6 +57,7 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* System service that manages app hibernation state, a state apps can enter that means they are
@@ -74,6 +77,8 @@ public final class AppHibernationService extends SystemService {
private final UserManager mUserManager;
@GuardedBy("mLock")
private final SparseArray<Map<String, UserPackageState>> mUserStates = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final Set<String> mGloballyHibernatedPackages = new ArraySet<>();
/**
* Initializes the system service.
@@ -138,7 +143,7 @@ public final class AppHibernationService extends SystemService {
* @param userId the user to check
* @return true if package is hibernating for the user
*/
- public boolean isHibernating(String packageName, int userId) {
+ boolean isHibernatingForUser(String packageName, int userId) {
userId = handleIncomingUser(userId, "isHibernating");
synchronized (mLock) {
final Map<String, UserPackageState> packageStates = mUserStates.get(userId);
@@ -151,7 +156,19 @@ public final class AppHibernationService extends SystemService {
String.format("Package %s is not installed for user %s",
packageName, userId));
}
- return pkgState != null ? pkgState.hibernated : null;
+ return pkgState.hibernated;
+ }
+ }
+
+ /**
+ * Whether a package is hibernated globally. This only occurs when a package is hibernating for
+ * all users and allows us to make optimizations at the package or APK level.
+ *
+ * @param packageName package to check
+ */
+ boolean isHibernatingGlobally(String packageName) {
+ synchronized (mLock) {
+ return mGloballyHibernatedPackages.contains(packageName);
}
}
@@ -162,7 +179,7 @@ public final class AppHibernationService extends SystemService {
* @param userId user
* @param isHibernating new hibernation state
*/
- public void setHibernating(String packageName, int userId, boolean isHibernating) {
+ void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
userId = handleIncomingUser(userId, "setHibernating");
synchronized (mLock) {
if (!mUserStates.contains(userId)) {
@@ -180,32 +197,99 @@ public final class AppHibernationService extends SystemService {
return;
}
+ if (isHibernating) {
+ hibernatePackageForUserL(packageName, userId, pkgState);
+ } else {
+ unhibernatePackageForUserL(packageName, userId, pkgState);
+ }
+ }
+ }
- final long caller = Binder.clearCallingIdentity();
- try {
+ /**
+ * Set whether the package should be hibernated globally at a package level, allowing the
+ * the system to make optimizations at the package or APK level.
+ *
+ * @param packageName package to hibernate globally
+ * @param isHibernating new hibernation state
+ */
+ void setHibernatingGlobally(String packageName, boolean isHibernating) {
+ if (isHibernating != mGloballyHibernatedPackages.contains(packageName)) {
+ synchronized (mLock) {
if (isHibernating) {
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
- mIActivityManager.forceStopPackage(packageName, userId);
- mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
- null /* observer */);
+ hibernatePackageGloballyL(packageName);
} else {
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
- mIPackageManager.setPackageStoppedState(packageName, false, userId);
+ unhibernatePackageGloballyL(packageName);
}
- pkgState.hibernated = isHibernating;
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Failed to hibernate due to manager not being available", e);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Binder.restoreCallingIdentity(caller);
}
+ }
+ }
- // TODO: Support package level hibernation when package is hibernating for all users
+ /**
+ * Put an app into hibernation for a given user, allowing user-level optimizations to occur.
+ * The caller should hold {@link #mLock}
+ *
+ * @param pkgState package hibernation state
+ */
+ private void hibernatePackageForUserL(@NonNull String packageName, int userId,
+ @NonNull UserPackageState pkgState) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mIActivityManager.forceStopPackage(packageName, userId);
+ mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
+ null /* observer */);
+ pkgState.hibernated = true;
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to hibernate due to manager not being available", e);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
/**
+ * Remove a package from hibernation for a given user. The caller should hold {@link #mLock}.
+ *
+ * @param pkgState package hibernation state
+ */
+ private void unhibernatePackageForUserL(@NonNull String packageName, int userId,
+ UserPackageState pkgState) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mIPackageManager.setPackageStoppedState(packageName, false, userId);
+ pkgState.hibernated = false;
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to unhibernate due to manager not being available", e);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+ }
+
+ /**
+ * Put a package into global hibernation, optimizing its storage at a package / APK level.
+ * The caller should hold {@link #mLock}.
+ */
+ private void hibernatePackageGloballyL(@NonNull String packageName) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
+ // TODO(175830194): Delete vdex/odex when DexManager API is built out
+ mGloballyHibernatedPackages.add(packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ /**
+ * Unhibernate a package from global hibernation. The caller should hold {@link #mLock}.
+ */
+ private void unhibernatePackageGloballyL(@NonNull String packageName) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
+ mGloballyHibernatedPackages.remove(packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ /**
* Populates {@link #mUserStates} with the users installed packages. The caller should hold
* {@link #mLock}.
*
@@ -220,8 +304,8 @@ public final class AppHibernationService extends SystemService {
throw new IllegalStateException("Package manager not available.", e);
}
- for (PackageInfo pkg : packageList) {
- packages.put(pkg.packageName, new UserPackageState());
+ for (int i = 0, size = packageList.size(); i < size; i++) {
+ packages.put(packageList.get(i).packageName, new UserPackageState());
}
mUserStates.put(userId, packages);
}
@@ -250,6 +334,12 @@ public final class AppHibernationService extends SystemService {
}
}
+ private void onPackageRemovedForAllUsers(@NonNull String packageName) {
+ synchronized (mLock) {
+ mGloballyHibernatedPackages.remove(packageName);
+ }
+ }
+
/**
* Private helper method to get the real user id and enforce permission checks.
*
@@ -277,13 +367,23 @@ public final class AppHibernationService extends SystemService {
}
@Override
- public boolean isHibernating(String packageName, int userId) {
- return mService.isHibernating(packageName, userId);
+ public boolean isHibernatingForUser(String packageName, int userId) {
+ return mService.isHibernatingForUser(packageName, userId);
+ }
+
+ @Override
+ public void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
+ mService.setHibernatingForUser(packageName, userId, isHibernating);
+ }
+
+ @Override
+ public void setHibernatingGlobally(String packageName, boolean isHibernating) {
+ mService.setHibernatingGlobally(packageName, isHibernating);
}
@Override
- public void setHibernating(String packageName, int userId, boolean isHibernating) {
- mService.setHibernating(packageName, userId, isHibernating);
+ public boolean isHibernatingGlobally(String packageName) {
+ return mService.isHibernatingGlobally(packageName);
}
@Override
@@ -322,6 +422,9 @@ public final class AppHibernationService extends SystemService {
onPackageAdded(packageName, userId);
} else if (ACTION_PACKAGE_REMOVED.equals(action)) {
onPackageRemoved(packageName, userId);
+ if (intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false)) {
+ onPackageRemovedForAllUsers(packageName);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
index 869885e28958..7d6eea25541a 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
@@ -18,7 +18,6 @@ package com.android.server.apphibernation;
import android.os.ShellCommand;
import android.os.UserHandle;
-import android.text.TextUtils;
import java.io.PrintWriter;
@@ -27,6 +26,7 @@ import java.io.PrintWriter;
*/
final class AppHibernationShellCommand extends ShellCommand {
private static final String USER_OPT = "--user";
+ private static final String GLOBAL_OPT = "--global";
private static final int SUCCESS = 0;
private static final int ERROR = -1;
private final AppHibernationService mService;
@@ -51,7 +51,21 @@ final class AppHibernationShellCommand extends ShellCommand {
}
private int runSetState() {
- int userId = parseUserOption();
+ String opt;
+ boolean setsGlobal = false;
+ int userId = UserHandle.USER_CURRENT;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case USER_OPT:
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case GLOBAL_OPT:
+ setsGlobal = true;
+ break;
+ default:
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ }
+ }
String pkg = getNextArgRequired();
if (pkg == null) {
@@ -66,32 +80,43 @@ final class AppHibernationShellCommand extends ShellCommand {
}
boolean newState = Boolean.parseBoolean(newStateRaw);
- mService.setHibernating(pkg, userId, newState);
+ if (setsGlobal) {
+ mService.setHibernatingGlobally(pkg, newState);
+ } else {
+ mService.setHibernatingForUser(pkg, userId, newState);
+ }
return SUCCESS;
}
private int runGetState() {
- int userId = parseUserOption();
+ String opt;
+ boolean requestsGlobal = false;
+ int userId = UserHandle.USER_CURRENT;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case USER_OPT:
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case GLOBAL_OPT:
+ requestsGlobal = true;
+ break;
+ default:
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ }
+ }
String pkg = getNextArgRequired();
if (pkg == null) {
getErrPrintWriter().println("Error: No package specified");
return ERROR;
}
- boolean isHibernating = mService.isHibernating(pkg, userId);
+ boolean isHibernating = requestsGlobal
+ ? mService.isHibernatingGlobally(pkg) : mService.isHibernatingForUser(pkg, userId);
final PrintWriter pw = getOutPrintWriter();
pw.println(isHibernating);
return SUCCESS;
}
- private int parseUserOption() {
- String option = getNextOption();
- if (TextUtils.equals(option, USER_OPT)) {
- return UserHandle.parseUserArg(getNextArgRequired());
- }
- return UserHandle.USER_CURRENT;
- }
-
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -99,11 +124,13 @@ final class AppHibernationShellCommand extends ShellCommand {
pw.println(" help");
pw.println(" Print this help text.");
pw.println("");
- pw.println(" set-state [--user USER_ID] PACKAGE true|false");
- pw.println(" Sets the hibernation state of the package to value specified");
+ pw.println(" set-state [--user USER_ID] [--global] PACKAGE true|false");
+ pw.println(" Sets the hibernation state of the package to value specified. Optionally");
+ pw.println(" may specify a user id or set global hibernation state.");
pw.println("");
- pw.println(" get-state [--user USER_ID] PACKAGE");
- pw.println(" Gets the hibernation state of the package");
+ pw.println(" get-state [--user USER_ID] [--global] PACKAGE");
+ pw.println(" Gets the hibernation state of the package. Optionally may specify a user");
+ pw.println(" id or request global hibernation state.");
pw.println("");
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 271537a9876c..c5237ab8c8e7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -635,10 +635,15 @@ public class BiometricScheduler {
proto.write(BiometricSchedulerProto.CURRENT_OPERATION, mCurrentOperation != null
? mCurrentOperation.mClientMonitor.getProtoEnum() : BiometricsProto.CM_NONE);
proto.write(BiometricSchedulerProto.TOTAL_OPERATIONS, mTotalOperationsHandled);
- Slog.d(getTag(), "Total operations: " + mTotalOperationsHandled);
- for (int i = 0; i < mRecentOperations.size(); i++) {
- Slog.d(getTag(), "Operation: " + mRecentOperations.get(i));
- proto.write(BiometricSchedulerProto.RECENT_OPERATIONS, mRecentOperations.get(i));
+
+ if (!mRecentOperations.isEmpty()) {
+ for (int i = 0; i < mRecentOperations.size(); i++) {
+ proto.write(BiometricSchedulerProto.RECENT_OPERATIONS, mRecentOperations.get(i));
+ }
+ } else {
+ // TODO:(b/178828362) Unsure why protobuf has a problem decoding when an empty list
+ // is returned. So, let's just add a no-op for this case.
+ proto.write(BiometricSchedulerProto.RECENT_OPERATIONS, BiometricsProto.CM_NONE);
}
proto.flush();
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 8ce6746bc7cb..b455a3f4169f 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -70,7 +70,7 @@ import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.UidRangeParcel;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
import android.net.VpnService;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -426,6 +426,7 @@ public class Vpn {
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
+ mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
loadAlwaysOnPackage(keyStore);
}
@@ -1819,12 +1820,12 @@ public class Vpn {
* This method should not be called if underlying interfaces field is needed, because it doesn't
* have enough data to fill VpnInfo.underlyingIfaces field.
*/
- public synchronized VpnInfo getVpnInfo() {
+ public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
if (!isRunningLocked()) {
return null;
}
- return new VpnInfo(mOwnerUID, mInterface, null);
+ return new UnderlyingNetworkInfo(mOwnerUID, mInterface, new ArrayList<>());
}
public synchronized boolean appliesToUid(int uid) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d9ee9a306f07..13dc0b9be21f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -710,9 +710,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
- private void initialize() {
+ private void initialize(int displayState) {
mPowerState = new DisplayPowerState(mBlanker,
- mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId);
+ mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId, displayState);
if (mColorFadeEnabled) {
mColorFadeOnAnimator = ObjectAnimator.ofFloat(
@@ -812,11 +812,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mustNotify = !mDisplayReadyLocked;
}
- // Initialize things the first time the power state is changed.
- if (mustInitialize) {
- initialize();
- }
-
// Compute the basic display state using the policy.
// We might override this below based on other factors.
// Initialise brightness as invalid.
@@ -850,6 +845,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
assert(state != Display.STATE_UNKNOWN);
+ // Initialize things the first time the power state is changed.
+ if (mustInitialize) {
+ initialize(state);
+ }
+
// Apply the proximity sensor.
if (mProximitySensor != null) {
if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 54f30a954c33..173adce00cd9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -72,7 +72,8 @@ final class DisplayPowerState {
private Runnable mCleanListener;
- public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, int displayId) {
+ DisplayPowerState(
+ DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mBlanker = blanker;
@@ -81,14 +82,14 @@ final class DisplayPowerState {
mPhotonicModulator.start();
mDisplayId = displayId;
- // At boot time, we know that the screen is on and the electron beam
- // animation is not playing. We don't know the screen's brightness though,
+ // At boot time, we don't know the screen's brightness,
// so prepare to set it to a known state when the state is next applied.
- // Although we set the brightness to full on here, the display power controller
+ // Although we set the brightness here, the display power controller
// will reset the brightness to a new level immediately before the changes
// actually have a chance to be applied.
- mScreenState = Display.STATE_ON;
- mScreenBrightness = PowerManager.BRIGHTNESS_MAX;
+ mScreenState = displayState;
+ mScreenBrightness = (displayState != Display.STATE_OFF) ? PowerManager.BRIGHTNESS_MAX
+ : PowerManager.BRIGHTNESS_OFF_FLOAT;
scheduleScreenUpdate();
mColorFadePrepared = false;
diff --git a/services/core/java/com/android/server/graphics/GameManagerService.java b/services/core/java/com/android/server/graphics/GameManagerService.java
new file mode 100644
index 000000000000..876f02f38536
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/GameManagerService.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2021 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.graphics;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.GameManager;
+import android.graphics.GameManager.GameMode;
+import android.graphics.IGameManagerService;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+
+/**
+ * Service to manage game related features.
+ *
+ * <p>Game service is a core service that monitors, coordinates game related features,
+ * as well as collect metrics.</p>
+ *
+ * @hide
+ */
+public final class GameManagerService extends IGameManagerService.Stub {
+ public static final String TAG = "GameManagerService";
+
+ private static final boolean DEBUG = false;
+
+ static final int WRITE_SETTINGS = 1;
+ static final int REMOVE_SETTINGS = 2;
+ static final int WRITE_SETTINGS_DELAY = 10 * 1000; // 10 seconds
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+ private final Handler mHandler;
+ @GuardedBy("mLock")
+ private final ArrayMap<Integer, Settings> mSettings = new ArrayMap<>();
+
+ public GameManagerService(Context context) {
+ this(context, createServiceThread().getLooper());
+ }
+
+ GameManagerService(Context context, Looper looper) {
+ mContext = context;
+ mHandler = new SettingsHandler(looper);
+ }
+
+ class SettingsHandler extends Handler {
+
+ SettingsHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ doHandleMessage(msg);
+ }
+
+ void doHandleMessage(Message msg) {
+ switch (msg.what) {
+ case WRITE_SETTINGS: {
+ final int userId = (int) msg.obj;
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ synchronized (mLock) {
+ removeMessages(WRITE_SETTINGS, msg.obj);
+ if (mSettings.containsKey(userId)) {
+ Settings userSettings = mSettings.get(userId);
+ userSettings.writePersistentDataLocked();
+ }
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ break;
+ }
+ case REMOVE_SETTINGS: {
+ final int userId = (int) msg.obj;
+ synchronized (mLock) {
+ // Since the user was removed, ignore previous write message
+ // and do write here.
+ removeMessages(WRITE_SETTINGS, msg.obj);
+ removeMessages(REMOVE_SETTINGS, msg.obj);
+ if (mSettings.containsKey(userId)) {
+ final Settings userSettings = mSettings.get(userId);
+ mSettings.remove(userId);
+ userSettings.writePersistentDataLocked();
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * SystemService lifecycle for GameService.
+ * @hide
+ */
+ public static class Lifecycle extends SystemService {
+ private GameManagerService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new GameManagerService(getContext());
+ publishBinderService(Context.GAME_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ mService.onBootCompleted();
+ }
+ }
+
+ @Override
+ public void onUserStarting(@NonNull TargetUser user) {
+ mService.onUserStarting(user.getUserIdentifier());
+ }
+
+ @Override
+ public void onUserStopping(@NonNull TargetUser user) {
+ mService.onUserStopping(user.getUserIdentifier());
+ }
+ }
+
+ //TODO(b/178111358) Add proper permission check and multi-user handling
+ @Override
+ public @GameMode int getGameMode(String packageName, int userId) {
+ synchronized (mLock) {
+ if (!mSettings.containsKey(userId)) {
+ return GameManager.GAME_MODE_UNSUPPORTED;
+ }
+ Settings userSettings = mSettings.get(userId);
+ return userSettings.getGameModeLocked(packageName);
+ }
+ }
+
+ //TODO(b/178111358) Add proper permission check and multi-user handling
+ @Override
+ public void setGameMode(String packageName, @GameMode int gameMode, int userId) {
+ synchronized (mLock) {
+ if (!mSettings.containsKey(userId)) {
+ return;
+ }
+ Settings userSettings = mSettings.get(userId);
+ userSettings.setGameModeLocked(packageName, gameMode);
+ final Message msg = mHandler.obtainMessage(WRITE_SETTINGS);
+ msg.obj = userId;
+ if (!mHandler.hasEqualMessages(WRITE_SETTINGS, userId)) {
+ mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY);
+ }
+ }
+ }
+
+ /**
+ * Notified when boot is completed.
+ */
+ @VisibleForTesting
+ void onBootCompleted() {
+ Slog.d(TAG, "onBootCompleted");
+ }
+
+ void onUserStarting(int userId) {
+ synchronized (mLock) {
+ if (mSettings.containsKey(userId)) {
+ return;
+ }
+
+ Settings userSettings = new Settings(Environment.getDataSystemDeDirectory(userId));
+ mSettings.put(userId, userSettings);
+ userSettings.readPersistentDataLocked();
+ }
+ }
+
+ void onUserStopping(int userId) {
+ synchronized (mLock) {
+ if (!mSettings.containsKey(userId)) {
+ return;
+ }
+ final Message msg = mHandler.obtainMessage(REMOVE_SETTINGS);
+ msg.obj = userId;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ private static ServiceThread createServiceThread() {
+ ServiceThread handlerThread = new ServiceThread(TAG,
+ Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
+ handlerThread.start();
+ return handlerThread;
+ }
+}
diff --git a/services/core/java/com/android/server/graphics/Settings.java b/services/core/java/com/android/server/graphics/Settings.java
new file mode 100644
index 000000000000..bbd84d037d18
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/Settings.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2021 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.graphics;
+
+import android.graphics.GameManager;
+import android.os.FileUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Persists all GameService related settings.
+ * @hide
+ */
+public class Settings {
+
+ // The XML file follows the below format:
+ // <?xml>
+ // <packages>
+ // <package></package>
+ // ...
+ // </packages>
+ private static final String GAME_SERVICE_FILE_NAME = "game-manager-service.xml";
+
+ private static final String TAG_PACKAGE = "package";
+ private static final String TAG_PACKAGES = "packages";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_GAME_MODE = "gameMode";
+
+ private final File mSystemDir;
+ @VisibleForTesting
+ final AtomicFile mSettingsFile;
+
+ // PackageName -> GameMode
+ private final ArrayMap<String, Integer> mGameModes = new ArrayMap<>();
+
+ Settings(File dataDir) {
+ mSystemDir = new File(dataDir, "system");
+ mSystemDir.mkdirs();
+ FileUtils.setPermissions(mSystemDir.toString(),
+ FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IROTH | FileUtils.S_IXOTH,
+ -1, -1);
+ mSettingsFile = new AtomicFile(new File(mSystemDir, GAME_SERVICE_FILE_NAME));
+ }
+
+ /**
+ * Return the game mode of a given package.
+ * This operation must be synced with an external lock.
+ */
+ int getGameModeLocked(String packageName) {
+ if (mGameModes.containsKey(packageName)) {
+ return mGameModes.get(packageName);
+ }
+ return GameManager.GAME_MODE_UNSUPPORTED;
+ }
+
+ /**
+ * Set the game mode of a given package.
+ * This operation must be synced with an external lock.
+ */
+ void setGameModeLocked(String packageName, int gameMode) {
+ mGameModes.put(packageName, gameMode);
+ }
+
+ /**
+ * Write all current game service settings into disk.
+ * This operation must be synced with an external lock.
+ */
+ void writePersistentDataLocked() {
+ FileOutputStream fstr = null;
+ try {
+ fstr = mSettingsFile.startWrite();
+
+ final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr);
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, TAG_PACKAGES);
+ for (Map.Entry<String, Integer> entry : mGameModes.entrySet()) {
+ serializer.startTag(null, TAG_PACKAGE);
+ serializer.attribute(null, ATTR_NAME, entry.getKey());
+ serializer.attributeInt(null, ATTR_GAME_MODE, entry.getValue());
+ serializer.endTag(null, TAG_PACKAGE);
+ }
+ serializer.endTag(null, TAG_PACKAGES);
+
+ serializer.endDocument();
+
+ mSettingsFile.finishWrite(fstr);
+
+ FileUtils.setPermissions(mSettingsFile.toString(),
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ -1, -1);
+ return;
+ } catch (java.io.IOException e) {
+ mSettingsFile.failWrite(fstr);
+ Slog.wtf(GameManagerService.TAG, "Unable to write game manager service settings, "
+ + "current changes will be lost at reboot", e);
+ }
+ }
+
+ /**
+ * Read game service settings from the disk.
+ * This operation must be synced with an external lock.
+ */
+ boolean readPersistentDataLocked() {
+ mGameModes.clear();
+
+ try {
+ final FileInputStream str = mSettingsFile.openRead();
+
+ final TypedXmlPullParser parser = Xml.resolvePullParser(str);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ Slog.wtf(GameManagerService.TAG,
+ "No start tag found in package manager settings");
+ return 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(TAG_PACKAGE)) {
+ readPackage(parser);
+ } else {
+ Slog.w(GameManagerService.TAG, "Unknown element: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ } catch (XmlPullParserException | java.io.IOException e) {
+ Slog.wtf(GameManagerService.TAG, "Error reading package manager settings", e);
+ return false;
+ }
+
+ return true;
+ }
+
+ private void readPackage(TypedXmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ String name = null;
+ int gameMode = GameManager.GAME_MODE_UNSUPPORTED;
+ try {
+ name = parser.getAttributeValue(null, ATTR_NAME);
+ gameMode = parser.getAttributeInt(null, ATTR_GAME_MODE);
+ } catch (XmlPullParserException e) {
+ Slog.wtf(GameManagerService.TAG, "Error reading game mode", e);
+ }
+ if (name != null) {
+ mGameModes.put(name, gameMode);
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index b5b93d6d8ecd..142f64f0a510 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -74,7 +74,6 @@ import android.os.ICancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
@@ -1297,10 +1296,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- long currentNanos = SystemClock.elapsedRealtimeNanos();
- long deltaMs = NANOSECONDS.toMillis(
- location.getElapsedRealtimeAgeNanos(currentNanos));
- return new LocationTime(location.getTime() + deltaMs, currentNanos);
+ return new LocationTime(location.getTime(), location.getElapsedRealtimeNanos());
}
}
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
index d4393d6a83d2..90c233030ed1 100644
--- a/services/core/java/com/android/server/location/contexthub/OWNERS
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -1,2 +1,3 @@
arthuri@google.com
bduddie@google.com
+stange@google.com
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
index 8399f54764e0..a1e18bd5a6bd 100644
--- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -106,6 +106,8 @@ public class ResumeOnRebootServiceProvider {
private final Context mContext;
private final ComponentName mComponentName;
private IResumeOnRebootService mBinder;
+ @Nullable
+ ServiceConnection mServiceConnection;
private ResumeOnRebootServiceConnection(Context context,
@NonNull ComponentName componentName) {
@@ -115,17 +117,9 @@ public class ResumeOnRebootServiceProvider {
/** Unbind from the service */
public void unbindService() {
- mContext.unbindService(new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mBinder = null;
-
- }
- });
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ }
}
/** Bind to the service */
@@ -134,17 +128,19 @@ public class ResumeOnRebootServiceProvider {
CountDownLatch connectionLatch = new CountDownLatch(1);
Intent intent = new Intent();
intent.setComponent(mComponentName);
- final boolean success = mContext.bindServiceAsUser(intent, new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mBinder = IResumeOnRebootService.Stub.asInterface(service);
- connectionLatch.countDown();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- },
+ mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mBinder = IResumeOnRebootService.Stub.asInterface(service);
+ connectionLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBinder = null;
+ }
+ };
+ final boolean success = mContext.bindServiceAsUser(intent, mServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
BackgroundThread.getHandler(), UserHandle.SYSTEM);
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 4faa7903c630..d042b882fee1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -27,7 +27,7 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import android.annotation.Nullable;
import android.net.INetd;
import android.net.NetworkStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
import android.net.util.NetdService;
import android.os.RemoteException;
import android.os.StrictMode;
@@ -81,7 +81,7 @@ public class NetworkStatsFactory {
private final Object mPersistentDataLock = new Object();
/** Set containing info about active VPNs and their underlying networks. */
- private volatile VpnInfo[] mVpnInfos = new VpnInfo[0];
+ private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0];
// A persistent snapshot of cumulative stats since device start
@GuardedBy("mPersistentDataLock")
@@ -116,8 +116,8 @@ public class NetworkStatsFactory {
*
* @param vpnArray The snapshot of the currently-running VPNs.
*/
- public void updateVpnInfos(VpnInfo[] vpnArray) {
- mVpnInfos = vpnArray.clone();
+ public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) {
+ mUnderlyingNetworkInfos = vpnArray.clone();
}
/**
@@ -319,7 +319,7 @@ public class NetworkStatsFactory {
// code that will acquire other locks within the system server. See b/134244752.
synchronized (mPersistentDataLock) {
// Take a reference. If this gets swapped out, we still have the old reference.
- final VpnInfo[] vpnArray = mVpnInfos;
+ final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos;
// Take a defensive copy. mPersistSnapshot is mutated in some cases below
final NetworkStats prev = mPersistSnapshot.clone();
@@ -369,8 +369,8 @@ public class NetworkStatsFactory {
}
@GuardedBy("mPersistentDataLock")
- private NetworkStats adjustForTunAnd464Xlat(
- NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) {
+ private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats,
+ NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) {
// Calculate delta from last snapshot
final NetworkStats delta = uidDetailStats.subtract(previousStats);
@@ -381,8 +381,9 @@ public class NetworkStatsFactory {
delta.apply464xlatAdjustments(mStackedIfaces);
// Migrate data usage over a VPN to the TUN network.
- for (VpnInfo info : vpnArray) {
- delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces);
+ for (UnderlyingNetworkInfo info : vpnArray) {
+ delta.migrateTun(info.ownerUid, info.iface,
+ info.underlyingIfaces.toArray(new String[0]));
// Filter out debug entries as that may lead to over counting.
delta.filterDebugEntries();
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4be7b483af16..0ab35a911025 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -104,8 +104,8 @@ import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
-import android.net.VpnInfo;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProvider;
@@ -973,7 +973,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
Network[] defaultNetworks,
NetworkState[] networkStates,
String activeIface,
- VpnInfo[] vpnInfos) {
+ UnderlyingNetworkInfo[] underlyingNetworkInfos) {
checkNetworkStackPermission(mContext);
final long token = Binder.clearCallingIdentity();
@@ -986,7 +986,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// Update the VPN underlying interfaces only after the poll is made and tun data has been
// migrated. Otherwise the migration would use the new interfaces instead of the ones that
// were current when the polled data was transferred.
- mStatsFactory.updateVpnInfos(vpnInfos);
+ mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4eaac2e44da8..7c425698e507 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3299,17 +3299,28 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ private void linkFile(String relativePath, String fromBase, String toBase) throws IOException {
+ try {
+ // Try
+ if (mIncrementalFileStorages != null && mIncrementalFileStorages.makeLink(relativePath,
+ fromBase, toBase)) {
+ return;
+ }
+ mPm.mInstaller.linkFile(relativePath, fromBase, toBase);
+ } catch (InstallerException | IOException e) {
+ throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
+ + fromBase + ", " + toBase + ")", e);
+ }
+ }
+
private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
throws IOException {
for (File fromFile : fromFiles) {
final String relativePath = getRelativePath(fromFile, fromDir);
- try {
- mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
- toDir.getAbsolutePath());
- } catch (InstallerException e) {
- throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
- + fromDir + ", " + toDir + ")", e);
- }
+ final String fromBase = fromDir.getAbsolutePath();
+ final String toBase = toDir.getAbsolutePath();
+
+ linkFile(relativePath, fromBase, toBase);
}
Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
@@ -3577,12 +3588,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Retrying commit.
if (mIncrementalFileStorages != null) {
- try {
- mIncrementalFileStorages.startLoading();
- } catch (IOException e) {
- throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
- e.getCause());
- }
return false;
}
@@ -3757,9 +3762,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
};
try {
+ final PackageInfo pkgInfo = mPm.getPackageInfo(this.params.appPackageName, 0,
+ userId);
+ final File inheritedDir =
+ (pkgInfo != null && pkgInfo.applicationInfo != null) ? new File(
+ pkgInfo.applicationInfo.getCodePath()).getParentFile() : null;
+
mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
- params, statusListener, healthCheckParams, healthListener, addedFiles,
- perUidReadTimeouts);
+ inheritedDir, params, statusListener, healthCheckParams, healthListener,
+ addedFiles, perUidReadTimeouts);
return false;
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c27e670c4c99..f772f63a08ac 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2153,6 +2153,10 @@ public class PackageManagerService extends IPackageManager.Stub
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message);
+ SigningDetails getSigningDetails(@NonNull String packageName);
+ SigningDetails getSigningDetails(int uid);
+ boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
+ boolean filterAppAccess(String packageName, int callingUid, int userId);
}
/**
@@ -4578,6 +4582,40 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException(errorMessage);
}
+ public SigningDetails getSigningDetails(@NonNull String packageName) {
+ AndroidPackage p = mPackages.get(packageName);
+ if (p == null) {
+ return null;
+ }
+ return p.getSigningDetails();
+ }
+
+ public SigningDetails getSigningDetails(int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ return ((SharedUserSetting) obj).signatures.mSigningDetails;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ return ps.signatures.mSigningDetails;
+ }
+ }
+ return SigningDetails.UNKNOWN;
+ }
+
+ public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ PackageSetting ps = getPackageSetting(pkg.getPackageName());
+ return shouldFilterApplicationLocked(ps, callingUid,
+ userId);
+ }
+
+ public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ PackageSetting ps = getPackageSetting(packageName);
+ return shouldFilterApplicationLocked(ps, callingUid,
+ userId);
+ }
+
}
/**
@@ -4728,6 +4766,26 @@ public class PackageManagerService extends IPackageManager.Stub
return super.getPackageUidInternal(packageName, flags, userId, callingUid);
}
}
+ public SigningDetails getSigningDetails(@NonNull String packageName) {
+ synchronized (mLock) {
+ return super.getSigningDetails(packageName);
+ }
+ }
+ public SigningDetails getSigningDetails(int uid) {
+ synchronized (mLock) {
+ return super.getSigningDetails(uid);
+ }
+ }
+ public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ synchronized (mLock) {
+ return super.filterAppAccess(pkg, callingUid, userId);
+ }
+ }
+ public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ synchronized (mLock) {
+ return super.filterAppAccess(packageName, callingUid, userId);
+ }
+ }
}
@@ -18105,13 +18163,15 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- String codePath = codeFile.getAbsolutePath();
- if (mIncrementalManager != null && isIncrementalPath(codePath)) {
- mIncrementalManager.onPackageRemoved(codePath);
- }
+ final boolean isIncremental = (mIncrementalManager != null && isIncrementalPath(
+ codeFile.getAbsolutePath()));
removeCodePathLI(codeFile);
+ if (isIncremental) {
+ mIncrementalManager.onPackageRemoved(codeFile);
+ }
+
return true;
}
@@ -26560,6 +26620,22 @@ public class PackageManagerService extends IPackageManager.Stub
return snapshotComputer().getPackage(uid);
}
+ private SigningDetails getSigningDetails(@NonNull String packageName) {
+ return snapshotComputer().getSigningDetails(packageName);
+ }
+
+ private SigningDetails getSigningDetails(int uid) {
+ return snapshotComputer().getSigningDetails(uid);
+ }
+
+ private boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ return snapshotComputer().filterAppAccess(pkg, callingUid, userId);
+ }
+
+ private boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ return snapshotComputer().filterAppAccess(packageName, callingUid, userId);
+ }
+
private class PackageManagerInternalImpl extends PackageManagerInternal {
@Override
public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
@@ -26615,29 +26691,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
private SigningDetails getSigningDetails(@NonNull String packageName) {
- synchronized (mLock) {
- AndroidPackage p = mPackages.get(packageName);
- if (p == null) {
- return null;
- }
- return p.getSigningDetails();
- }
+ return PackageManagerService.this.getSigningDetails(packageName);
}
private SigningDetails getSigningDetails(int uid) {
- synchronized (mLock) {
- final int appId = UserHandle.getAppId(uid);
- final Object obj = mSettings.getSettingLPr(appId);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- return ((SharedUserSetting) obj).signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- return ps.signatures.mSigningDetails;
- }
- }
- return SigningDetails.UNKNOWN;
- }
+ return PackageManagerService.this.getSigningDetails(uid);
}
@Override
@@ -26652,20 +26710,12 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- synchronized (mLock) {
- PackageSetting ps = getPackageSetting(pkg.getPackageName());
- return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
- userId);
- }
+ return PackageManagerService.this.filterAppAccess(pkg, callingUid, userId);
}
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- synchronized (mLock) {
- PackageSetting ps = getPackageSetting(packageName);
- return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
- userId);
- }
+ return PackageManagerService.this.filterAppAccess(packageName, callingUid, userId);
}
@Override
@@ -28304,6 +28354,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
continue;
}
+ if (ps.appId < Process.FIRST_APPLICATION_UID) {
+ if (DEBUG_PER_UID_READ_TIMEOUTS) {
+ Slog.i(TAG, "PerUidReadTimeouts: package is system, appId=" + ps.appId);
+ }
+ continue;
+ }
+
final AndroidPackage pkg = ps.getPkg();
if (pkg.getLongVersionCode() < perPackage.versionCodes.minVersionCode
|| pkg.getLongVersionCode() > perPackage.versionCodes.maxVersionCode) {
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 8c31d88c6f15..aff871118a34 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3356,11 +3356,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// - or its signing certificate was rotated from the source package's certificate
// - or its signing certificate is a previous signing certificate of the defining
// package, and the defining package still trusts the old certificate for permissions
+ // - or it shares a common signing certificate in its lineage with the defining package,
+ // and the defining package still trusts the old certificate for permissions
// - or it shares the above relationships with the system package
final PackageParser.SigningDetails sourceSigningDetails =
getSourcePackageSigningDetails(bp);
- return pkg.getSigningDetails().hasAncestorOrSelf(sourceSigningDetails)
- || sourceSigningDetails.checkCapability(
+ return sourceSigningDetails.hasCommonSignerWithCapability(
pkg.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION)
|| pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails())
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c073b430c8df..89e7986fc4bc 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3491,15 +3491,27 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+ final int keyCode = event.getKeyCode();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
+ || event.isWakeKey();
+
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
+ // Exception: Wake and power key events are forwarded to PowerManager to allow it to
+ // wake from quiescent mode during boot.
+ if (down && (keyCode == KeyEvent.KEYCODE_POWER
+ || keyCode == KeyEvent.KEYCODE_TV_POWER)) {
+ wakeUpFromPowerKey(event.getDownTime());
+ } else if (down && (isWakeKey || keyCode == KeyEvent.KEYCODE_WAKEUP)
+ && isWakeKeyWhenScreenOff(keyCode)) {
+ wakeUpFromWakeKey(event);
+ }
return 0;
}
final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
- final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
- final int keyCode = event.getKeyCode();
final int displayId = event.getDisplayId();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
@@ -3518,8 +3530,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Basic policy based on interactive state.
int result;
- boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
- || event.isWakeKey();
if (interactive || (isInjected && !isWakeKey)) {
// When the device is interactive or the key is injected pass the
// key to the application.
@@ -4740,7 +4750,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
- screenTurningOn(DEFAULT_DISPLAY, null);
+ screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener());
screenTurnedOn(DEFAULT_DISPLAY);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 54d05124c114..db4b6d0a3005 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1036,12 +1036,12 @@ public final class PowerManagerService extends SystemService
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+ updatePowerStateLocked();
if (sQuiescent) {
goToSleepNoUpdateLocked(mClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
}
- updatePowerStateLocked();
}
}
}
@@ -1679,8 +1679,15 @@ public final class PowerManagerService extends SystemService
Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
}
- if (eventTime < mLastSleepTime || getWakefulnessLocked() == WAKEFULNESS_AWAKE
- || mForceSuspendActive || !mSystemReady) {
+ if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
+ return false;
+ }
+
+ if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
+ if (!mBootCompleted && sQuiescent) {
+ mDirty |= DIRTY_QUIESCENT;
+ return true;
+ }
return false;
}
@@ -2821,7 +2828,7 @@ public final class PowerManagerService extends SystemService
*
* This function recalculates the display power state each time.
*
- * @return True if the display became ready.
+ * @return true if the display became ready.
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
@@ -2830,7 +2837,11 @@ public final class PowerManagerService extends SystemService
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
DIRTY_QUIESCENT)) != 0) {
if ((dirty & DIRTY_QUIESCENT) != 0) {
- sQuiescent = false;
+ if (mDisplayReady) {
+ sQuiescent = false;
+ } else {
+ mDirty |= DIRTY_QUIESCENT;
+ }
}
final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
@@ -5605,7 +5616,7 @@ public final class PowerManagerService extends SystemService
* ignore the proximity sensor. We don't turn off the proximity sensor because
* we still want it to be reenabled if it's state changes.
*
- * @return True if the proximity sensor was successfully ignored and we should
+ * @return true if the proximity sensor was successfully ignored and we should
* consume the key event.
*/
private boolean interceptPowerKeyDownInternal(KeyEvent event) {
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index 5bd907fb2654..5fe5db69bc8e 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -69,6 +69,8 @@ public class PowerStatsService extends SystemService {
private BatteryTrigger mBatteryTrigger;
@Nullable
private TimerTrigger mTimerTrigger;
+ @Nullable
+ private StatsPullAtomCallbackImpl mPullAtomCallback;
@VisibleForTesting
static class Injector {
@@ -119,6 +121,11 @@ public class PowerStatsService extends SystemService {
TimerTrigger createTimerTrigger(Context context, PowerStatsLogger powerStatsLogger) {
return new TimerTrigger(context, powerStatsLogger, true /* trigger enabled */);
}
+
+ StatsPullAtomCallbackImpl createStatsPullerImpl(Context context,
+ IPowerStatsHALWrapper powerStatsHALWrapper) {
+ return new StatsPullAtomCallbackImpl(context, powerStatsHALWrapper);
+ }
}
private final class BinderService extends Binder {
@@ -156,8 +163,10 @@ public class PowerStatsService extends SystemService {
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_BOOT_COMPLETED) {
- onSystemServiceReady();
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ onSystemServicesReady();
+ } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+ onBootCompleted();
}
}
@@ -170,7 +179,18 @@ public class PowerStatsService extends SystemService {
publishBinderService(Context.POWER_STATS_SERVICE, new BinderService());
}
- private void onSystemServiceReady() {
+ private void onSystemServicesReady() {
+ if (getPowerStatsHal().isInitialized()) {
+ if (DEBUG) Slog.d(TAG, "Starting PowerStatsService statsd pullers");
+
+ // Only start statsd pullers if initialization is successful.
+ mPullAtomCallback = mInjector.createStatsPullerImpl(mContext, getPowerStatsHal());
+ } else {
+ Slog.e(TAG, "Failed to start PowerStatsService statsd pullers");
+ }
+ }
+
+ private void onBootCompleted() {
if (getPowerStatsHal().isInitialized()) {
if (DEBUG) Slog.d(TAG, "Starting PowerStatsService loggers");
diff --git a/services/core/java/com/android/server/powerstats/StatsPullAtomCallbackImpl.java b/services/core/java/com/android/server/powerstats/StatsPullAtomCallbackImpl.java
new file mode 100644
index 000000000000..f8b9601bfd62
--- /dev/null
+++ b/services/core/java/com/android/server/powerstats/StatsPullAtomCallbackImpl.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.powerstats;
+
+import android.app.StatsManager;
+import android.content.Context;
+import android.hardware.power.stats.Channel;
+import android.hardware.power.stats.EnergyMeasurement;
+import android.hardware.power.stats.PowerEntity;
+import android.hardware.power.stats.State;
+import android.hardware.power.stats.StateResidency;
+import android.hardware.power.stats.StateResidencyResult;
+import android.util.StatsEvent;
+
+import com.android.internal.util.ConcurrentUtils;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * StatsPullAtomCallbackImpl is responsible implementing the stats pullers for
+ * SUBSYSTEM_SLEEP_STATE and ON_DEVICE_POWER_MEASUREMENT statsd atoms.
+ */
+public class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
+ private Context mContext;
+ private IPowerStatsHALWrapper mPowerStatsHALWrapper;
+ private Map<Integer, Channel> mChannels = new HashMap();
+ private Map<Integer, String> mEntityNames = new HashMap();
+ private Map<Integer, Map<Integer, String>> mStateNames = new HashMap();;
+
+ @Override
+ public int onPullAtom(int atomTag, List<StatsEvent> data) {
+ switch (atomTag) {
+ case FrameworkStatsLog.SUBSYSTEM_SLEEP_STATE:
+ return pullSubsystemSleepState(atomTag, data);
+ case FrameworkStatsLog.ON_DEVICE_POWER_MEASUREMENT:
+ return pullOnDevicePowerMeasurement(atomTag, data);
+ default:
+ throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
+ }
+ }
+
+ private void initPullOnDevicePowerMeasurement() {
+ Channel[] channels = mPowerStatsHALWrapper.getEnergyMeterInfo();
+ if (channels == null) {
+ return;
+ }
+
+ for (int i = 0; i < channels.length; i++) {
+ final Channel channel = channels[i];
+ mChannels.put(channel.id, channel);
+ }
+ }
+
+ private int pullOnDevicePowerMeasurement(int atomTag, List<StatsEvent> events) {
+ EnergyMeasurement[] energyMeasurements = mPowerStatsHALWrapper.readEnergyMeters(new int[0]);
+ if (energyMeasurements == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ for (int i = 0; i < energyMeasurements.length; i++) {
+ // Only report energy measurements that have been accumulated since boot
+ final EnergyMeasurement energyMeasurement = energyMeasurements[i];
+ if (energyMeasurement.durationMs == energyMeasurement.timestampMs) {
+ events.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ mChannels.get(energyMeasurement.id).subsystem,
+ mChannels.get(energyMeasurement.id).name,
+ energyMeasurement.durationMs,
+ energyMeasurement.energyUWs));
+ }
+ }
+
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ private void initSubsystemSleepState() {
+ PowerEntity[] entities = mPowerStatsHALWrapper.getPowerEntityInfo();
+ if (entities == null) {
+ return;
+ }
+
+ for (int i = 0; i < entities.length; i++) {
+ final PowerEntity entity = entities[i];
+ Map<Integer, String> states = new HashMap();
+ for (int j = 0; j < entity.states.length; j++) {
+ final State state = entity.states[j];
+ states.put(state.id, state.name);
+ }
+
+ mEntityNames.put(entity.id, entity.name);
+ mStateNames.put(entity.id, states);
+ }
+ }
+
+ private int pullSubsystemSleepState(int atomTag, List<StatsEvent> events) {
+ StateResidencyResult[] results = mPowerStatsHALWrapper.getStateResidency(new int[0]);
+ if (results == null) {
+ return StatsManager.PULL_SKIP;
+ }
+ for (int i = 0; i < results.length; i++) {
+ final StateResidencyResult result = results[i];
+ for (int j = 0; j < result.stateResidencyData.length; j++) {
+ final StateResidency stateResidency = result.stateResidencyData[j];
+ events.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ mEntityNames.get(result.id),
+ mStateNames.get(result.id).get(stateResidency.id),
+ stateResidency.totalStateEntryCount,
+ stateResidency.totalTimeInStateMs));
+ }
+ }
+
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ public StatsPullAtomCallbackImpl(Context context, IPowerStatsHALWrapper powerStatsHALWrapper) {
+ mContext = context;
+ mPowerStatsHALWrapper = powerStatsHALWrapper;
+ initPullOnDevicePowerMeasurement();
+ initSubsystemSleepState();
+
+ StatsManager manager = mContext.getSystemService(StatsManager.class);
+ manager.setPullAtomCallback(
+ FrameworkStatsLog.SUBSYSTEM_SLEEP_STATE,
+ null, // use default PullAtomMetadata values
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ this);
+ manager.setPullAtomCallback(
+ FrameworkStatsLog.ON_DEVICE_POWER_MEASUREMENT,
+ null, // use default PullAtomMetadata values
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ this);
+ }
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 0cc2a6c52b1d..263776c63db6 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -407,8 +407,6 @@ public class StatsPullAtomService extends SystemService {
mContext = context;
}
- private native void nativeInit();
-
/**
* Use of this StatsPullAtomCallbackImpl means we avoid one class per tagId, which we would
* get if we used lambdas.
@@ -681,7 +679,6 @@ public class StatsPullAtomService extends SystemService {
super.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
BackgroundThread.getHandler().post(() -> {
- nativeInit();
initializePullersState();
registerPullers();
registerEventListeners();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 081141c5519c..7d2075cca84d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -279,12 +279,6 @@ public abstract class ActivityTaskManagerInternal {
public abstract void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition);
/**
- * This enforces {@code func} can only be called if either the caller is Recents activity or
- * has {@code permission}.
- */
- public abstract void enforceCallerIsRecentsOrHasPermission(String permission, String func);
-
- /**
* Returns true if the app can close system dialogs. Otherwise it either throws a {@link
* SecurityException} or returns false with a logcat message depending on whether the app
* targets SDK level {@link android.os.Build.VERSION_CODES#S} or not.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0db3f9855df..9e2e58fddd18 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -35,6 +35,7 @@ import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -1577,7 +1578,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void startRecentsActivity(Intent intent, long eventTime,
@Nullable IRecentsAnimationRunner recentsAnimationRunner) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "startRecentsActivity()");
+ enforceTaskPermission("startRecentsActivity()");
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
@@ -1605,7 +1606,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public final int startActivityFromRecents(int taskId, Bundle bOptions) {
- enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
+ mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"startActivityFromRecents()");
final int callingPid = Binder.getCallingPid();
@@ -1735,7 +1736,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public RootTaskInfo getFocusedRootTaskInfo() throws RemoteException {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getFocusedRootTaskInfo()");
+ enforceTaskPermission("getFocusedRootTaskInfo()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -1796,7 +1797,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public boolean removeTask(int taskId) {
- enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeTask()");
+ mAmInternal.enforceCallingPermission(REMOVE_TASKS, "removeTask()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -1821,7 +1822,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void removeAllVisibleRecentTasks() {
- enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeAllVisibleRecentTasks()");
+ mAmInternal.enforceCallingPermission(REMOVE_TASKS, "removeAllVisibleRecentTasks()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -1860,8 +1861,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public ActivityManager.TaskDescription getTaskDescription(int id) {
synchronized (mGlobalLock) {
- enforceCallerIsRecentsOrHasPermission(
- MANAGE_ACTIVITY_TASKS, "getTaskDescription()");
+ enforceTaskPermission("getTaskDescription()");
final Task tr = mRootWindowContainer.anyTaskForId(id,
MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (tr != null) {
@@ -1873,10 +1873,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "setTaskWindowingMode()");
+ enforceTaskPermission("setTaskWindowingMode()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
+ if (isInLockTaskMode() && windowingMode != WINDOWING_MODE_FULLSCREEN) {
+ Slog.w(TAG, "setTaskWindowingMode: Is in lock task mode="
+ + getLockTaskModeState());
+ return false;
+ }
+
if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
return setTaskWindowingModeSplitScreen(taskId, windowingMode, toTop);
}
@@ -2103,7 +2109,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void moveTaskToRootTask(int taskId, int rootTaskId, boolean toTop) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "moveTaskToRootTask()");
+ enforceTaskPermission("moveTaskToRootTask()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -2141,11 +2147,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
throw new IllegalArgumentException("Calling setTaskWindowingModeSplitScreen with non"
+ "split-screen mode: " + windowingMode);
}
- if (isInLockTaskMode()) {
- Slog.w(TAG, "setTaskWindowingModeSplitScreen: Is in lock task mode="
- + getLockTaskModeState());
- return false;
- }
final Task task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_ATTACHED_TASK_ONLY);
@@ -2197,8 +2198,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
*/
@Override
public void removeRootTasksInWindowingModes(int[] windowingModes) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS,
- "removeRootTasksInWindowingModes()");
+ enforceTaskPermission("removeRootTasksInWindowingModes()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
@@ -2212,8 +2212,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void removeRootTasksWithActivityTypes(int[] activityTypes) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS,
- "removeRootTasksWithActivityTypes()");
+ enforceTaskPermission("removeRootTasksWithActivityTypes()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
@@ -2239,7 +2238,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public List<RootTaskInfo> getAllRootTaskInfos() {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getAllRootTaskInfos()");
+ enforceTaskPermission("getAllRootTaskInfos()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2252,7 +2251,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getRootTaskInfo()");
+ enforceTaskPermission("getRootTaskInfo()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2265,8 +2264,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public List<RootTaskInfo> getAllRootTaskInfosOnDisplay(int displayId) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS,
- "getAllRootTaskInfosOnDisplay()");
+ enforceTaskPermission("getAllRootTaskInfosOnDisplay()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2280,7 +2278,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public RootTaskInfo getRootTaskInfoOnDisplay(int windowingMode, int activityType,
int displayId) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getRootTaskInfoOnDisplay()");
+ enforceTaskPermission("getRootTaskInfoOnDisplay()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2293,7 +2291,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "cancelRecentsAnimation()");
+ enforceTaskPermission("cancelRecentsAnimation()");
final long callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
@@ -2728,16 +2726,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** Sets the task stack listener that gets callbacks when a task stack changes. */
@Override
public void registerTaskStackListener(ITaskStackListener listener) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS,
- "registerTaskStackListener()");
+ enforceTaskPermission("registerTaskStackListener()");
mTaskChangeNotificationController.registerTaskStackListener(listener);
}
/** Unregister a task stack listener so that it stops receiving callbacks. */
@Override
public void unregisterTaskStackListener(ITaskStackListener listener) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS,
- "unregisterTaskStackListener()");
+ enforceTaskPermission("unregisterTaskStackListener()");
mTaskChangeNotificationController.unregisterTaskStackListener(listener);
}
@@ -2790,19 +2786,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
permission, Binder.getCallingPid(), Binder.getCallingUid());
}
- /** This can be called with or without the global lock held. */
- void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
- if (getRecentTasks().isCallerRecents(Binder.getCallingUid())) {
- return;
- }
-
- if (permission.equals(MANAGE_ACTIVITY_TASKS) || permission.equals(MANAGE_ACTIVITY_STACKS)) {
- enforceTaskPermission(func);
- } else {
- mAmInternal.enforceCallingPermission(permission, func);
- }
- }
-
/**
* Returns true if the app can close system dialogs. Otherwise it either throws a {@link
* SecurityException} or returns false with a logcat message depending on whether the app
@@ -3263,7 +3246,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void resizePrimarySplitScreen(Rect dockedBounds, Rect tempDockedTaskBounds,
Rect tempDockedTaskInsetBounds,
Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "resizePrimarySplitScreen()");
+ enforceTaskPermission("resizePrimarySplitScreen()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -3301,7 +3284,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void setSplitScreenResizing(boolean resizing) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "setSplitScreenResizing()");
+ enforceTaskPermission("setSplitScreenResizing()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -3371,8 +3354,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void cancelTaskWindowTransition(int taskId) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS,
- "cancelTaskWindowTransition()");
+ enforceTaskPermission("cancelTaskWindowTransition()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -3391,7 +3373,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public TaskSnapshot getTaskSnapshot(int taskId, boolean isLowResolution) {
- enforceCallerIsRecentsOrHasPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
+ mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
final long ident = Binder.clearCallingIdentity();
try {
return getTaskSnapshot(taskId, isLowResolution, true /* restoreFromDisk */);
@@ -3526,7 +3508,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void stopAppSwitches() {
- enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "stopAppSwitches");
+ mAmInternal.enforceCallingPermission(STOP_APP_SWITCHES, "stopAppSwitches");
synchronized (mGlobalLock) {
mAppSwitchesAllowed = false;
mLastStopAppSwitchesTime = SystemClock.uptimeMillis();
@@ -3535,7 +3517,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void resumeAppSwitches() {
- enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
+ mAmInternal.enforceCallingPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
synchronized (mGlobalLock) {
mAppSwitchesAllowed = true;
}
@@ -5135,11 +5117,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
- ActivityTaskManagerService.this.enforceCallerIsRecentsOrHasPermission(permission, func);
- }
-
- @Override
public boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
return ActivityTaskManagerService.this.checkCanCloseSystemDialogs(pid, uid,
packageName);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f293fc373bfe..ece101d2e605 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -190,6 +190,7 @@ import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayCutout;
+import android.view.DisplayCutout.CutoutPathParserInfo;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
@@ -1934,18 +1935,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
return WmDisplayCutout.NO_CUTOUT;
}
- final Insets waterfallInsets =
- RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
if (rotation == ROTATION_0) {
return WmDisplayCutout.computeSafeInsets(
cutout, mInitialDisplayWidth, mInitialDisplayHeight);
}
+ final Insets waterfallInsets =
+ RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final Rect[] newBounds = mRotationUtil.getRotatedBounds(
cutout.getBoundingRectsAll(),
rotation, mInitialDisplayWidth, mInitialDisplayHeight);
+ final CutoutPathParserInfo info = cutout.getCutoutPathParserInfo();
+ final CutoutPathParserInfo newInfo = new CutoutPathParserInfo(
+ info.getDisplayWidth(), info.getDisplayHeight(), info.getDensity(),
+ info.getCutoutSpec(), rotation, info.getScale());
return WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
+ DisplayCutout.constructDisplayCutout(newBounds, waterfallInsets, newInfo),
rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
}
@@ -4102,8 +4107,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* Callbacks when the given type of {@link WindowContainer} animation finished running in the
* hierarchy.
*/
- void onWindowAnimationFinished(int type) {
+ void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
if (type == ANIMATION_TYPE_APP_TRANSITION || type == ANIMATION_TYPE_RECENTS) {
+ // Unfreeze the insets state of the frozen target when the animation finished if exists.
+ final Task task = wc.asTask();
+ if (task != null) {
+ task.forAllWindows(w -> {
+ w.clearFrozenInsetsState();
+ }, true /* traverseTopToBottom */);
+ }
removeImeSurfaceImmediately();
}
}
@@ -4180,12 +4192,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mInsetsStateController.getImeSourceProvider().checkShowImePostLayout();
mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
- mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
- mLastHasContent,
- mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
- mTmpApplySurfaceChangesTransactionState.preferredModeId,
- mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
- true /* inTraversal, must call performTraversalInTrans... below */);
+ if (!mWmService.mDisplayFrozen) {
+ mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
+ mLastHasContent,
+ mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
+ mTmpApplySurfaceChangesTransactionState.preferredModeId,
+ mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
+ true /* inTraversal, must call performTraversalInTrans... below */);
+ }
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
if (wallpaperVisible != mLastWallpaperVisible) {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 398049fb97c3..267f67759a24 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -74,7 +74,7 @@ class InsetsStateController {
private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
- if (w.isVisible()) {
+ if (w.isReadyToDispatchInsetsState()) {
w.notifyInsetsChanged();
}
};
@@ -117,7 +117,8 @@ class InsetsStateController {
final @InternalInsetsType int type = provider != null
? provider.getSource().getType() : ITYPE_INVALID;
return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
- isAboveIme(target));
+ isAboveIme(target),
+ target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() : mState);
}
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
@@ -132,7 +133,7 @@ class InsetsStateController {
final @WindowingMode int windowingMode = token != null
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
- return getInsetsForTarget(type, windowingMode, alwaysOnTop, isAboveIme(token));
+ return getInsetsForTarget(type, windowingMode, alwaysOnTop, isAboveIme(token), mState);
}
private boolean isAboveIme(WindowContainer target) {
@@ -180,9 +181,8 @@ class InsetsStateController {
* @see #getInsetsForWindowMetrics
*/
private InsetsState getInsetsForTarget(@InternalInsetsType int type,
- @WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
- InsetsState state = mState;
-
+ @WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme,
+ @NonNull InsetsState state) {
if (type != ITYPE_INVALID) {
state = new InsetsState(state);
state.removeSource(type);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b1606c506d5b..3d3e31da469c 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -103,6 +103,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
private final ArraySet<WindowSurfaceController> mAlertWindowSurfaces = new ArraySet<>();
private final DragDropController mDragDropController;
final boolean mCanAddInternalSystemWindow;
+ private final boolean mCanStartTasksFromRecents;
+
// If non-system overlays from this process can be hidden by the user or app using
// HIDE_NON_SYSTEM_OVERLAY_WINDOWS.
final boolean mOverlaysCanBeHidden;
@@ -134,6 +136,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
mCanCreateSystemApplicationOverlay =
service.mContext.checkCallingOrSelfPermission(SYSTEM_APPLICATION_OVERLAY)
== PERMISSION_GRANTED;
+ mCanStartTasksFromRecents = service.mContext.checkCallingOrSelfPermission(
+ START_TASKS_FROM_RECENTS) == PERMISSION_GRANTED;
mOverlaysCanBeHidden = !mCanAddInternalSystemWindow
&& !mService.mAtmInternal.isCallerRecents(mUid);
mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER)
@@ -374,8 +378,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
} else if (hasShortcut) {
// Restrict who can start a shortcut drag since it will start the shortcut as the
// target shortcut package
- mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
- "performDrag");
+ if (!mCanStartTasksFromRecents) {
+ throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
+ }
for (int i = 0; i < data.getItemCount(); i++) {
final ClipData.Item item = data.getItemAt(i);
final Intent intent = item.getIntent();
@@ -403,8 +408,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
} else if (hasTask) {
// TODO(b/169894807): Consider opening this up for tasks from the same app as the caller
- mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
- "performDrag");
+ if (!mCanStartTasksFromRecents) {
+ throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
+ }
for (int i = 0; i < data.getItemCount(); i++) {
final ClipData.Item item = data.getItemAt(i);
final Intent intent = item.getIntent();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 03fca1137e47..dd4ee877c05b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2684,6 +2684,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
@Nullable ArrayList<WindowContainer> sources) {
final Task task = asTask();
if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
+ if (AppTransition.isClosingTransitOld(transit)) {
+ // Freezes the insets state when the window is in app exiting transition, to
+ // ensure the exiting window won't receive unexpected insets changes from the
+ // next window.
+ task.forAllWindows(w -> {
+ w.freezeInsetsState();
+ }, true /* traverseTopToBottom */);
+ }
mDisplayContent.showImeScreenshot();
}
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
@@ -2831,7 +2839,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
mSurfaceAnimationSources.clear();
if (mDisplayContent != null) {
- mDisplayContent.onWindowAnimationFinished(type);
+ mDisplayContent.onWindowAnimationFinished(this, type);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8e6a778c351d..931f52933e2a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3997,8 +3997,10 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
- mAtmInternal.enforceCallerIsRecentsOrHasPermission(
- android.Manifest.permission.SET_ORIENTATION, "setIgnoreOrientationRequest()");
+ if (!checkCallingPermission(
+ android.Manifest.permission.SET_ORIENTATION, "setIgnoreOrientationRequest()")) {
+ throw new SecurityException("Requires SET_ORIENTATION permission");
+ }
final long origId = Binder.clearCallingIdentity();
try {
@@ -6061,8 +6063,10 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setRecentsVisibility(boolean visible) {
- mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR,
- "setRecentsVisibility()");
+ if (!checkCallingPermission(
+ android.Manifest.permission.STATUS_BAR, "setRecentsVisibility()")) {
+ throw new SecurityException("Requires STATUS_BAR permission");
+ }
synchronized (mGlobalLock) {
mPolicy.setRecentsVisibilityLw(visible);
}
@@ -6070,8 +6074,11 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void hideTransientBars(int displayId) {
- mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR,
- "hideTransientBars()");
+ if (!checkCallingPermission(
+ android.Manifest.permission.STATUS_BAR, "hideTransientBars()")) {
+ throw new SecurityException("Requires STATUS_BAR permission");
+ }
+
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
@@ -8373,8 +8380,11 @@ public class WindowManagerService extends IWindowManager.Stub
/** Return whether layer tracing is enabled */
public boolean isLayerTracing() {
- mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
- "isLayerTracing");
+ if (!checkCallingPermission(
+ android.Manifest.permission.DUMP, "isLayerTracing()")) {
+ throw new SecurityException("Requires DUMP permission");
+ }
+
final long token = Binder.clearCallingIdentity();
try {
Parcel data = null;
@@ -8406,8 +8416,11 @@ public class WindowManagerService extends IWindowManager.Stub
/** Enable or disable layer tracing */
public void setLayerTracing(boolean enabled) {
- mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
- "setLayerTracing");
+ if (!checkCallingPermission(
+ android.Manifest.permission.DUMP, "setLayerTracing()")) {
+ throw new SecurityException("Requires DUMP permission");
+ }
+
final long token = Binder.clearCallingIdentity();
try {
Parcel data = null;
@@ -8433,8 +8446,11 @@ public class WindowManagerService extends IWindowManager.Stub
/** Set layer tracing flags. */
public void setLayerTracingFlags(int flags) {
- mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
- "setLayerTracingFlags");
+ if (!checkCallingPermission(
+ android.Manifest.permission.DUMP, "setLayerTracingFlags")) {
+ throw new SecurityException("Requires DUMP permission");
+ }
+
final long token = Binder.clearCallingIdentity();
try {
Parcel data = null;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 043844b2e66b..1b81914bbe7c 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
@@ -264,57 +265,63 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
// Hierarchy changes
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
- for (int i = 0, n = hops.size(); i < n; ++i) {
- final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
- switch (hop.getType()) {
- case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
- final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
- if (task != null) {
- task.getDisplayArea().setLaunchRootTask(task,
- hop.getWindowingModes(), hop.getActivityTypes());
- } else {
- throw new IllegalArgumentException(
- "Cannot set non-task as launch root: " + wc);
- }
- break;
- }
- case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
- effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
- break;
- case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
- effects |= setAdjacentRootsHierarchyOp(hop);
- break;
- case HIERARCHY_OP_TYPE_REORDER:
- case HIERARCHY_OP_TYPE_REPARENT:
- final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- if (wc == null || !wc.isAttached()) {
- Slog.e(TAG, "Attempt to operate on detached container: " + wc);
- continue;
- }
- if (syncId >= 0) {
- addToSyncSet(syncId, wc);
+ if (!hops.isEmpty() && mService.isInLockTaskMode()) {
+ Slog.w(TAG, "Attempt to perform hierarchy operations while in lock task mode...");
+ } else {
+ for (int i = 0, n = hops.size(); i < n; ++i) {
+ final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
+ switch (hop.getType()) {
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
+ final WindowContainer wc = WindowContainer.fromBinder(
+ hop.getContainer());
+ final Task task = wc != null ? wc.asTask() : null;
+ if (task != null) {
+ task.getDisplayArea().setLaunchRootTask(task,
+ hop.getWindowingModes(), hop.getActivityTypes());
+ } else {
+ throw new IllegalArgumentException(
+ "Cannot set non-task as launch root: " + wc);
+ }
+ break;
}
- if (transition != null) {
- transition.collect(wc);
- if (hop.isReparent()) {
- if (wc.getParent() != null) {
- // Collect the current parent. It's visibility may change as
- // a result of this reparenting.
- transition.collect(wc.getParent());
- }
- if (hop.getNewParent() != null) {
- final WindowContainer parentWc =
- WindowContainer.fromBinder(hop.getNewParent());
- if (parentWc == null) {
- Slog.e(TAG, "Can't resolve parent window from token");
- continue;
+ case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
+ effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
+ break;
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
+ effects |= setAdjacentRootsHierarchyOp(hop);
+ break;
+ case HIERARCHY_OP_TYPE_REORDER:
+ case HIERARCHY_OP_TYPE_REPARENT:
+ final WindowContainer wc = WindowContainer.fromBinder(
+ hop.getContainer());
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on detached container: " + wc);
+ continue;
+ }
+ if (syncId >= 0) {
+ addToSyncSet(syncId, wc);
+ }
+ if (transition != null) {
+ transition.collect(wc);
+ if (hop.isReparent()) {
+ if (wc.getParent() != null) {
+ // Collect the current parent. It's visibility may change as
+ // a result of this reparenting.
+ transition.collect(wc.getParent());
+ }
+ if (hop.getNewParent() != null) {
+ final WindowContainer parentWc =
+ WindowContainer.fromBinder(hop.getNewParent());
+ if (parentWc == null) {
+ Slog.e(TAG, "Can't resolve parent window from token");
+ continue;
+ }
+ transition.collect(parentWc);
}
- transition.collect(parentWc);
}
}
- }
- effects |= sanitizeAndApplyHierarchyOp(wc, hop);
+ effects |= sanitizeAndApplyHierarchyOp(wc, hop);
+ }
}
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
@@ -412,6 +419,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (windowingMode > -1) {
+ if (mService.isInLockTaskMode() && windowingMode != WINDOWING_MODE_FULLSCREEN) {
+ throw new UnsupportedOperationException("Not supported to set non-fullscreen"
+ + " windowing mode during locked task mode.");
+ }
container.setWindowingMode(windowingMode);
}
return effects;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9f3188be7623..9a7823e35a01 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -713,6 +713,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private @Nullable InsetsSourceProvider mControllableInsetProvider;
private final InsetsState mRequestedInsetsState = new InsetsState();
+ /**
+ * Freeze the insets state in some cases that not necessarily keeps up-to-date to the client.
+ * (e.g app exiting transition)
+ */
+ private InsetsState mFrozenInsetsState;
+
@Nullable InsetsSourceProvider mPendingPositionChanged;
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
@@ -758,6 +764,33 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
+ /**
+ * Set a freeze state for the window to ignore dispatching its insets state to the client.
+ *
+ * Used to keep the insets state for some use cases. (e.g. app exiting transition)
+ */
+ void freezeInsetsState() {
+ if (mFrozenInsetsState == null) {
+ mFrozenInsetsState = new InsetsState(getInsetsState(), true /* copySources */);
+ }
+ }
+
+ void clearFrozenInsetsState() {
+ mFrozenInsetsState = null;
+ }
+
+ InsetsState getFrozenInsetsState() {
+ return mFrozenInsetsState;
+ }
+
+ /**
+ * Check if the insets state of the window is ready to dispatch to the client when invoking
+ * {@link InsetsStateController#notifyInsetsChanged}.
+ */
+ boolean isReadyToDispatchInsetsState() {
+ return isVisible() && mFrozenInsetsState == null;
+ }
+
void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation,
@Rotation int rotation, boolean requested) {
// Invisible windows and the wallpaper do not participate in the seamless rotation animation
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 345b2464d75a..cc7e00a43a6e 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -25,8 +25,6 @@ cc_library_static {
"gnss/GnssMeasurement.cpp",
"gnss/GnssMeasurementCallback.cpp",
"gnss/Utils.cpp",
- "stats/PowerStatsPuller.cpp",
- "stats/SubsystemSleepStatePuller.cpp",
"com_android_server_adb_AdbDebuggingManager.cpp",
"com_android_server_am_BatteryStatsService.cpp",
"com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
@@ -45,7 +43,6 @@ cc_library_static {
"com_android_server_SerialService.cpp",
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
"com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp",
- "com_android_server_stats_pull_StatsPullAtomService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
"com_android_server_SystemServer.cpp",
"com_android_server_tv_TvUinputBridge.cpp",
@@ -152,6 +149,7 @@ cc_defaults {
"android.hardware.power@1.1",
"android.hardware.power-cpp",
"android.hardware.power.stats@1.0",
+ "android.hardware.power.stats-ndk_platform",
"android.hardware.thermal@1.0",
"android.hardware.tv.input@1.0",
"android.hardware.vibrator-unstable-cpp",
diff --git a/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
index 1208354899d5..3f54529211dd 100644
--- a/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
+++ b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
@@ -335,7 +335,8 @@ static jobjectArray nativeReadEnergyMeters(JNIEnv *env, jclass clazz, jintArray
field_EM_timestampMs,
energyData[i].timestamp);
env->SetLongField(energyMeasurement,
- field_EM_durationMs, -1);
+ field_EM_durationMs,
+ energyData[i].timestamp);
env->SetLongField(energyMeasurement,
field_EM_energyUWs,
energyData[i].energy);
diff --git a/services/core/jni/com_android_server_stats_pull_StatsPullAtomService.cpp b/services/core/jni/com_android_server_stats_pull_StatsPullAtomService.cpp
deleted file mode 100644
index b1fbe6461c44..000000000000
--- a/services/core/jni/com_android_server_stats_pull_StatsPullAtomService.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "StatsPullAtomService"
-
-#include <jni.h>
-#include <log/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <stats_event.h>
-#include <stats_pull_atom_callback.h>
-#include <statslog.h>
-
-#include "stats/PowerStatsPuller.h"
-#include "stats/SubsystemSleepStatePuller.h"
-
-namespace android {
-
-static server::stats::PowerStatsPuller gPowerStatsPuller;
-static server::stats::SubsystemSleepStatePuller gSubsystemSleepStatePuller;
-
-static AStatsManager_PullAtomCallbackReturn onDevicePowerMeasurementCallback(int32_t atom_tag,
- AStatsEventList* data,
- void* cookie) {
- return gPowerStatsPuller.Pull(atom_tag, data);
-}
-
-static AStatsManager_PullAtomCallbackReturn subsystemSleepStateCallback(int32_t atom_tag,
- AStatsEventList* data,
- void* cookie) {
- return gSubsystemSleepStatePuller.Pull(atom_tag, data);
-}
-
-static void nativeInit(JNIEnv* env, jobject javaObject) {
- // on device power measurement
- gPowerStatsPuller = server::stats::PowerStatsPuller();
- AStatsManager_setPullAtomCallback(android::util::ON_DEVICE_POWER_MEASUREMENT,
- /* metadata= */ nullptr, onDevicePowerMeasurementCallback,
- /* cookie= */ nullptr);
-
- // subsystem sleep state
- gSubsystemSleepStatePuller = server::stats::SubsystemSleepStatePuller();
- AStatsManager_setPullAtomCallback(android::util::SUBSYSTEM_SLEEP_STATE,
- /* metadata= */ nullptr, subsystemSleepStateCallback,
- /* cookie= */ nullptr);
-}
-
-static const JNINativeMethod sMethods[] = {{"nativeInit", "()V", (void*)nativeInit}};
-
-int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env) {
- int res = jniRegisterNativeMethods(env, "com/android/server/stats/pull/StatsPullAtomService",
- sMethods, NELEM(sMethods));
- if (res < 0) {
- ALOGE("failed to register native methods");
- }
- return res;
-}
-
-} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 189332107a5d..c5394f3aba69 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -59,7 +59,6 @@ int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl
int register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(
JNIEnv* env);
int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env);
-int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
int register_android_server_AdbDebuggingManager(JNIEnv* env);
int register_android_server_FaceService(JNIEnv* env);
int register_android_server_GpuService(JNIEnv* env);
@@ -115,7 +114,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(
env);
register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env);
- register_android_server_stats_pull_StatsPullAtomService(env);
register_android_server_AdbDebuggingManager(env);
register_android_server_FaceService(env);
register_android_server_GpuService(env);
diff --git a/services/core/jni/stats/OWNERS b/services/core/jni/stats/OWNERS
deleted file mode 100644
index a61babf32e58..000000000000
--- a/services/core/jni/stats/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-jeffreyhuang@google.com
-joeo@google.com
-jtnguyen@google.com
-muhammadq@google.com
-ruchirr@google.com
-singhtejinder@google.com
-tsaichristine@google.com
-yaochen@google.com
-yro@google.com
diff --git a/services/core/jni/stats/PowerStatsPuller.cpp b/services/core/jni/stats/PowerStatsPuller.cpp
deleted file mode 100644
index 7f788c226c7b..000000000000
--- a/services/core/jni/stats/PowerStatsPuller.cpp
+++ /dev/null
@@ -1,160 +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.
- */
-
-#define DEBUG false // STOPSHIP if true
-#define LOG_TAG "PowerStatsPuller"
-
-#include <android/hardware/power/stats/1.0/IPowerStats.h>
-#include <log/log.h>
-#include <statslog.h>
-
-#include <vector>
-
-#include "PowerStatsPuller.h"
-
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::power::stats::V1_0::EnergyData;
-using android::hardware::power::stats::V1_0::IPowerStats;
-using android::hardware::power::stats::V1_0::RailInfo;
-using android::hardware::power::stats::V1_0::Status;
-
-namespace android {
-namespace server {
-namespace stats {
-
-static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
-static std::mutex gPowerStatsHalMutex;
-static bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
-static std::vector<RailInfo> gRailInfo;
-
-struct PowerStatsPullerDeathRecipient : virtual public hardware::hidl_death_recipient {
- virtual void serviceDied(uint64_t cookie,
- const wp<android::hidl::base::V1_0::IBase>& who) override {
- // The HAL just died. Reset all handles to HAL services.
- std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
- gPowerStatsHal = nullptr;
- }
-};
-
-static sp<PowerStatsPullerDeathRecipient> gDeathRecipient = new PowerStatsPullerDeathRecipient();
-
-static bool getPowerStatsHalLocked() {
- if (gPowerStatsHal == nullptr && gPowerStatsExist) {
- gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
- if (gPowerStatsHal == nullptr) {
- ALOGW("Couldn't load power.stats HAL service");
- gPowerStatsExist = false;
- } else {
- // Link death recipient to power.stats service handle
- hardware::Return<bool> linked = gPowerStatsHal->linkToDeath(gDeathRecipient, 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to power.stats HAL death: %s",
- linked.description().c_str());
- gPowerStatsHal = nullptr;
- return false;
- } else if (!linked) {
- ALOGW("Unable to link to power.stats HAL death notifications");
- // We should still continue even though linking failed
- }
- }
- }
- return gPowerStatsHal != nullptr;
-}
-
-PowerStatsPuller::PowerStatsPuller() {}
-
-AStatsManager_PullAtomCallbackReturn PowerStatsPuller::Pull(int32_t atomTag,
- AStatsEventList* data) {
- std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
-
- if (!getPowerStatsHalLocked()) {
- return AStatsManager_PULL_SKIP;
- }
-
- // Pull getRailInfo if necessary
- if (gRailInfo.empty()) {
- bool resultSuccess = true;
- Return<void> ret = gPowerStatsHal->getRailInfo(
- [&resultSuccess](const hidl_vec<RailInfo>& list, Status status) {
- resultSuccess = (status == Status::SUCCESS || status == Status::NOT_SUPPORTED);
- if (status != Status::SUCCESS) return;
- gRailInfo.reserve(list.size());
- for (size_t i = 0; i < list.size(); ++i) {
- gRailInfo.push_back(list[i]);
- }
- });
- if (!resultSuccess || !ret.isOk()) {
- ALOGE("power.stats getRailInfo() failed. Description: %s", ret.description().c_str());
- gPowerStatsHal = nullptr;
- return AStatsManager_PULL_SKIP;
- }
- // If SUCCESS but empty, or if NOT_SUPPORTED, then never try again.
- if (gRailInfo.empty()) {
- ALOGE("power.stats has no rail information");
- gPowerStatsExist = false; // No rail info, so never try again.
- gPowerStatsHal = nullptr;
- return AStatsManager_PULL_SKIP;
- }
- }
-
- // Pull getEnergyData and write the data out
- const hidl_vec<uint32_t> desiredRailIndices; // Empty vector indicates we want all.
- bool resultSuccess = true;
- Return<void> ret =
- gPowerStatsHal
- ->getEnergyData(desiredRailIndices,
- [&data, &resultSuccess](hidl_vec<EnergyData> energyDataList,
- Status status) {
- resultSuccess = (status == Status::SUCCESS);
- if (!resultSuccess) return;
-
- for (size_t i = 0; i < energyDataList.size(); i++) {
- const EnergyData& energyData = energyDataList[i];
-
- if (energyData.index >= gRailInfo.size()) {
- ALOGE("power.stats getEnergyData() returned an "
- "invalid rail index %u.",
- energyData.index);
- resultSuccess = false;
- return;
- }
- const RailInfo& rail = gRailInfo[energyData.index];
-
- android::util::addAStatsEvent(
- data,
- android::util::ON_DEVICE_POWER_MEASUREMENT,
- rail.subsysName.c_str(), rail.railName.c_str(),
- energyData.timestamp, energyData.energy);
-
- ALOGV("power.stat: %s.%s: %llu, %llu",
- rail.subsysName.c_str(), rail.railName.c_str(),
- (unsigned long long)energyData.timestamp,
- (unsigned long long)energyData.energy);
- }
- });
- if (!resultSuccess || !ret.isOk()) {
- ALOGE("power.stats getEnergyData() failed. Description: %s", ret.description().c_str());
- gPowerStatsHal = nullptr;
- return AStatsManager_PULL_SKIP;
- }
- return AStatsManager_PULL_SUCCESS;
-}
-
-} // namespace stats
-} // namespace server
-} // namespace android
diff --git a/services/core/jni/stats/SubsystemSleepStatePuller.cpp b/services/core/jni/stats/SubsystemSleepStatePuller.cpp
deleted file mode 100644
index 1ba98ef8dab7..000000000000
--- a/services/core/jni/stats/SubsystemSleepStatePuller.cpp
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2017 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 DEBUG false // STOPSHIP if true
-#define LOG_TAG "SubsystemSleepStatePuller"
-
-#include <log/log.h>
-#include <statslog.h>
-
-#include <android/hardware/power/1.0/IPower.h>
-#include <android/hardware/power/1.1/IPower.h>
-#include <android/hardware/power/stats/1.0/IPowerStats.h>
-
-#include <fcntl.h>
-#include <hardware/power.h>
-#include <hardware_legacy/power.h>
-#include <inttypes.h>
-#include <semaphore.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <unordered_map>
-#include "SubsystemSleepStatePuller.h"
-
-using android::hardware::hidl_vec;
-using android::hardware::power::V1_0::IPower;
-using android::hardware::power::V1_0::PowerStatePlatformSleepState;
-using android::hardware::power::V1_0::PowerStateVoter;
-using android::hardware::power::V1_1::PowerStateSubsystem;
-using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
-using android::hardware::power::stats::V1_0::PowerEntityInfo;
-using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
-using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
-
-using android::hardware::Return;
-using android::hardware::Void;
-
-namespace android {
-namespace server {
-namespace stats {
-
-static std::function<AStatsManager_PullAtomCallbackReturn(int32_t atomTag, AStatsEventList* data)>
- gPuller = {};
-
-static sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
-static sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
-static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
-
-static std::unordered_map<uint32_t, std::string> gEntityNames = {};
-static std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};
-
-static std::mutex gPowerHalMutex;
-
-// The caller must be holding gPowerHalMutex.
-static void deinitPowerStatsLocked() {
- gPowerHalV1_0 = nullptr;
- gPowerHalV1_1 = nullptr;
- gPowerStatsHalV1_0 = nullptr;
-}
-
-struct SubsystemSleepStatePullerDeathRecipient : virtual public hardware::hidl_death_recipient {
- virtual void serviceDied(uint64_t cookie,
- const wp<android::hidl::base::V1_0::IBase>& who) override {
-
- // The HAL just died. Reset all handles to HAL services.
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- deinitPowerStatsLocked();
- }
-};
-
-static sp<SubsystemSleepStatePullerDeathRecipient> gDeathRecipient =
- new SubsystemSleepStatePullerDeathRecipient();
-
-SubsystemSleepStatePuller::SubsystemSleepStatePuller() {}
-
-// The caller must be holding gPowerHalMutex.
-static bool checkResultLocked(const Return<void> &ret, const char* function) {
- if (!ret.isOk()) {
- ALOGE("%s failed: requested HAL service not available. Description: %s",
- function, ret.description().c_str());
- if (ret.isDeadObject()) {
- deinitPowerStatsLocked();
- }
- return false;
- }
- return true;
-}
-
-// The caller must be holding gPowerHalMutex.
-// gPowerStatsHalV1_0 must not be null
-static bool initializePowerStats() {
- using android::hardware::power::stats::V1_0::Status;
-
- // Clear out previous content if we are re-initializing
- gEntityNames.clear();
- gStateNames.clear();
-
- Return<void> ret;
- ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
- if (status != Status::SUCCESS) {
- ALOGE("Error getting power entity info");
- return;
- }
-
- // construct lookup table of powerEntityId to power entity name
- for (auto info : infos) {
- gEntityNames.emplace(info.powerEntityId, info.powerEntityName);
- }
- });
- if (!checkResultLocked(ret, __func__)) {
- return false;
- }
-
- ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
- if (status != Status::SUCCESS) {
- ALOGE("Error getting state info");
- return;
- }
-
- // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
- for (auto stateSpace : stateSpaces) {
- std::unordered_map<uint32_t, std::string> stateNames = {};
- for (auto state : stateSpace.states) {
- stateNames.emplace(state.powerEntityStateId,
- state.powerEntityStateName);
- }
- gStateNames.emplace(stateSpace.powerEntityId, stateNames);
- }
- });
- if (!checkResultLocked(ret, __func__)) {
- return false;
- }
-
- return (!gEntityNames.empty()) && (!gStateNames.empty());
-}
-
-// The caller must be holding gPowerHalMutex.
-static bool getPowerStatsHalLocked() {
- if(gPowerStatsHalV1_0 == nullptr) {
- gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
- if (gPowerStatsHalV1_0 == nullptr) {
- ALOGE("Unable to get power.stats HAL service.");
- return false;
- }
-
- // Link death recipient to power.stats service handle
- hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to power.stats HAL death: %s",
- linked.description().c_str());
- deinitPowerStatsLocked();
- return false;
- } else if (!linked) {
- ALOGW("Unable to link to power.stats HAL death notifications");
- // We should still continue even though linking failed
- }
- return initializePowerStats();
- }
- return true;
-}
-
-// The caller must be holding gPowerHalMutex.
-static AStatsManager_PullAtomCallbackReturn getIPowerStatsDataLocked(int32_t atomTag,
- AStatsEventList* data) {
- using android::hardware::power::stats::V1_0::Status;
-
- if(!getPowerStatsHalLocked()) {
- return AStatsManager_PULL_SKIP;
- }
- // Get power entity state residency data
- bool success = false;
- Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
- {}, [&data, &success](auto results, auto status) {
- if (status == Status::NOT_SUPPORTED) {
- ALOGW("getPowerEntityStateResidencyData is not supported");
- success = false;
- return;
- }
- for (auto result : results) {
- for (auto stateResidency : result.stateResidencyData) {
- android::util::addAStatsEvent(data, android::util::SUBSYSTEM_SLEEP_STATE,
- gEntityNames.at(result.powerEntityId).c_str(),
- gStateNames.at(result.powerEntityId)
- .at(stateResidency.powerEntityStateId)
- .c_str(),
- stateResidency.totalStateEntryCount,
- stateResidency.totalTimeInStateMs);
- }
- }
- success = true;
- });
- // Intentionally not returning early here.
- // bool success determines if this succeeded or not.
- checkResultLocked(ret, __func__);
- if (!success) {
- return AStatsManager_PULL_SKIP;
- }
- return AStatsManager_PULL_SUCCESS;
-}
-
-// The caller must be holding gPowerHalMutex.
-static bool getPowerHalLocked() {
- if(gPowerHalV1_0 == nullptr) {
- gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
- if(gPowerHalV1_0 == nullptr) {
- ALOGE("Unable to get power HAL service.");
- return false;
- }
- gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
-
- // Link death recipient to power service handle
- hardware::Return<bool> linked = gPowerHalV1_0->linkToDeath(gDeathRecipient, 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to power HAL death: %s",
- linked.description().c_str());
- gPowerHalV1_0 = nullptr;
- return false;
- } else if (!linked) {
- ALOGW("Unable to link to power. death notifications");
- // We should still continue even though linking failed
- }
- }
- return true;
-}
-
-// The caller must be holding gPowerHalMutex.
-static AStatsManager_PullAtomCallbackReturn getIPowerDataLocked(int32_t atomTag,
- AStatsEventList* data) {
- using android::hardware::power::V1_0::Status;
-
- if(!getPowerHalLocked()) {
- return AStatsManager_PULL_SKIP;
- }
-
- Return<void> ret;
- ret = gPowerHalV1_0->getPlatformLowPowerStats(
- [&data](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
- if (status != Status::SUCCESS) return;
-
- for (size_t i = 0; i < states.size(); i++) {
- const PowerStatePlatformSleepState& state = states[i];
- android::util::addAStatsEvent(data, android::util::SUBSYSTEM_SLEEP_STATE,
- state.name.c_str(), "",
- state.totalTransitions,
- state.residencyInMsecSinceBoot);
-
- ALOGV("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
- (long long)state.residencyInMsecSinceBoot,
- (long long)state.totalTransitions,
- state.supportedOnlyInSuspend ? 1 : 0);
- for (const auto& voter : state.voters) {
- android::util::addAStatsEvent(data,
- android::util::SUBSYSTEM_SLEEP_STATE,
- state.name.c_str(), voter.name.c_str(),
- voter.totalNumberOfTimesVotedSinceBoot,
- voter.totalTimeInMsecVotedForSinceBoot);
-
- ALOGV("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
- voter.name.c_str(),
- (long long)voter.totalTimeInMsecVotedForSinceBoot,
- (long long)voter.totalNumberOfTimesVotedSinceBoot);
- }
- }
- });
- if (!checkResultLocked(ret, __func__)) {
- return AStatsManager_PULL_SKIP;
- }
-
- // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
- sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
- android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
- if (gPowerHal_1_1 != nullptr) {
- ret = gPowerHal_1_1->getSubsystemLowPowerStats(
- [&data](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
- if (status != Status::SUCCESS) return;
-
- if (subsystems.size() > 0) {
- for (size_t i = 0; i < subsystems.size(); i++) {
- const PowerStateSubsystem& subsystem = subsystems[i];
- for (size_t j = 0; j < subsystem.states.size(); j++) {
- const PowerStateSubsystemSleepState& state =
- subsystem.states[j];
- android::util::
- addAStatsEvent(data,
- android::util::SUBSYSTEM_SLEEP_STATE,
- subsystem.name.c_str(),
- state.name.c_str(),
- state.totalTransitions,
- state.residencyInMsecSinceBoot);
-
- ALOGV("subsystemstate: %s, %s, %lld, %lld, %lld",
- subsystem.name.c_str(), state.name.c_str(),
- (long long)state.residencyInMsecSinceBoot,
- (long long)state.totalTransitions,
- (long long)state.lastEntryTimestampMs);
- }
- }
- }
- });
- }
- return AStatsManager_PULL_SUCCESS;
-}
-
-// The caller must be holding gPowerHalMutex.
-std::function<AStatsManager_PullAtomCallbackReturn(int32_t atomTag, AStatsEventList* data)>
-getPullerLocked() {
- std::function<AStatsManager_PullAtomCallbackReturn(int32_t atomTag, AStatsEventList * data)>
- ret = {};
-
- // First see if power.stats HAL is available. Fall back to power HAL if
- // power.stats HAL is unavailable.
- if(android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
- ALOGI("Using power.stats HAL");
- ret = getIPowerStatsDataLocked;
- } else if(android::hardware::power::V1_0::IPower::getService() != nullptr) {
- ALOGI("Using power HAL");
- ret = getIPowerDataLocked;
- }
-
- return ret;
-}
-
-AStatsManager_PullAtomCallbackReturn SubsystemSleepStatePuller::Pull(int32_t atomTag,
- AStatsEventList* data) {
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
-
- if(!gPuller) {
- gPuller = getPullerLocked();
- }
-
- if(gPuller) {
- return gPuller(atomTag, data);
- }
-
- ALOGE("Unable to load Power Hal or power.stats HAL");
- return AStatsManager_PULL_SKIP;
-}
-
-} // namespace stats
-} // namespace server
-} // namespace android
diff --git a/services/core/jni/stats/SubsystemSleepStatePuller.h b/services/core/jni/stats/SubsystemSleepStatePuller.h
deleted file mode 100644
index da9679c68a64..000000000000
--- a/services/core/jni/stats/SubsystemSleepStatePuller.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stats_event.h>
-#include <stats_pull_atom_callback.h>
-
-namespace android {
-namespace server {
-namespace stats {
-
-/**
- * Reads hal for sleep states
- */
-class SubsystemSleepStatePuller {
-public:
- SubsystemSleepStatePuller();
- AStatsManager_PullAtomCallbackReturn Pull(int32_t atomTag, AStatsEventList* data);
-};
-
-} // namespace stats
-} // namespace server
-} // namespace android
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index d2244286450b..b2efc71860fb 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -118,18 +118,10 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path,
binder::Status BinderIncrementalService::createStorage(
const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params,
- int32_t createMode,
- const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener,
- const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
- const ::android::sp<::android::os::incremental::IStorageHealthListener>& healthListener,
- const ::std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts,
- int32_t* _aidl_return) {
- *_aidl_return =
- mImpl.createStorage(path, const_cast<content::pm::DataLoaderParamsParcel&&>(params),
- android::incremental::IncrementalService::CreateOptions(createMode),
- statusListener,
- const_cast<StorageHealthCheckParams&&>(healthCheckParams),
- healthListener, perUidReadTimeouts);
+ int32_t createMode, int32_t* _aidl_return) {
+ *_aidl_return = mImpl.createStorage(path, params,
+ android::incremental::IncrementalService::CreateOptions(
+ createMode));
return ok();
}
@@ -144,6 +136,21 @@ binder::Status BinderIncrementalService::createLinkedStorage(const std::string&
return ok();
}
+binder::Status BinderIncrementalService::startLoading(
+ int32_t storageId, const ::android::content::pm::DataLoaderParamsParcel& params,
+ const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener,
+ const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
+ const ::android::sp<IStorageHealthListener>& healthListener,
+ const ::std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts,
+ bool* _aidl_return) {
+ *_aidl_return =
+ mImpl.startLoading(storageId, const_cast<content::pm::DataLoaderParamsParcel&&>(params),
+ statusListener,
+ const_cast<StorageHealthCheckParams&&>(healthCheckParams),
+ healthListener, perUidReadTimeouts);
+ return ok();
+}
+
binder::Status BinderIncrementalService::makeBindMount(int32_t storageId,
const std::string& sourcePath,
const std::string& targetFullPath,
@@ -253,9 +260,16 @@ binder::Status BinderIncrementalService::isFileFullyLoaded(int32_t storageId,
return ok();
}
+binder::Status BinderIncrementalService::isFullyLoaded(int32_t storageId, int32_t* _aidl_return) {
+ *_aidl_return = mImpl.getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/true)
+ .blocksRemainingOrError();
+ return ok();
+}
+
binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
float* _aidl_return) {
- *_aidl_return = mImpl.getLoadingProgress(storageId).getProgress();
+ *_aidl_return =
+ mImpl.getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false).getProgress();
return ok();
}
@@ -291,11 +305,6 @@ binder::Status BinderIncrementalService::makeDirectories(int32_t storageId, cons
return ok();
}
-binder::Status BinderIncrementalService::startLoading(int32_t storageId, bool* _aidl_return) {
- *_aidl_return = mImpl.startLoading(storageId);
- return ok();
-}
-
binder::Status BinderIncrementalService::configureNativeBinaries(
int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath,
const std::string& abi, bool extractNativeLibs, bool* _aidl_return) {
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 9a4537a15f31..740c542f9759 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -39,16 +39,18 @@ public:
void onInvalidStorage(int mountId);
binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final;
- binder::Status createStorage(
- const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params,
- int32_t createMode,
+ binder::Status createStorage(const ::std::string& path,
+ const ::android::content::pm::DataLoaderParamsParcel& params,
+ int32_t createMode, int32_t* _aidl_return) final;
+ binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId,
+ int32_t createMode, int32_t* _aidl_return) final;
+ binder::Status startLoading(
+ int32_t storageId, const ::android::content::pm::DataLoaderParamsParcel& params,
const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener,
const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
const ::android::sp<IStorageHealthListener>& healthListener,
const ::std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts,
- int32_t* _aidl_return) final;
- binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId,
- int32_t createMode, int32_t* _aidl_return) final;
+ bool* _aidl_return) final;
binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath,
const std::string& targetFullPath, int32_t bindType,
int32_t* _aidl_return) final;
@@ -71,12 +73,12 @@ public:
binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
binder::Status isFileFullyLoaded(int32_t storageId, const std::string& path,
int32_t* _aidl_return) final;
+ binder::Status isFullyLoaded(int32_t storageId, int32_t* _aidl_return) final;
binder::Status getLoadingProgress(int32_t storageId, float* _aidl_return) final;
binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
std::vector<uint8_t>* _aidl_return) final;
binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
std::vector<uint8_t>* _aidl_return) final;
- binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
binder::Status deleteStorage(int32_t storageId) final;
binder::Status disallowReadLogs(int32_t storageId) final;
binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index c9c5489a50df..132f973ee83b 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -356,7 +356,9 @@ void IncrementalService::onDump(int fd) {
dprintf(fd, " storages (%d): {\n", int(mnt.storages.size()));
for (auto&& [storageId, storage] : mnt.storages) {
dprintf(fd, " [%d] -> [%s] (%d %% loaded) \n", storageId, storage.name.c_str(),
- (int)(getLoadingProgressFromPath(mnt, storage.name.c_str()).getProgress() *
+ (int)(getLoadingProgressFromPath(mnt, storage.name.c_str(),
+ /*stopOnFirstIncomplete=*/false)
+ .getProgress() *
100));
}
dprintf(fd, " }\n");
@@ -427,10 +429,8 @@ auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator {
}
StorageId IncrementalService::createStorage(
- std::string_view mountPoint, content::pm::DataLoaderParamsParcel&& dataLoaderParams,
- CreateOptions options, const DataLoaderStatusListener& statusListener,
- StorageHealthCheckParams&& healthCheckParams, const StorageHealthListener& healthListener,
- const std::vector<PerUidReadTimeouts>& perUidReadTimeouts) {
+ std::string_view mountPoint, const content::pm::DataLoaderParamsParcel& dataLoaderParams,
+ CreateOptions options) {
LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
if (!path::isAbsolute(mountPoint)) {
LOG(ERROR) << "path is not absolute: " << mountPoint;
@@ -538,13 +538,10 @@ StorageId IncrementalService::createStorage(
metadata::Mount m;
m.mutable_storage()->set_id(ifs->mountId);
m.mutable_loader()->set_type((int)dataLoaderParams.type);
- m.mutable_loader()->set_allocated_package_name(&dataLoaderParams.packageName);
- m.mutable_loader()->set_allocated_class_name(&dataLoaderParams.className);
- m.mutable_loader()->set_allocated_arguments(&dataLoaderParams.arguments);
+ m.mutable_loader()->set_package_name(dataLoaderParams.packageName);
+ m.mutable_loader()->set_class_name(dataLoaderParams.className);
+ m.mutable_loader()->set_arguments(dataLoaderParams.arguments);
const auto metadata = m.SerializeAsString();
- m.mutable_loader()->release_arguments();
- m.mutable_loader()->release_class_name();
- m.mutable_loader()->release_package_name();
if (auto err =
mIncFs->makeFile(ifs->control,
path::join(ifs->root, constants().mount,
@@ -568,26 +565,9 @@ StorageId IncrementalService::createStorage(
// Done here as well, all data structures are in good state.
secondCleanupOnFailure.release();
- // DataLoader.
- auto dataLoaderStub = prepareDataLoader(*ifs, std::move(dataLoaderParams), &statusListener,
- std::move(healthCheckParams), &healthListener);
- CHECK(dataLoaderStub);
-
mountIt->second = std::move(ifs);
l.unlock();
- // Per Uid timeouts.
- if (!perUidReadTimeouts.empty()) {
- setUidReadTimeouts(mountId, perUidReadTimeouts);
- }
-
- if (mSystemReady.load(std::memory_order_relaxed) && !dataLoaderStub->requestCreate()) {
- // failed to create data loader
- LOG(ERROR) << "initializeDataLoader() failed";
- deleteStorage(dataLoaderStub->id());
- return kInvalidStorageId;
- }
-
LOG(INFO) << "created storage " << mountId;
return mountId;
}
@@ -634,6 +614,37 @@ StorageId IncrementalService::createLinkedStorage(std::string_view mountPoint,
return storageId;
}
+bool IncrementalService::startLoading(StorageId storage,
+ content::pm::DataLoaderParamsParcel&& dataLoaderParams,
+ const DataLoaderStatusListener& statusListener,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener& healthListener,
+ const std::vector<PerUidReadTimeouts>& perUidReadTimeouts) {
+ // Per Uid timeouts.
+ if (!perUidReadTimeouts.empty()) {
+ setUidReadTimeouts(storage, perUidReadTimeouts);
+ }
+
+ // Re-initialize DataLoader.
+ std::unique_lock l(mLock);
+ const auto ifs = getIfsLocked(storage);
+ if (!ifs) {
+ return false;
+ }
+ if (ifs->dataLoaderStub) {
+ ifs->dataLoaderStub->cleanupResources();
+ ifs->dataLoaderStub = {};
+ }
+ l.unlock();
+
+ // DataLoader.
+ auto dataLoaderStub = prepareDataLoader(*ifs, std::move(dataLoaderParams), &statusListener,
+ std::move(healthCheckParams), &healthListener);
+ CHECK(dataLoaderStub);
+
+ return dataLoaderStub->requestStart();
+}
+
IncrementalService::BindPathMap::const_iterator IncrementalService::findStorageLocked(
std::string_view path) const {
return findParentPath(mBindsByPath, path);
@@ -960,7 +971,12 @@ int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath
LOG(ERROR) << "Invalid paths in link(): " << normOldPath << " | " << normNewPath;
return -EINVAL;
}
- return mIncFs->link(ifsSrc->control, normOldPath, normNewPath);
+ if (auto err = mIncFs->link(ifsSrc->control, normOldPath, normNewPath); err < 0) {
+ PLOG(ERROR) << "Failed to link " << oldPath << "[" << normOldPath << "]"
+ << " to " << newPath << "[" << normNewPath << "]";
+ return err;
+ }
+ return 0;
}
int IncrementalService::unlink(StorageId storage, std::string_view path) {
@@ -1065,23 +1081,6 @@ RawMetadata IncrementalService::getMetadata(StorageId storage, FileId node) cons
return mIncFs->getMetadata(ifs->control, node);
}
-bool IncrementalService::startLoading(StorageId storage) const {
- DataLoaderStubPtr dataLoaderStub;
- {
- std::unique_lock l(mLock);
- const auto& ifs = getIfsLocked(storage);
- if (!ifs) {
- return false;
- }
- dataLoaderStub = ifs->dataLoaderStub;
- if (!dataLoaderStub) {
- return false;
- }
- }
- dataLoaderStub->requestStart();
- return true;
-}
-
void IncrementalService::setUidReadTimeouts(
StorageId storage, const std::vector<PerUidReadTimeouts>& perUidReadTimeouts) {
using microseconds = std::chrono::microseconds;
@@ -1092,11 +1091,15 @@ void IncrementalService::setUidReadTimeouts(
maxPendingTimeUs = std::max(maxPendingTimeUs, microseconds(timeouts.maxPendingTimeUs));
}
if (maxPendingTimeUs < Constants::minPerUidTimeout) {
+ LOG(ERROR) << "Skip setting timeouts: maxPendingTime < Constants::minPerUidTimeout"
+ << duration_cast<milliseconds>(maxPendingTimeUs).count() << "ms < "
+ << Constants::minPerUidTimeout.count() << "ms";
return;
}
const auto ifs = getIfs(storage);
if (!ifs) {
+ LOG(ERROR) << "Setting read timeouts failed: invalid storage id: " << storage;
return;
}
@@ -1126,7 +1129,7 @@ void IncrementalService::updateUidReadTimeouts(StorageId storage, Clock::time_po
}
// Still loading?
- const auto progress = getLoadingProgress(storage);
+ const auto progress = getLoadingProgress(storage, /*stopOnFirstIncomplete=*/true);
if (progress.isError()) {
// Something is wrong, abort.
return clearUidReadTimeouts(storage);
@@ -1840,7 +1843,7 @@ int IncrementalService::isFileFullyLoadedFromPath(const IncFsMount& ifs,
}
IncrementalService::LoadingProgress IncrementalService::getLoadingProgress(
- StorageId storage) const {
+ StorageId storage, bool stopOnFirstIncomplete) const {
std::unique_lock l(mLock);
const auto ifs = getIfsLocked(storage);
if (!ifs) {
@@ -1853,11 +1856,11 @@ IncrementalService::LoadingProgress IncrementalService::getLoadingProgress(
return {-EINVAL, -EINVAL};
}
l.unlock();
- return getLoadingProgressFromPath(*ifs, storageInfo->second.name);
+ return getLoadingProgressFromPath(*ifs, storageInfo->second.name, stopOnFirstIncomplete);
}
IncrementalService::LoadingProgress IncrementalService::getLoadingProgressFromPath(
- const IncFsMount& ifs, std::string_view storagePath) const {
+ const IncFsMount& ifs, std::string_view storagePath, bool stopOnFirstIncomplete) const {
ssize_t totalBlocks = 0, filledBlocks = 0;
const auto filePaths = mFs->listFilesRecursive(storagePath);
for (const auto& filePath : filePaths) {
@@ -1870,6 +1873,9 @@ IncrementalService::LoadingProgress IncrementalService::getLoadingProgressFromPa
}
totalBlocks += totalBlocksCount;
filledBlocks += filledBlocksCount;
+ if (stopOnFirstIncomplete && filledBlocks < totalBlocks) {
+ break;
+ }
}
return {filledBlocks, totalBlocks};
@@ -1877,7 +1883,7 @@ IncrementalService::LoadingProgress IncrementalService::getLoadingProgressFromPa
bool IncrementalService::updateLoadingProgress(
StorageId storage, const StorageLoadingProgressListener& progressListener) {
- const auto progress = getLoadingProgress(storage);
+ const auto progress = getLoadingProgress(storage, /*stopOnFirstIncomplete=*/false);
if (progress.isError()) {
// Failed to get progress from incfs, abort.
return false;
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 306612159412..5d53bac777b5 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -113,6 +113,10 @@ public:
bool started() const { return totalBlocks > 0; }
bool fullyLoaded() const { return !isError() && (totalBlocks == filledBlocks); }
+ int blocksRemainingOrError() const {
+ return totalBlocks <= 0 ? totalBlocks : totalBlocks - filledBlocks;
+ }
+
float getProgress() const {
return totalBlocks < 0
? totalBlocks
@@ -130,15 +134,18 @@ public:
void onSystemReady();
StorageId createStorage(std::string_view mountPoint,
- content::pm::DataLoaderParamsParcel&& dataLoaderParams,
- CreateOptions options, const DataLoaderStatusListener& statusListener,
- StorageHealthCheckParams&& healthCheckParams,
- const StorageHealthListener& healthListener,
- const std::vector<PerUidReadTimeouts>& perUidReadTimeouts);
+ const content::pm::DataLoaderParamsParcel& dataLoaderParams,
+ CreateOptions options);
StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
CreateOptions options = CreateOptions::Default);
StorageId openStorage(std::string_view path);
+ bool startLoading(StorageId storage, content::pm::DataLoaderParamsParcel&& dataLoaderParams,
+ const DataLoaderStatusListener& statusListener,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener& healthListener,
+ const std::vector<PerUidReadTimeouts>& perUidReadTimeouts);
+
int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind);
int unbind(StorageId storage, std::string_view target);
void deleteStorage(StorageId storage);
@@ -156,7 +163,9 @@ public:
int unlink(StorageId storage, std::string_view path);
int isFileFullyLoaded(StorageId storage, std::string_view filePath) const;
- LoadingProgress getLoadingProgress(StorageId storage) const;
+
+ LoadingProgress getLoadingProgress(StorageId storage, bool stopOnFirstIncomplete) const;
+
bool registerLoadingProgressListener(StorageId storage,
const StorageLoadingProgressListener& progressListener);
bool unregisterLoadingProgressListener(StorageId storage);
@@ -167,8 +176,6 @@ public:
RawMetadata getMetadata(StorageId storage, std::string_view path) const;
RawMetadata getMetadata(StorageId storage, FileId node) const;
- bool startLoading(StorageId storage) const;
-
bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
std::string_view libDirRelativePath, std::string_view abi,
bool extractNativeLibs);
@@ -388,7 +395,8 @@ private:
binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
int isFileFullyLoadedFromPath(const IncFsMount& ifs, std::string_view filePath) const;
- LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
+ LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path,
+ bool stopOnFirstIncomplete) const;
int setFileContent(const IfsMountPtr& ifs, const incfs::FileId& fileId,
std::string_view debugFilePath, std::span<const uint8_t> data) const;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 6fabc589cf95..3573177af185 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -210,7 +210,22 @@ public:
ErrorCode setUidReadTimeouts(const Control& control,
const std::vector<android::os::incremental::PerUidReadTimeouts>&
perUidReadTimeouts) const final {
- return -ENOTSUP;
+ std::vector<incfs::UidReadTimeouts> timeouts;
+ timeouts.resize(perUidReadTimeouts.size());
+ for (int i = 0, size = perUidReadTimeouts.size(); i < size; ++i) {
+ auto&& timeout = timeouts[i];
+ const auto& perUidTimeout = perUidReadTimeouts[i];
+ timeout.uid = perUidTimeout.uid;
+ timeout.minTimeUs = perUidTimeout.minTimeUs;
+ timeout.minPendingTimeUs = perUidTimeout.minPendingTimeUs;
+ timeout.maxPendingTimeUs = perUidTimeout.maxPendingTimeUs;
+ }
+
+ LOG(ERROR) << "Set read timeouts: " << timeouts.size() << " ["
+ << (timeouts.empty() ? -1 : timeouts.front().uid) << "@"
+ << (timeouts.empty() ? -1 : timeouts.front().minTimeUs / 1000) << "ms]";
+
+ return incfs::setUidReadTimeouts(control, timeouts);
}
};
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index f0deba7db01c..8713f9d3d821 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -678,9 +678,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) {
mVold->mountIncFsFails();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(0);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -689,9 +689,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel)
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(0);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -702,9 +702,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) {
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -716,9 +716,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) {
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -734,24 +734,24 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
- ASSERT_LT(storageId, 0);
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {}, {});
}
TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
- EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
- EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
- EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(1);
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {}, {});
mIncrementalService->deleteStorage(storageId);
}
@@ -759,14 +759,15 @@ TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
- EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(2);
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {}, {});
// Simulated crash/other connection breakage.
mDataLoaderManager->setDataLoaderStatusDestroyed();
}
@@ -780,12 +781,13 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
mDataLoaderManager->setDataLoaderStatusCreated();
- ASSERT_TRUE(mIncrementalService->startLoading(storageId));
mDataLoaderManager->setDataLoaderStatusStarted();
}
@@ -793,16 +795,17 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
mDataLoader->initializeCreateOkNoStatus();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
- EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoader, start(_)).Times(1);
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
- ASSERT_TRUE(mIncrementalService->startLoading(storageId));
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
mDataLoaderManager->setDataLoaderStatusCreated();
}
@@ -815,10 +818,12 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
mDataLoaderManager->setDataLoaderStatusUnavailable();
}
@@ -836,10 +841,12 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1);
EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
mDataLoaderManager->setDataLoaderStatusUnavailable();
ASSERT_NE(nullptr, mLooper->mCallback);
ASSERT_NE(nullptr, mLooper->mCallbackData);
@@ -890,10 +897,12 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
kFirstTimestampUs - std::chrono::duration_cast<MCS>(unhealthyTimeout).count();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, std::move(params), listener, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {},
+ std::move(params), listener, {});
// Healthy state, registered for pending reads.
ASSERT_NE(nullptr, mLooper->mCallback);
@@ -985,10 +994,12 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
// Not expecting callback removal.
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
}
@@ -1006,10 +1017,12 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
// Not expecting callback removal.
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
// Now disable.
mIncrementalService->disallowReadLogs(storageId);
@@ -1032,10 +1045,12 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChang
// After callback is called, disable read logs and remove callback.
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(1);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
ASSERT_NE(nullptr, mAppOpsManager->mStoredCallback.get());
mAppOpsManager->mStoredCallback->opChanged(0, {});
@@ -1051,10 +1066,12 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
ASSERT_LT(mDataLoader->setStorageParams(true), 0);
}
@@ -1068,10 +1085,12 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionNoCrossUse
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
ASSERT_LT(mDataLoader->setStorageParams(true), 0);
}
@@ -1087,18 +1106,20 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
ASSERT_LT(mDataLoader->setStorageParams(true), 0);
}
TEST_F(IncrementalServiceTest, testMakeDirectory) {
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
std::string dir_path("test");
// Expecting incfs to call makeDir on a path like:
@@ -1115,9 +1136,9 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) {
TEST_F(IncrementalServiceTest, testMakeDirectories) {
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
auto first = "first"sv;
auto second = "second"sv;
auto third = "third"sv;
@@ -1138,9 +1159,9 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithNoFile) {
mFs->hasNoFile();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
}
@@ -1149,9 +1170,9 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithFailedRanges) {
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
}
@@ -1161,9 +1182,9 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccessWithEmptyRanges) {
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
}
@@ -1173,9 +1194,9 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
}
@@ -1185,10 +1206,12 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
mFs->hasNoFile();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
- ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId).getProgress());
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_EQ(1,
+ mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
+ .getProgress());
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
@@ -1196,11 +1219,13 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
- ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId).getProgress());
+ ASSERT_EQ(-1,
+ mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
+ .getProgress());
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithEmptyRanges) {
@@ -1208,11 +1233,13 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithEmptyRanges) {
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
- ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId).getProgress());
+ ASSERT_EQ(1,
+ mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
+ .getProgress());
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
@@ -1220,11 +1247,13 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
- ASSERT_EQ(0.5, mIncrementalService->getLoadingProgress(storageId).getProgress());
+ ASSERT_EQ(0.5,
+ mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
+ .getProgress());
}
TEST_F(IncrementalServiceTest, testRegisterLoadingProgressListenerSuccess) {
@@ -1232,9 +1261,9 @@ TEST_F(IncrementalServiceTest, testRegisterLoadingProgressListenerSuccess) {
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
sp<NiceMock<MockStorageLoadingProgressListener>> listener{
new NiceMock<MockStorageLoadingProgressListener>};
NiceMock<MockStorageLoadingProgressListener>* listenerMock = listener.get();
@@ -1257,9 +1286,9 @@ TEST_F(IncrementalServiceTest, testRegisterLoadingProgressListenerFailsToGetProg
mFs->hasFiles();
TemporaryDir tempDir;
- int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew,
- {}, {}, {}, {});
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
sp<NiceMock<MockStorageLoadingProgressListener>> listener{
new NiceMock<MockStorageLoadingProgressListener>};
NiceMock<MockStorageLoadingProgressListener>* listenerMock = listener.get();
@@ -1275,10 +1304,12 @@ TEST_F(IncrementalServiceTest, testRegisterStorageHealthListenerSuccess) {
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew, {},
- StorageHealthCheckParams{}, listener, {});
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, listener,
+ {});
+
StorageHealthCheckParams newParams;
newParams.blockedTimeoutMs = 10000;
newParams.unhealthyTimeoutMs = 20000;
@@ -1378,19 +1409,19 @@ TEST_F(IncrementalServiceTest, testPerUidTimeoutsTooShort) {
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
- EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(1);
EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
EXPECT_CALL(*mIncFs, setUidReadTimeouts(_, _)).Times(0);
EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew, {}, {},
- {},
- createPerUidTimeouts(
- {{0, 1, 2, 3}, {1, 2, 3, 4}, {2, 3, 4, 5}}));
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {},
+ createPerUidTimeouts(
+ {{0, 1, 2, 3}, {1, 2, 3, 4}, {2, 3, 4, 5}}));
}
TEST_F(IncrementalServiceTest, testPerUidTimeoutsSuccess) {
@@ -1410,13 +1441,12 @@ TEST_F(IncrementalServiceTest, testPerUidTimeoutsSuccess) {
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew, {}, {},
- {},
- createPerUidTimeouts({{0, 1, 2, 3},
- {1, 2, 3, 4},
- {2, 3, 4, 100000000}}));
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {},
+ createPerUidTimeouts(
+ {{0, 1, 2, 3}, {1, 2, 3, 4}, {2, 3, 4, 100000000}}));
{
// Timed callback present -> 0 progress.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d28c3cc8e2b8..544eedf99c9e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -360,6 +360,8 @@ public final class SystemServer implements Dumpable {
private static final String IP_CONNECTIVITY_METRICS_CLASS =
"com.android.server.connectivity.IpConnectivityMetrics";
private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService";
+ private static final String GAME_MANAGER_SERVICE_CLASS =
+ "com.android.server.graphics.GameManagerService$Lifecycle";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -2514,6 +2516,10 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
+ t.traceBegin("GameManagerService");
+ mSystemServiceManager.startService(GAME_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
+
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 091e688743dd..5453de14a5f1 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -45,7 +45,6 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.people.data.DataManager;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -156,6 +155,13 @@ public class PeopleService extends SystemService {
final IBinder mService = new IPeopleManager.Stub() {
@Override
+ public ConversationChannel getConversation(
+ String packageName, int userId, String shortcutId) {
+ enforceSystemRootOrSystemUI(getContext(), "get conversation");
+ return mDataManager.getConversation(packageName, userId, shortcutId);
+ }
+
+ @Override
public ParceledListSlice<ConversationChannel> getRecentConversations() {
enforceSystemRootOrSystemUI(getContext(), "get recent conversations");
return new ParceledListSlice<>(
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 752141598c9d..9a9a17112245 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -222,33 +222,65 @@ public class DataManager {
mContext.getPackageName(), intentFilter, callingUserId);
}
+ /**
+ * Returns a {@link ConversationChannel} with the associated {@code shortcutId} if existent.
+ * Otherwise, returns null.
+ */
+ @Nullable
+ public ConversationChannel getConversation(String packageName, int userId, String shortcutId) {
+ UserData userData = getUnlockedUserData(userId);
+ if (userData != null) {
+ PackageData packageData = userData.getPackageData(packageName);
+ // App may have been uninstalled.
+ if (packageData != null) {
+ return getConversationChannel(packageData, shortcutId);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private ConversationChannel getConversationChannel(PackageData packageData, String shortcutId) {
+ ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
+ if (conversationInfo == null) {
+ return null;
+ }
+ int userId = packageData.getUserId();
+ String packageName = packageData.getPackageName();
+ ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
+ if (shortcutInfo == null) {
+ return null;
+ }
+ int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
+ NotificationChannel parentChannel =
+ mNotificationManagerInternal.getNotificationChannel(packageName, uid,
+ conversationInfo.getParentNotificationChannelId());
+ NotificationChannelGroup parentChannelGroup = null;
+ if (parentChannel != null) {
+ parentChannelGroup =
+ mNotificationManagerInternal.getNotificationChannelGroup(packageName,
+ uid, parentChannel.getId());
+ }
+ return new ConversationChannel(shortcutInfo, uid, parentChannel,
+ parentChannelGroup,
+ conversationInfo.getLastEventTimestamp(),
+ hasActiveNotifications(packageName, userId, shortcutId));
+ }
+
/** Returns the cached non-customized recent conversations. */
public List<ConversationChannel> getRecentConversations(@UserIdInt int callingUserId) {
List<ConversationChannel> conversationChannels = new ArrayList<>();
forPackagesInProfile(callingUserId, packageData -> {
- String packageName = packageData.getPackageName();
- int userId = packageData.getUserId();
packageData.forAllConversations(conversationInfo -> {
if (!isCachedRecentConversation(conversationInfo)) {
return;
}
String shortcutId = conversationInfo.getShortcutId();
- ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
- int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
- NotificationChannel parentChannel =
- mNotificationManagerInternal.getNotificationChannel(packageName, uid,
- conversationInfo.getParentNotificationChannelId());
- if (shortcutInfo == null || parentChannel == null) {
+ ConversationChannel channel = getConversationChannel(packageData, shortcutId);
+ if (channel == null || channel.getParentNotificationChannel() == null) {
return;
}
- NotificationChannelGroup parentChannelGroup =
- mNotificationManagerInternal.getNotificationChannelGroup(packageName,
- uid, parentChannel.getId());
- conversationChannels.add(
- new ConversationChannel(shortcutInfo, uid, parentChannel,
- parentChannelGroup,
- conversationInfo.getLastEventTimestamp(),
- hasActiveNotifications(packageName, userId, shortcutId)));
+ conversationChannels.add(channel);
});
});
return conversationChannels;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
index 17f326fbdbce..a18632b8d1b2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
@@ -118,8 +118,12 @@ public class AppChildProcessTest {
@After
public void tearDown() {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
- mMockitoSession.finishMocking();
- mHandlerThread.quit();
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ }
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index e9a50b36693a..9441ecf74e83 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -164,24 +164,24 @@ public class ApplicationExitInfoTest {
}
private void updateExitInfo(ProcessRecord app) {
- ApplicationExitInfo raw = mAppExitInfoTracker.obtainRawRecordLocked(app);
+ ApplicationExitInfo raw = mAppExitInfoTracker.obtainRawRecord(app);
mAppExitInfoTracker.handleNoteProcessDiedLocked(raw);
- mAppExitInfoTracker.recycleRawRecordLocked(raw);
+ mAppExitInfoTracker.recycleRawRecord(raw);
}
private void noteAppKill(ProcessRecord app, int reason, int subReason, String msg) {
- ApplicationExitInfo raw = mAppExitInfoTracker.obtainRawRecordLocked(app);
+ ApplicationExitInfo raw = mAppExitInfoTracker.obtainRawRecord(app);
raw.setReason(reason);
raw.setSubReason(subReason);
raw.setDescription(msg);
mAppExitInfoTracker.handleNoteAppKillLocked(raw);
- mAppExitInfoTracker.recycleRawRecordLocked(raw);
+ mAppExitInfoTracker.recycleRawRecord(raw);
}
@Test
public void testApplicationExitInfo() throws Exception {
mAppExitInfoTracker.clearProcessExitInfo(true);
- mAppExitInfoTracker.mAppExitInfoLoaded = true;
+ mAppExitInfoTracker.mAppExitInfoLoaded.set(true);
mAppExitInfoTracker.mProcExitStoreDir = new File(mContext.getFilesDir(),
AppExitInfoTracker.APP_EXIT_STORE_DIR);
assertTrue(FileUtils.createDir(mAppExitInfoTracker.mProcExitStoreDir));
@@ -1001,9 +1001,9 @@ public class ApplicationExitInfoTest {
}
app.connectionGroup = connectionGroup;
app.setProcState = procState;
- app.lastMemInfo = spy(new Debug.MemoryInfo());
- app.lastPss = pss;
- app.mLastRss = rss;
+ app.mProfile.setLastMemInfo(spy(new Debug.MemoryInfo()));
+ app.mProfile.setLastPss(pss);
+ app.mProfile.setLastRss(rss);
return app;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
index 37103965de3b..c82db7305bd8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
@@ -84,7 +84,7 @@ public class CacheOomRankerTest {
private int mNextPackageName = 1;
private TestExecutor mExecutor = new TestExecutor();
- private CacheOomRanker mCacheOomRanker = new CacheOomRanker();
+ private CacheOomRanker mCacheOomRanker;
@Before
public void setUp() {
@@ -107,6 +107,7 @@ public class CacheOomRankerTest {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+ mCacheOomRanker = new CacheOomRanker(mAms);
mCacheOomRanker.init(mExecutor);
}
@@ -383,7 +384,7 @@ public class CacheOomRankerTest {
app.setProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
app.setAdj = setAdj;
app.lastActivityTime = lastActivityTime;
- app.mLastRss = lastRss;
+ app.mProfile.setLastRss(lastRss);
app.setCached(false);
for (int i = 0; i < returnedToCacheCount; ++i) {
app.setCached(false);
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 8011ec2c8fa4..7daf357705bc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -103,6 +103,7 @@ import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Test class for {@link OomAdjuster}.
@@ -159,8 +160,9 @@ public class MockingOomAdjusterTests {
sContext.getMainThreadHandler());
setFieldValue(ActivityManagerService.class, sService, "mContext",
sContext);
- ProcessList pr = new ProcessList();
- pr.init(sService, new ActiveUids(sService, false), null);
+ ProcessList pr = spy(new ProcessList());
+ pr.mService = sService;
+ AppProfiler profiler = mock(AppProfiler.class);
setFieldValue(ActivityManagerService.class, sService, "mProcessList",
pr);
setFieldValue(ActivityManagerService.class, sService, "mHandler",
@@ -173,13 +175,14 @@ public class MockingOomAdjusterTests {
mock(OomAdjProfiler.class));
setFieldValue(ActivityManagerService.class, sService, "mUserController",
mock(UserController.class));
- setFieldValue(ActivityManagerService.class, sService, "mAppProfiler",
- mock(AppProfiler.class));
- doReturn(new ActivityManagerService.ProcessChangeItem()).when(sService)
+ setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler);
+ setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
+ doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr)
.enqueueProcessChangeItemLocked(anyInt(), anyInt());
sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList,
mock(ActiveUids.class));
sService.mOomAdjuster.mAdjSeq = 10000;
+ sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
}
@AfterClass
@@ -206,9 +209,9 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.maxAdj = PERSISTENT_PROC_ADJ;
app.setHasTopUi(true);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_ASLEEP;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERSISTENT_PROC_ADJ,
SCHED_GROUP_RESTRICTED);
@@ -221,7 +224,7 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.maxAdj = PERSISTENT_PROC_ADJ;
app.setHasTopUi(true);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
@@ -234,10 +237,10 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.maxAdj = PERSISTENT_PROC_ADJ;
- doReturn(app).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(app).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
SCHED_GROUP_TOP_APP);
@@ -249,10 +252,10 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(app).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_TOP_APP);
}
@@ -264,7 +267,7 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
app.runningRemoteAnimation = true;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
@@ -277,7 +280,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(mock(ActiveInstrumentation.class)).when(app).getActiveInstrumentation();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doCallRealMethod().when(app).getActiveInstrumentation();
@@ -292,7 +295,7 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(true).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(ArraySet.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(false).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(ArraySet.class));
@@ -306,7 +309,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.executingServices.add(mock(ServiceRecord.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_SERVICE, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -318,12 +321,12 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_ASLEEP;
+ doReturn(app).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, FOREGROUND_APP_ADJ,
SCHED_GROUP_BACKGROUND);
@@ -335,8 +338,8 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.setCurRawAdj(CACHED_APP_MIN_ADJ);
- doReturn(null).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(null).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, CACHED_APP_MIN_ADJ,
@@ -363,7 +366,7 @@ public class MockingOomAdjusterTests {
return 0;
})).when(wpc).computeOomAdjFromActivities(
any(WindowProcessController.ComputeOomAdjCallback.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doCallRealMethod().when(app).getWindowProcessController();
@@ -379,7 +382,7 @@ public class MockingOomAdjusterTests {
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).hasRecentTasks();
app.lastTopTime = SystemClock.uptimeMillis();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doCallRealMethod().when(wpc).hasRecentTasks();
@@ -392,7 +395,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -405,7 +408,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.setHasForegroundServices(true, 0);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -418,7 +421,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.setHasOverlayUi(true);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
@@ -432,7 +435,7 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.setHasForegroundServices(true, 0);
app.lastTopTime = SystemClock.uptimeMillis();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE,
@@ -445,7 +448,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.forcingToImportant = new Object();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -460,7 +463,7 @@ public class MockingOomAdjusterTests {
doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHeavyWeightProcess();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(false).when(wpc).isHeavyWeightProcess();
@@ -476,7 +479,7 @@ public class MockingOomAdjusterTests {
doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_HOME, HOME_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -491,7 +494,7 @@ public class MockingOomAdjusterTests {
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isPreviousProcess();
doReturn(true).when(wpc).hasActivities();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
@@ -506,7 +509,7 @@ public class MockingOomAdjusterTests {
BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
backupTarget.app = app;
doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(null).when(sService.mBackupTargets).get(anyInt());
@@ -520,7 +523,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(true).when(app).hasClientActivities();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.setProcState);
@@ -532,7 +535,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.treatLikeActivity = true;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.setProcState);
@@ -549,7 +552,7 @@ public class MockingOomAdjusterTests {
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
app.startService(s);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_B_ADJ, SCHED_GROUP_BACKGROUND);
@@ -561,7 +564,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.maxAdj = PERCEPTIBLE_LOW_APP_ADJ;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, PERCEPTIBLE_LOW_APP_ADJ,
@@ -575,8 +578,8 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.setCached(false);
app.setCurRawAdj(SERVICE_ADJ);
- doReturn(null).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(null).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.setAdj);
@@ -593,7 +596,7 @@ public class MockingOomAdjusterTests {
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
app.startService(s);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -609,11 +612,11 @@ public class MockingOomAdjusterTests {
ServiceRecord s = bindService(app, client, null, Context.BIND_WAIVE_PRIORITY,
mock(IBinder.class));
s.startRequested = true;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopAppLocked();
+ doReturn(client).when(sService).getTopApp();
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
assertProcStates(app, PROCESS_STATE_SERVICE, UNKNOWN_ADJ, SCHED_GROUP_BACKGROUND);
}
@@ -627,7 +630,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.setProcState);
@@ -647,7 +650,7 @@ public class MockingOomAdjusterTests {
setFieldValue(ConnectionRecord.class, cr, "activity",
mock(ActivityServiceConnectionsHolder.class));
doReturn(true).when(cr.activity).isActivityVisible();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(FOREGROUND_APP_ADJ, app.setAdj);
@@ -660,7 +663,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
bindService(app, app, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, UNKNOWN_ADJ, SCHED_GROUP_BACKGROUND);
@@ -675,7 +678,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.treatLikeActivity = true;
bindService(app, client, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_CACHED_EMPTY, app.setProcState);
@@ -695,10 +698,10 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_ALLOW_OOM_MANAGEMENT, mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(client).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
assertEquals(PREVIOUS_APP_ADJ, app.setAdj);
}
@@ -713,7 +716,7 @@ public class MockingOomAdjusterTests {
bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.maxAdj = PERSISTENT_PROC_ADJ;
client.setHasTopUi(true);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -729,7 +732,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_IMPORTANT, mock(IBinder.class));
client.executingServices.add(mock(ServiceRecord.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(FOREGROUND_APP_ADJ, app.setAdj);
@@ -744,10 +747,10 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, 0, mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(client).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT);
}
@@ -761,7 +764,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.maxAdj = PERSISTENT_PROC_ADJ;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.setProcState);
@@ -776,7 +779,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
client.maxAdj = PERSISTENT_PROC_ADJ;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.setProcState);
@@ -791,7 +794,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, 0, mock(IBinder.class));
client.setHasForegroundServices(true, 0);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, app.setProcState);
@@ -808,7 +811,7 @@ public class MockingOomAdjusterTests {
BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
backupTarget.app = client;
doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(null).when(sService.mBackupTargets).get(anyInt());
@@ -829,7 +832,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
client.runningRemoteAnimation = true;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.setAdj);
@@ -844,7 +847,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
client.runningRemoteAnimation = true;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PERCEPTIBLE_APP_ADJ, app.setAdj);
@@ -859,7 +862,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, 0, mock(IBinder.class));
client.setHasOverlayUi(true);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PERCEPTIBLE_APP_ADJ, app.setAdj);
@@ -874,7 +877,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, 0, mock(IBinder.class));
client.runningRemoteAnimation = true;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(VISIBLE_APP_ADJ, app.setAdj);
@@ -889,7 +892,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, Context.BIND_IMPORTANT_BACKGROUND, mock(IBinder.class));
client.setHasOverlayUi(true);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.setProcState);
@@ -915,7 +918,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, false);
client.treatLikeActivity = true;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, UNKNOWN_ADJ, SCHED_GROUP_BACKGROUND);
@@ -930,10 +933,10 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, false);
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(client).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
}
@@ -947,7 +950,7 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.setHasForegroundServices(true, 0);
bindProvider(app, client, null, null, false);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -962,7 +965,7 @@ public class MockingOomAdjusterTests {
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, true);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, FOREGROUND_APP_ADJ,
@@ -975,7 +978,7 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.lastProviderTime = SystemClock.uptimeMillis();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
@@ -994,10 +997,10 @@ public class MockingOomAdjusterTests {
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, 0, mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client2).when(sService).getTopAppLocked();
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ doReturn(client2).when(sService).getTopApp();
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(null).when(sService).getTopAppLocked();
+ doReturn(null).when(sService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
@@ -1015,7 +1018,7 @@ public class MockingOomAdjusterTests {
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(app, client2, null, 0, mock(IBinder.class));
client2.setHasForegroundServices(true, 0);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1034,7 +1037,7 @@ public class MockingOomAdjusterTests {
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, 0, mock(IBinder.class));
client2.setHasForegroundServices(true, 0);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1059,7 +1062,7 @@ public class MockingOomAdjusterTests {
lru.add(app);
lru.add(client);
lru.add(client2);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, true, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1070,7 +1073,7 @@ public class MockingOomAdjusterTests {
SCHED_GROUP_DEFAULT);
client2.setHasForegroundServices(false, 0);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(client2, true, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.setProcState);
@@ -1096,7 +1099,7 @@ public class MockingOomAdjusterTests {
lru.add(app);
lru.add(client);
lru.add(client2);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, true, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1124,7 +1127,7 @@ public class MockingOomAdjusterTests {
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.forcingToImportant = new Object();
bindService(app, client3, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1150,7 +1153,7 @@ public class MockingOomAdjusterTests {
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.forcingToImportant = new Object();
bindService(app, client3, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1178,7 +1181,7 @@ public class MockingOomAdjusterTests {
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.forcingToImportant = new Object();
bindService(app, client4, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1208,7 +1211,7 @@ public class MockingOomAdjusterTests {
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.setHasForegroundServices(true, 0);
bindService(app, client4, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1234,7 +1237,7 @@ public class MockingOomAdjusterTests {
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.forcingToImportant = new Object();
bindService(app, client3, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1253,7 +1256,7 @@ public class MockingOomAdjusterTests {
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
client2.setHasForegroundServices(true, 0);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1273,7 +1276,7 @@ public class MockingOomAdjusterTests {
bindProvider(client, client2, null, null, false);
client2.setHasForegroundServices(true, 0);
bindService(client2, app, null, 0, mock(IBinder.class));
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1292,7 +1295,7 @@ public class MockingOomAdjusterTests {
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
client2.setHasForegroundServices(true, 0);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1312,7 +1315,7 @@ public class MockingOomAdjusterTests {
bindProvider(client, client2, null, null, false);
client2.setHasForegroundServices(true, 0);
bindProvider(client2, app, null, null, false);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1332,7 +1335,7 @@ public class MockingOomAdjusterTests {
lru.clear();
lru.add(app);
lru.add(app2);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1356,7 +1359,7 @@ public class MockingOomAdjusterTests {
lru.clear();
lru.add(app);
lru.add(app2);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1384,7 +1387,7 @@ public class MockingOomAdjusterTests {
lru.add(app);
lru.add(app2);
lru.add(app3);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1435,7 +1438,7 @@ public class MockingOomAdjusterTests {
lru.add(app3);
lru.add(app4);
lru.add(app5);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1481,7 +1484,7 @@ public class MockingOomAdjusterTests {
lru.add(app3);
lru.add(app2);
lru.add(app);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1527,7 +1530,7 @@ public class MockingOomAdjusterTests {
lru.add(app2);
lru.add(app);
lru.add(app5);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1573,7 +1576,7 @@ public class MockingOomAdjusterTests {
lru.add(app3);
lru.add(app4);
lru.add(app5);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1618,7 +1621,7 @@ public class MockingOomAdjusterTests {
lru.add(app3);
lru.add(app2);
lru.add(app);
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.mNumServiceProcs = 3;
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
lru.clear();
@@ -1678,7 +1681,7 @@ public class MockingOomAdjusterTests {
app2.startService(s2);
app2.hasShownUi = false;
- sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services");
@@ -1773,11 +1776,12 @@ public class MockingOomAdjusterTests {
ai.longVersionCode = versionCode;
ai.targetSdkVersion = targetSdkVersion;
ProcessRecord app = new ProcessRecord(service, ai, processName, uid);
+ final ProcessProfileRecord profile = app.mProfile;
app.thread = mock(IApplicationThread.class);
app.lastActivityTime = lastActivityTime;
- app.lastPssTime = lastPssTime;
- app.nextPssTime = nextPssTime;
- app.lastPss = lastPss;
+ profile.setLastPssTime(lastPssTime);
+ profile.setNextPssTime(nextPssTime);
+ profile.setLastPss(lastPss);
app.maxAdj = maxAdj;
app.setRawAdj = setRawAdj;
app.curAdj = curAdj;
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java
index c9fcd0233bef..c5e1ed1f04c6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java
@@ -37,6 +37,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -82,6 +83,13 @@ public class UsageStatsServiceTest {
mService.onStart();
}
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
@Test
public void testUsageEventListener() throws Exception {
TestUsageEventListener listener = new TestUsageEventListener();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index df8a720d59b9..110bb21b5851 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -164,9 +164,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
@SmallTest
public void testRegisterSystemActionWithoutPermission() throws Exception {
doThrow(SecurityException.class).when(mMockSecurityPolicy)
- .enforceCallerIsRecentsOrHasPermission(
- Manifest.permission.MANAGE_ACCESSIBILITY,
- AccessibilityManagerService.FUNCTION_REGISTER_SYSTEM_ACTION);
+ .enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
try {
mA11yms.registerSystemAction(TEST_ACTION, ACTION_ID);
@@ -185,9 +183,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
@SmallTest
public void testUnregisterSystemActionWithoutPermission() throws Exception {
doThrow(SecurityException.class).when(mMockSecurityPolicy)
- .enforceCallerIsRecentsOrHasPermission(
- Manifest.permission.MANAGE_ACCESSIBILITY,
- AccessibilityManagerService.FUNCTION_UNREGISTER_SYSTEM_ACTION);
+ .enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
try {
mA11yms.unregisterSystemAction(ACTION_ID);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index cc8ac86d6b59..c7e7c7861370 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -51,9 +51,6 @@ import android.util.ArraySet;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityWindowInfo;
-import com.android.server.LocalServices;
-import com.android.server.wm.ActivityTaskManagerInternal;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -123,7 +120,6 @@ public class AccessibilitySecurityPolicyTest {
@Mock private AccessibilityWindowManager mMockA11yWindowManager;
@Mock private AppWidgetManagerInternal mMockAppWidgetManager;
@Mock private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
- @Mock private ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
@Before
public void setUp() {
@@ -132,10 +128,6 @@ public class AccessibilitySecurityPolicyTest {
when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager);
- LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
- LocalServices.addService(
- ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal);
-
mA11ySecurityPolicy = new AccessibilitySecurityPolicy(mMockContext, mMockA11yUserManager);
mA11ySecurityPolicy.setAccessibilityWindowManager(mMockA11yWindowManager);
mA11ySecurityPolicy.setAppWidgetManager(mMockAppWidgetManager);
@@ -570,10 +562,4 @@ public class AccessibilitySecurityPolicyTest {
APP_UID, PACKAGE_NAME);
}
- @Test
- public void testEnforceCallerIsRecentsOrHasPermission() {
- mA11ySecurityPolicy.enforceCallerIsRecentsOrHasPermission(PERMISSION, FUNCTION);
- verify(mMockActivityTaskManagerInternal).enforceCallerIsRecentsOrHasPermission(
- PERMISSION, FUNCTION);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
index 4f58c87e61ea..7355b80940a4 100644
--- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -40,6 +40,9 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
/**
* Test class for {@link OomAdjuster}.
*
@@ -76,6 +79,9 @@ public class OomAdjusterTests {
sService.mConstants = new ActivityManagerConstants(sContext, sService,
sContext.getMainThreadHandler());
+ final AppProfiler profiler = mock(AppProfiler.class);
+ setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
+ setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler);
sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null);
LocalServices.addService(UsageStatsManagerInternal.class,
mock(UsageStatsManagerInternal.class));
@@ -83,6 +89,18 @@ public class OomAdjusterTests {
});
}
+ private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ Field mfield = Field.class.getDeclaredField("accessFlags");
+ mfield.setAccessible(true);
+ mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE));
+ field.set(obj, val);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ }
+ }
+
@AfterClass
public static void tearDownOnce() {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
index ded14b89d01c..263efa670a67 100644
--- a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
@@ -42,6 +42,8 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.util.Collections;
/**
@@ -67,6 +69,11 @@ public class ProcessRecordTests {
sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal();
+ final AppProfiler profiler = mock(AppProfiler.class);
+ setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
+ setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler);
+ final ProcessList processList = new ProcessList();
+ setFieldValue(ActivityManagerService.class, sService, "mProcessList", processList);
});
// Avoid NPE when initializing {@link ProcessRecord#mWindowProcessController}.
@@ -76,6 +83,18 @@ public class ProcessRecordTests {
doReturn(sysUiName).when(packageManagerInternal).getSystemUiServiceComponent();
}
+ private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ Field mfield = Field.class.getDeclaredField("accessFlags");
+ mfield.setAccessible(true);
+ mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE));
+ field.set(obj, val);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ }
+ }
+
@AfterClass
public static void tearDownOnce() {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 784718b5f51e..9ffb50176f0e 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -770,7 +770,7 @@ public class UserControllerTest {
}
@Override
- void reportGlobalUsageEventLocked(int event) {
+ void reportGlobalUsageEvent(int event) {
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index d0370b6c25e9..45bca6829553 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -64,6 +64,8 @@ public final class AppHibernationServiceTest {
private static final int USER_ID_1 = 1;
private static final int USER_ID_2 = 2;
+ private final List<UserInfo> mUserInfos = new ArrayList<>();
+
private AppHibernationService mAppHibernationService;
private BroadcastReceiver mBroadcastReceiver;
@Mock
@@ -88,47 +90,42 @@ public final class AppHibernationServiceTest {
verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any());
mBroadcastReceiver = mReceiverCaptor.getValue();
- List<UserInfo> userList = new ArrayList<>();
- userList.add(new UserInfo(USER_ID_1, "user 1", 0 /* flags */));
- doReturn(userList).when(mUserManager).getUsers();
-
- List<PackageInfo> userPackages = new ArrayList<>();
- userPackages.add(makePackageInfo(PACKAGE_NAME_1));
-
- doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
- .getInstalledPackages(anyInt(), eq(USER_ID_1));
+ doReturn(mUserInfos).when(mUserManager).getUsers();
doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), any(), any());
+ addUser(USER_ID_1);
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
}
@Test
- public void testSetHibernating_packageIsHibernating() {
+ public void testSetHibernatingForUser_packageIsHibernating() throws RemoteException {
// WHEN we hibernate a package for a user
- mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
// THEN the package is marked hibernating for the user
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
}
@Test
- public void testSetHibernating_newPackageAdded_packageIsHibernating() {
+ public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating()
+ throws RemoteException {
// WHEN a new package is added and it is hibernated
Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED,
Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1);
mBroadcastReceiver.onReceive(mContext, intent);
- mAppHibernationService.setHibernating(PACKAGE_NAME_2, USER_ID_1, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_1, true);
// THEN the new package is hibernated
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_2, USER_ID_1));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_2, USER_ID_1));
}
@Test
- public void testSetHibernating_newUserAdded_packageIsHibernating() throws RemoteException {
+ public void testSetHibernatingForUser_newUserAdded_packageIsHibernating()
+ throws RemoteException {
// WHEN a new user is added and a package from the user is hibernated
List<PackageInfo> userPackages = new ArrayList<>();
userPackages.add(makePackageInfo(PACKAGE_NAME_1));
@@ -138,16 +135,17 @@ public final class AppHibernationServiceTest {
intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_2);
mBroadcastReceiver.onReceive(mContext, intent);
- mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_2, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
// THEN the new user's package is hibernated
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_2));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_2));
}
@Test
- public void testIsHibernating_packageReplaced_stillReturnsHibernating() {
+ public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating()
+ throws RemoteException {
// GIVEN a package is currently hibernated
- mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
// WHEN the package is removed but marked as replacing
Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
@@ -157,7 +155,38 @@ public final class AppHibernationServiceTest {
mBroadcastReceiver.onReceive(mContext, intent);
// THEN the package is still hibernating
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
+ }
+
+ @Test
+ public void testSetHibernatingGlobally_packageIsHibernatingGlobally() throws RemoteException {
+ // WHEN we hibernate a package
+ mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
+
+ // THEN the package is marked hibernating for the user
+ assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
+ }
+
+ /**
+ * Add a mock user with one package. Must be called before
+ * {@link AppHibernationService#onBootPhase(int)} to work properly.
+ */
+ private void addUser(int userId) throws RemoteException {
+ addUser(userId, new String[]{PACKAGE_NAME_1});
+ }
+
+ /**
+ * Add a mock user with the packages specified. Must be called before
+ * {@link AppHibernationService#onBootPhase(int)} to work properly
+ */
+ private void addUser(int userId, String[] packageNames) throws RemoteException {
+ mUserInfos.add(new UserInfo(userId, "user_" + userId, 0 /* flags */));
+ List<PackageInfo> userPackages = new ArrayList<>();
+ for (String pkgName : packageNames) {
+ userPackages.add(makePackageInfo(pkgName));
+ }
+ doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
+ .getInstalledPackages(anyInt(), eq(userId));
}
private static PackageInfo makePackageInfo(String packageName) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 57b0d01b3025..2d457260b8fe 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -196,7 +196,8 @@ public class BiometricSchedulerTest {
BiometricSchedulerProto bsp = getDump(true /* clearSchedulerBuffer */);
assertEquals(BiometricsProto.CM_NONE, bsp.currentOperation);
assertEquals(0, bsp.totalOperations);
- assertEquals(0, bsp.recentOperations.length);
+ // TODO:(b/178828362) See bug and/or commit message :/
+ // assertEquals(0, bsp.recentOperations.length);
// Pretend the scheduler is busy enrolling, and check the proto dump again.
final TestClientMonitor2 client = new TestClientMonitor2(mContext, mToken,
@@ -207,7 +208,11 @@ public class BiometricSchedulerTest {
assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation);
// No operations have completed yet
assertEquals(0, bsp.totalOperations);
- assertEquals(0, bsp.recentOperations.length);
+
+ // TODO:(b/178828362) See bug and/or commit message :/
+ assertEquals(1, bsp.recentOperations.length);
+ assertEquals(BiometricsProto.CM_NONE, bsp.recentOperations[0]);
+
// Finish this operation, so the next scheduled one can start
client.getCallback().onClientFinished(client, true);
}
@@ -223,7 +228,8 @@ public class BiometricSchedulerTest {
assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation);
// No operations have completed yet
assertEquals(0, bsp.totalOperations);
- assertEquals(0, bsp.recentOperations.length);
+ // TODO:(b/178828362) See bug and/or commit message :/
+ // assertEquals(0, bsp.recentOperations.length);
// Finish this operation, so the next scheduled one can start
client.getCallback().onClientFinished(client, true);
@@ -265,7 +271,10 @@ public class BiometricSchedulerTest {
// RecentOperations queue is cleared (by the previous dump)
bsp = getDump(true /* clearSchedulerBuffer */);
- assertEquals(0, bsp.recentOperations.length);
+
+ // TODO:(b/178828362) See bug and/or commit message :/
+ assertEquals(1, bsp.recentOperations.length);
+ assertEquals(BiometricsProto.CM_NONE, bsp.recentOperations[0]);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceSettingsTests.java b/services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceSettingsTests.java
new file mode 100644
index 000000000000..6fc6b9eb3da3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceSettingsTests.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 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.graphics;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.util.AtomicFile;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GameManagerServiceSettingsTests {
+
+ private static final String TAG = "GameServiceSettingsTests";
+ private static final String PACKAGE_NAME_1 = "com.android.app1";
+ private static final String PACKAGE_NAME_2 = "com.android.app2";
+ private static final String PACKAGE_NAME_3 = "com.android.app3";
+
+ private void writeFile(File file, byte[] data) {
+ file.mkdirs();
+ try {
+ AtomicFile aFile = new AtomicFile(file);
+ FileOutputStream fos = aFile.startWrite();
+ fos.write(data);
+ aFile.finishWrite(fos);
+ } catch (IOException ioe) {
+ Log.e(TAG, "Cannot write file " + file.getPath());
+ }
+ }
+
+ private void writeGameServiceXml() {
+ writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(),
+ "system/game-manager-service.xml"),
+ ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<packages>\n"
+ + " <package name=\"com.android.app1\" gameMode=\"1\">\n"
+ + " </package>\n"
+ + " <package name=\"com.android.app2\" gameMode=\"2\">\n"
+ + " </package>\n"
+ + " <package name=\"com.android.app3\" gameMode=\"3\">\n"
+ + " </package>\n"
+ + "</packages>\n").getBytes());
+ }
+
+ private void deleteSystemFolder() {
+ File systemFolder = new File(InstrumentationRegistry.getContext().getFilesDir(), "system");
+ deleteFolder(systemFolder);
+ }
+
+ private static void deleteFolder(File folder) {
+ File[] files = folder.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ deleteFolder(file);
+ }
+ }
+ folder.delete();
+ }
+
+ private void writeOldFiles() {
+ deleteSystemFolder();
+ writeGameServiceXml();
+ }
+
+ private void verifyGameServiceSettingsData(Settings settings) {
+ assertThat(settings.getGameModeLocked(PACKAGE_NAME_1), is(1));
+ assertThat(settings.getGameModeLocked(PACKAGE_NAME_2), is(2));
+ assertThat(settings.getGameModeLocked(PACKAGE_NAME_3), is(3));
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ deleteFolder(InstrumentationRegistry.getTargetContext().getFilesDir());
+ }
+
+ /** read in data and verify */
+ @Test
+ public void testReadGameServiceSettings() {
+ /* write out files and read */
+ writeOldFiles();
+ final Context context = InstrumentationRegistry.getContext();
+ Settings settings = new Settings(context.getFilesDir());
+ assertThat(settings.readPersistentDataLocked(), is(true));
+ verifyGameServiceSettingsData(settings);
+ }
+
+ /** read in data, write it out, and read it back in. Verify same. */
+ @Test
+ public void testWriteGameServiceSettings() {
+ // write out files and read
+ writeOldFiles();
+ final Context context = InstrumentationRegistry.getContext();
+ Settings settings = new Settings(context.getFilesDir());
+ assertThat(settings.readPersistentDataLocked(), is(true));
+
+ // write out, read back in and verify the same
+ settings.writePersistentDataLocked();
+ assertThat(settings.readPersistentDataLocked(), is(true));
+ verifyGameServiceSettingsData(settings);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceTests.java
new file mode 100644
index 000000000000..22df645f7619
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/graphics/GameManagerServiceTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 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.graphics;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.GameManager;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GameManagerServiceTests {
+
+ private static final String TAG = "GameServiceTests";
+ private static final String PACKAGE_NAME_0 = "com.android.app0";
+ private static final String PACKAGE_NAME_1 = "com.android.app1";
+ private static final int USER_ID_1 = 1001;
+ private static final int USER_ID_2 = 1002;
+
+ /**
+ * By default game mode is not supported.
+ */
+ @Test
+ public void testGameModeDefaultValue() {
+ GameManagerService gameManagerService =
+ new GameManagerService(InstrumentationRegistry.getContext());
+ gameManagerService.onUserStarting(USER_ID_1);
+
+ assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ gameManagerService.getGameMode(PACKAGE_NAME_0, USER_ID_1));
+ }
+
+ /**
+ * Test the default behaviour for a nonexistent user.
+ */
+ @Test
+ public void testDefaultValueForNonexistentUser() {
+ GameManagerService gameManagerService =
+ new GameManagerService(InstrumentationRegistry.getContext());
+ gameManagerService.onUserStarting(USER_ID_1);
+
+ gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD, USER_ID_2);
+ assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_2));
+ }
+
+ /**
+ * Test getter and setter of game modes.
+ */
+ @Test
+ public void testGameMode() {
+ GameManagerService gameManagerService =
+ new GameManagerService(InstrumentationRegistry.getContext());
+ gameManagerService.onUserStarting(USER_ID_1);
+
+ assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD, USER_ID_1);
+ assertEquals(GameManager.GAME_MODE_STANDARD,
+ gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_PERFORMANCE,
+ USER_ID_1);
+ assertEquals(GameManager.GAME_MODE_PERFORMANCE,
+ gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/JobCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index e5529cb899cc..15a9bcf59b28 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -16,36 +16,42 @@
package com.android.server.job;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+
import static com.google.common.truth.Truth.assertThat;
import android.util.Log;
+import android.util.Pair;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
-import com.android.server.job.JobConcurrencyManager.JobCountTracker;
+import com.android.server.job.JobConcurrencyManager.WorkCountTracker;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
import java.util.Random;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
/**
- * Test for {@link com.android.server.job.JobConcurrencyManager.JobCountTracker}.
+ * Test for {@link WorkCountTracker}.
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
-public class JobCountTrackerTest {
- private static final String TAG = "JobCountTrackerTest";
+public class WorkCountTrackerTest {
+ private static final String TAG = "WorkerCountTrackerTest";
private Random mRandom;
- private JobCountTracker mJobCountTracker;
+ private WorkCountTracker mWorkCountTracker;
@Before
public void setUp() {
mRandom = new Random(1); // Always use the same series of pseudo random values.
- mJobCountTracker = new JobCountTracker();
+ mWorkCountTracker = new WorkCountTracker();
}
/**
@@ -83,44 +89,57 @@ public class JobCountTrackerTest {
private void startPendingJobs(Jobs jobs, int totalMax, int maxBg, int minBg) {
- mJobCountTracker.reset(totalMax, maxBg, minBg);
+ mWorkCountTracker.setConfig(new JobConcurrencyManager.WorkTypeConfig("critical",
+ totalMax,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, totalMax - maxBg),
+ Pair.create(WORK_TYPE_BG, minBg)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, maxBg))));
+ mWorkCountTracker.resetCounts();
for (int i = 0; i < jobs.runningFg; i++) {
- mJobCountTracker.incrementRunningJobCount(true);
+ mWorkCountTracker.incrementRunningJobCount(WORK_TYPE_TOP);
}
for (int i = 0; i < jobs.runningBg; i++) {
- mJobCountTracker.incrementRunningJobCount(false);
+ mWorkCountTracker.incrementRunningJobCount(WORK_TYPE_BG);
}
for (int i = 0; i < jobs.pendingFg; i++) {
- mJobCountTracker.incrementPendingJobCount(true);
+ mWorkCountTracker.incrementPendingJobCount(WORK_TYPE_TOP);
}
for (int i = 0; i < jobs.pendingBg; i++) {
- mJobCountTracker.incrementPendingJobCount(false);
+ mWorkCountTracker.incrementPendingJobCount(WORK_TYPE_BG);
}
- mJobCountTracker.onCountDone();
+ mWorkCountTracker.onCountDone();
- while ((jobs.pendingFg > 0 && mJobCountTracker.canJobStart(true))
- || (jobs.pendingBg > 0 && mJobCountTracker.canJobStart(false))) {
+ while ((jobs.pendingFg > 0
+ && mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE)
+ || (jobs.pendingBg > 0
+ && mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE)) {
final boolean isStartingFg = mRandom.nextBoolean();
if (isStartingFg) {
- if (jobs.pendingFg > 0 && mJobCountTracker.canJobStart(true)) {
+ if (jobs.pendingFg > 0
+ && mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE) {
jobs.pendingFg--;
jobs.runningFg++;
- mJobCountTracker.onStartingNewJob(true);
+ mWorkCountTracker.stageJob(WORK_TYPE_TOP);
+ mWorkCountTracker.onJobStarted(WORK_TYPE_TOP);
}
} else {
- if (jobs.pendingBg > 0 && mJobCountTracker.canJobStart(false)) {
+ if (jobs.pendingBg > 0
+ && mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE) {
jobs.pendingBg--;
jobs.runningBg++;
- mJobCountTracker.onStartingNewJob(false);
+ mWorkCountTracker.stageJob(WORK_TYPE_BG);
+ mWorkCountTracker.onJobStarted(WORK_TYPE_BG);
}
}
}
- Log.i(TAG, "" + mJobCountTracker);
+ Log.i(TAG, "" + mWorkCountTracker);
}
/**
@@ -277,6 +296,7 @@ public class JobCountTrackerTest {
startPendingJobs(jobs, totalMax, maxBg, minBg);
+// fail(mWorkerCountTracker.toString());
assertThat(jobs.runningFg).isEqualTo(resultRunningFg);
assertThat(jobs.runningBg).isEqualTo(resultRunningBg);
@@ -300,6 +320,8 @@ public class JobCountTrackerTest {
checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 1, /*res run/pen=*/ 5, 1, 5, 0);
checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 3, /*res run/pen=*/ 4, 2, 6, 1);
+ checkSimple(8, 6, 2, /*run=*/ 0, 0, /*pen=*/ 0, 49, /*res run/pen=*/ 0, 6, 0, 43);
+
checkSimple(6, 4, 2, /*run=*/ 6, 0, /*pen=*/ 10, 3, /*res run/pen=*/ 6, 0, 10, 3);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
index 4c3674767e97..fba36cb402a0 100644
--- a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
@@ -15,22 +15,34 @@
*/
package com.android.server.job;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+
import android.annotation.Nullable;
import android.provider.DeviceConfig;
+import android.util.Pair;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.job.JobSchedulerService.MaxJobCounts;
+import com.android.server.job.JobConcurrencyManager.WorkTypeConfig;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class MaxJobCountsTest {
+public class WorkTypeConfigTest {
+ private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
+ private static final String KEY_MAX_TOP = "concurrency_max_top_test";
+ private static final String KEY_MAX_BG = "concurrency_max_bg_test";
+ private static final String KEY_MIN_TOP = "concurrency_min_top_test";
+ private static final String KEY_MIN_BG = "concurrency_min_bg_test";
+
@After
public void tearDown() throws Exception {
resetConfig();
@@ -38,9 +50,11 @@ public class MaxJobCountsTest {
private void resetConfig() {
// DeviceConfig.resetToDefaults() doesn't work here. Need to reset constants manually.
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "total", "", false);
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "maxbg", "", false);
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "minbg", "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, "", false);
}
private void check(@Nullable DeviceConfig.Properties config,
@@ -51,16 +65,19 @@ public class MaxJobCountsTest {
DeviceConfig.setProperties(config);
}
- final MaxJobCounts counts = new JobSchedulerService.MaxJobCounts(
- defaultTotal, "total",
- defaultMaxBg, "maxbg",
- defaultMinBg, "minbg");
+ final WorkTypeConfig counts = new WorkTypeConfig("test",
+ defaultTotal,
+ // defaultMin
+ List.of(Pair.create(WORK_TYPE_TOP, defaultTotal - defaultMaxBg),
+ Pair.create(WORK_TYPE_BG, defaultMinBg)),
+ // defaultMax
+ List.of(Pair.create(WORK_TYPE_BG, defaultMaxBg)));
- counts.update();
+ counts.update(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
Assert.assertEquals(expectedTotal, counts.getMaxTotal());
- Assert.assertEquals(expectedMaxBg, counts.getMaxBg());
- Assert.assertEquals(expectedMinBg, counts.getMinBg());
+ Assert.assertEquals(expectedMaxBg, counts.getMax(WORK_TYPE_BG));
+ Assert.assertEquals(expectedMinBg, counts.getMinReserved(WORK_TYPE_BG));
}
@Test
@@ -80,19 +97,19 @@ public class MaxJobCountsTest {
// Test for overriding with a setting string.
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
- .setInt("total", 5)
- .setInt("maxbg", 4)
- .setInt("minbg", 3)
+ .setInt(KEY_MAX_TOTAL, 5)
+ .setInt(KEY_MAX_BG, 4)
+ .setInt(KEY_MIN_BG, 3)
.build(),
/*default*/ 9, 9, 9, /*expected*/ 5, 4, 3);
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
- .setInt("total", 5).build(),
+ .setInt(KEY_MAX_TOTAL, 5).build(),
/*default*/ 9, 9, 9, /*expected*/ 5, 5, 4);
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
- .setInt("maxbg", 4).build(),
+ .setInt(KEY_MAX_BG, 4).build(),
/*default*/ 9, 9, 9, /*expected*/ 9, 4, 4);
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
- .setInt("minbg", 3).build(),
+ .setInt(KEY_MIN_BG, 3).build(),
/*default*/ 9, 9, 9, /*expected*/ 9, 9, 3);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 63330d518297..161d3163c1cf 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -515,6 +515,85 @@ public final class DataManagerTest {
}
@Test
+ public void testGetConversationReturnsCustomizedConversation() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+ }
+
+ @Test
+ public void testGetConversation() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNull();
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID + "1")).isNull();
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+ assertThat(result).isNotNull();
+ assertEquals(shortcut.getId(), result.getShortcutInfo().getId());
+ assertEquals(1, result.getShortcutInfo().getPersons().length);
+ assertEquals(CONTACT_URI, result.getShortcutInfo().getPersons()[0].getUri());
+ assertEquals(mParentNotificationChannel.getId(),
+ result.getParentNotificationChannel().getId());
+ assertEquals(mStatusBarNotification.getPostTime(), result.getLastEventTimestamp());
+ assertTrue(result.hasActiveNotifications());
+ }
+
+ @Test
+ public void testGetConversationGetsPersonsData() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+
+ verify(mShortcutServiceInternal).getShortcuts(
+ anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+ mQueryFlagsCaptor.capture(), anyInt(), anyInt(), anyInt());
+ Integer queryFlags = mQueryFlagsCaptor.getValue();
+ assertThat(hasFlag(queryFlags, ShortcutQuery.FLAG_GET_PERSONS_DATA)).isTrue();
+ }
+
+ @Test
public void testNotificationChannelCreated() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
mDataManager.onUserUnlocked(USER_ID_SECONDARY);
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 533dc1708896..1d0b595d8fc1 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -877,6 +877,22 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testQuiescentBoot_WakeKeyBeforeBootCompleted_AwakeAfterBootCompleted()
+ throws Exception {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
+ createService();
+ mService.systemReady(null);
+
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
+
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ DisplayPowerRequest.POLICY_BRIGHT);
+ }
+
+ @Test
public void testIsAmbientDisplayAvailable_available() throws Exception {
createService();
when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
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 78dd4b8119e3..4bea9a2eea45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -27,7 +27,6 @@ import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
-import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -96,6 +95,7 @@ import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.metrics.LogMaker;
@@ -707,6 +707,7 @@ public class DisplayContentTests extends WindowTestsBase {
// same width and height.
final int displayWidth = dc.mInitialDisplayWidth;
final int displayHeight = dc.mInitialDisplayHeight;
+ final float density = dc.mInitialDisplayDensity;
final int cutoutWidth = 40;
final int cutoutHeight = 10;
final int left = (displayWidth - cutoutWidth) / 2;
@@ -714,9 +715,13 @@ public class DisplayContentTests extends WindowTestsBase {
final int right = (displayWidth + cutoutWidth) / 2;
final int bottom = cutoutHeight;
- final Rect r1 = new Rect(left, top, right, bottom);
+ final Rect zeroRect = new Rect();
+ final Rect[] bounds = new Rect[]{zeroRect, new Rect(left, top, right, bottom), zeroRect,
+ zeroRect};
+ final DisplayCutout.CutoutPathParserInfo info = new DisplayCutout.CutoutPathParserInfo(
+ displayWidth, displayHeight, density, "", Surface.ROTATION_0, 1f);
final DisplayCutout cutout = new WmDisplayCutout(
- fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
+ DisplayCutout.constructDisplayCutout(bounds, Insets.NONE, info), null)
.computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
dc.mInitialDisplayCutout = cutout;
@@ -731,9 +736,12 @@ public class DisplayContentTests extends WindowTestsBase {
// | | ---o
// | | |
// | | -------------
- final Rect r = new Rect(top, left, bottom, right);
+ final Rect[] bounds90 = new Rect[]{new Rect(top, left, bottom, right), zeroRect, zeroRect,
+ zeroRect};
+ final DisplayCutout.CutoutPathParserInfo info90 = new DisplayCutout.CutoutPathParserInfo(
+ displayWidth, displayHeight, density, "", Surface.ROTATION_90, 1f);
assertEquals(new WmDisplayCutout(
- fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
+ DisplayCutout.constructDisplayCutout(bounds90, Insets.NONE, info90), null)
.computeSafeInsets(displayHeight, displayWidth).getDisplayCutout(),
dc.getDisplayInfo().displayCutout);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 70d47a580801..8703c3103607 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -16,11 +16,13 @@
package com.android.server.wm;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.DragEvent.ACTION_DRAG_STARTED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -34,6 +36,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import android.app.PendingIntent;
@@ -278,6 +281,8 @@ public class DragDropControllerTests extends WindowTestsBase {
@Test
public void testValidateAppShortcutArguments() {
+ doReturn(PERMISSION_GRANTED).when(mWm.mContext)
+ .checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS));
final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {}
@@ -329,6 +334,8 @@ public class DragDropControllerTests extends WindowTestsBase {
@Test
public void testValidateAppTaskArguments() {
+ doReturn(PERMISSION_GRANTED).when(mWm.mContext)
+ .checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS));
final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {}
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 673b00f25824..21fd04ee3ae9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -45,7 +45,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -58,7 +57,6 @@ import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
-import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.os.Bundle;
@@ -1109,28 +1107,6 @@ public class RecentTasksTest extends WindowTestsBase {
assertEquals(originalStackCount, mTaskContainer.getRootTaskCount());
}
- @Test
- public void testNotRecentsComponent_denyApiAccess() throws Exception {
- doReturn(PackageManager.PERMISSION_DENIED).when(mAtm)
- .checkGetTasksPermission(anyString(), anyInt(), anyInt());
- // Expect the following methods to fail due to recents component not being set
- mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
- doTestRecentTasksApis(false /* expectNoSecurityException */);
- // Don't throw for the following tests
- mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY);
- testGetTasksApis(false /* expectNoSecurityException */);
- }
-
- @Test
- public void testRecentsComponent_allowApiAccessWithoutPermissions() {
- doReturn(PackageManager.PERMISSION_DENIED).when(mAtm)
- .checkGetTasksPermission(anyString(), anyInt(), anyInt());
- // Set the recents component and ensure that the following calls do not fail
- mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
- doTestRecentTasksApis(true /* expectNoSecurityException */);
- testGetTasksApis(true /* expectNoSecurityException */);
- }
-
private void doTestRecentTasksApis(boolean expectCallable) {
assertSecurityException(expectCallable, () -> mAtm.removeTask(INVALID_STACK_ID));
assertSecurityException(expectCallable,
@@ -1295,13 +1271,7 @@ public class RecentTasksTest extends WindowTestsBase {
}
private static class TestRecentTasks extends RecentTasks {
- static final int GRANT = 0;
- static final int DENY = 1;
- static final int DENY_THROW_SECURITY_EXCEPTION = 2;
-
- private boolean mOverrideIsCallerRecents;
private boolean mIsTrimmableOverride;
- private int mIsCallerRecentsPolicy;
public boolean mLastAllowed;
@@ -1334,26 +1304,6 @@ public class RecentTasksTest extends WindowTestsBase {
return new int[] { TEST_USER_0_ID, TEST_QUIET_USER_ID };
}
- @Override
- boolean isCallerRecents(int callingUid) {
- if (mOverrideIsCallerRecents) {
- switch (mIsCallerRecentsPolicy) {
- case GRANT:
- return true;
- case DENY:
- return false;
- case DENY_THROW_SECURITY_EXCEPTION:
- throw new SecurityException();
- }
- }
- return super.isCallerRecents(callingUid);
- }
-
- void setIsCallerRecentsOverride(int policy) {
- mOverrideIsCallerRecents = true;
- mIsCallerRecentsPolicy = policy;
- }
-
/**
* To simplify the setup for some tests, the caller can request that we only rely on the
* visible range test to determine what is trimmable. In this case, we don't try to
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index b0b8afd6c3a4..df5b48a038f3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -22,6 +22,8 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
@@ -978,6 +980,31 @@ public class WindowContainerTests extends WindowTestsBase {
assertEquals(200, listener.mConfiguration.densityDpi);
}
+ @Test
+ public void testFreezeInsetsStateWhenAppTransition() {
+ final Task stack = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTaskInStack(stack, 0 /* userId */);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
+ task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE);
+ spyOn(win);
+ doReturn(true).when(task).okToAnimate();
+ ArrayList<WindowContainer> sources = new ArrayList<>();
+ sources.add(activity);
+
+ // Simulate the task applying the exit transition, verify the main window of the task
+ // will be set the frozen insets state.
+ task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
+ false /* isVoiceInteraction */, sources);
+ verify(win).freezeInsetsState();
+
+ // Simulate the task transition finished, verify the frozen insets state of the window
+ // will be reset.
+ task.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION,
+ task.mSurfaceAnimator.getAnimation());
+ verify(win).clearFrozenInsetsState();
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 263aa194a108..3231f8b6551a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -810,4 +810,27 @@ public class WindowStateTests extends WindowTestsBase {
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
}
+
+ @Test
+ public void testSetFreezeInsetsState() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ spyOn(app);
+ doReturn(true).when(app).isVisible();
+
+ // Set freezing the insets state to make the window ignore to dispatch insets changed.
+ final InsetsState expectedState = new InsetsState(app.getInsetsState(),
+ true /* copySources */);
+ app.freezeInsetsState();
+ assertEquals(expectedState, app.getFrozenInsetsState());
+ assertFalse(app.isReadyToDispatchInsetsState());
+ assertEquals(expectedState, app.getInsetsState());
+ mDisplayContent.getInsetsStateController().notifyInsetsChanged();
+ verify(app, never()).notifyInsetsChanged();
+
+ // Unfreeze the insets state to make the window can dispatch insets changed.
+ app.clearFrozenInsetsState();
+ assertTrue(app.isReadyToDispatchInsetsState());
+ mDisplayContent.getInsetsStateController().notifyInsetsChanged();
+ verify(app).notifyInsetsChanged();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
index 39976a5a2af1..b2646f281eb9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
@@ -150,9 +150,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_waterfall() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT},
- Insets.of(1, 2, 3, 4)),
+ Insets.of(1, 2, 3, 4), null),
200, 400);
assertEquals(new Rect(1, 2, 3, 4), cutout.getDisplayCutout().getSafeInsets());
@@ -161,9 +161,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutTop_greaterThan_waterfallTop() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
- Insets.of(0, 20, 0, 0)),
+ Insets.of(0, 20, 0, 0), null),
200, 400);
assertEquals(new Rect(0, 30, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -172,9 +172,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutTop_lessThan_waterfallTop() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
- Insets.of(0, 40, 0, 0)),
+ Insets.of(0, 40, 0, 0), null),
200, 400);
assertEquals(new Rect(0, 40, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -183,9 +183,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutLeft_greaterThan_waterfallLeft() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
- Insets.of(20, 0, 0, 0)),
+ Insets.of(20, 0, 0, 0), null),
200, 400);
assertEquals(new Rect(30, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -194,9 +194,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutLeft_lessThan_waterfallLeft() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
- Insets.of(40, 0, 0, 0)),
+ Insets.of(40, 0, 0, 0), null),
200, 400);
assertEquals(new Rect(40, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -205,9 +205,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutBottom_greaterThan_waterfallBottom() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
- Insets.of(0, 0, 0, 20)),
+ Insets.of(0, 0, 0, 20), null),
200, 400);
assertEquals(new Rect(0, 0, 0, 30), cutout.getDisplayCutout().getSafeInsets());
@@ -216,9 +216,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutBottom_lessThan_waterfallBottom() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
- Insets.of(0, 0, 0, 40)),
+ Insets.of(0, 0, 0, 40), null),
200, 400);
assertEquals(new Rect(0, 0, 0, 40), cutout.getDisplayCutout().getSafeInsets());
@@ -227,9 +227,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutRight_greaterThan_waterfallRight() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
- Insets.of(0, 0, 20, 0)),
+ Insets.of(0, 0, 20, 0), null),
200, 400);
assertEquals(new Rect(0, 0, 30, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -238,9 +238,9 @@ public class WmDisplayCutoutTest {
@Test
public void computeSafeInsets_cutoutRight_lessThan_waterfallRight() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
- Insets.of(0, 0, 40, 0)),
+ Insets.of(0, 0, 40, 0), null),
200, 400);
assertEquals(new Rect(0, 0, 40, 0), cutout.getDisplayCutout().getSafeInsets());
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index a4f5249c9cb4..339249b33db6 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -1026,6 +1026,8 @@ public class UsageStatsDatabase {
writeLocked(fos, stats, version, packagesTokenData);
file.finishWrite(fos);
fos = null;
+ } catch (Exception e) {
+ // Do nothing. Exception has already been handled.
} finally {
// When fos is null (successful write), this will no-op
file.failWrite(fos);
@@ -1033,7 +1035,7 @@ public class UsageStatsDatabase {
}
private static void writeLocked(OutputStream out, IntervalStats stats, int version,
- PackagesTokenData packagesTokenData) throws RuntimeException {
+ PackagesTokenData packagesTokenData) throws Exception {
switch (version) {
case 1:
case 2:
@@ -1045,6 +1047,7 @@ public class UsageStatsDatabase {
UsageStatsProto.write(out, stats);
} catch (Exception e) {
Slog.e(TAG, "Unable to write interval stats to proto.", e);
+ throw e;
}
break;
case 5:
@@ -1053,6 +1056,7 @@ public class UsageStatsDatabase {
UsageStatsProtoV2.write(out, stats);
} catch (Exception e) {
Slog.e(TAG, "Unable to write interval stats to proto.", e);
+ throw e;
}
break;
default:
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index baa0576cdf13..754814facb71 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -178,4 +178,11 @@ public class ImsUtListener {
public ImsUtListener(IImsUtListener serviceInterface) {
mServiceInterface = serviceInterface;
}
+
+ /**
+ * @hide
+ */
+ public IImsUtListener getListenerInterface() {
+ return mServiceInterface;
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 06c35eaec6dd..2e35d27614d1 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -23,6 +23,8 @@ import android.util.Log;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsEcbmListener;
+import java.util.Objects;
+
/**
* Base implementation of ImsEcbm, which implements stub versions of the methods
* in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
@@ -36,11 +38,27 @@ import com.android.ims.internal.IImsEcbmListener;
public class ImsEcbmImplBase {
private static final String TAG = "ImsEcbmImplBase";
+ private final Object mLock = new Object();
private IImsEcbmListener mListener;
- private IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
+ private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
@Override
public void setListener(IImsEcbmListener listener) {
- mListener = listener;
+ synchronized (mLock) {
+ if (mImsEcbm != null && listener != null && Objects.equals(
+ mImsEcbm.asBinder(), listener.asBinder())) {
+ return;
+ }
+ if (listener == null) {
+ mListener = null;
+ } else if (listener != null && mListener == null) {
+ mListener = listener;
+ } else {
+ // Fail fast here instead of silently overwriting the listener to another
+ // listener due to another connection connecting.
+ throw new IllegalStateException("ImsEcbmImplBase: Listener already set by "
+ + "another connection.");
+ }
+ }
}
@Override
@@ -69,9 +87,13 @@ public class ImsEcbmImplBase {
*/
public final void enteredEcbm() {
Log.d(TAG, "Entered ECBM.");
- if (mListener != null) {
+ IImsEcbmListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
try {
- mListener.enteredECBM();
+ listener.enteredECBM();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -85,9 +107,13 @@ public class ImsEcbmImplBase {
*/
public final void exitedEcbm() {
Log.d(TAG, "Exited ECBM.");
- if (mListener != null) {
+ IImsEcbmListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
try {
- mListener.exitedECBM();
+ listener.exitedECBM();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index d002903a11b6..555a47eb8200 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -25,6 +25,7 @@ import com.android.ims.internal.IImsExternalCallStateListener;
import com.android.ims.internal.IImsMultiEndpoint;
import java.util.List;
+import java.util.Objects;
/**
* Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
@@ -41,10 +42,28 @@ public class ImsMultiEndpointImplBase {
private static final String TAG = "MultiEndpointImplBase";
private IImsExternalCallStateListener mListener;
- private IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+ private final Object mLock = new Object();
+ private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+
@Override
public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
- mListener = listener;
+ synchronized (mLock) {
+ if (mListener != null && listener != null && Objects.equals(
+ mListener.asBinder(), listener.asBinder())) {
+ return;
+ }
+
+ if (listener == null) {
+ mListener = null;
+ } else if (listener != null && mListener == null) {
+ mListener = listener;
+ } else {
+ // Fail fast here instead of silently overwriting the listener to another
+ // listener due to another connection connecting.
+ throw new IllegalStateException("ImsMultiEndpointImplBase: Listener already"
+ + " set by another connection.");
+ }
+ }
}
@Override
@@ -65,9 +84,13 @@ public class ImsMultiEndpointImplBase {
*/
public final void onImsExternalCallStateUpdate(List<ImsExternalCallState> externalCallDialogs) {
Log.d(TAG, "ims external call state update triggered.");
- if (mListener != null) {
+ IImsExternalCallStateListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
try {
- mListener.onImsExternalCallStateUpdate(externalCallDialogs);
+ listener.onImsExternalCallStateUpdate(externalCallDialogs);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index f5219d5b49e8..eef4fcaceeaf 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -29,6 +29,7 @@ import com.android.ims.internal.IImsUtListener;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Base implementation of IMS UT interface, which implements stubs. Override these methods to
@@ -116,7 +117,10 @@ public class ImsUtImplBase {
*/
public static final int INVALID_RESULT = -1;
- private IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+ private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+ private final Object mLock = new Object();
+ private ImsUtListener mUtListener;
+
@Override
public void close() throws RemoteException {
ImsUtImplBase.this.close();
@@ -202,7 +206,26 @@ public class ImsUtImplBase {
@Override
public void setListener(IImsUtListener listener) throws RemoteException {
- ImsUtImplBase.this.setListener(new ImsUtListener(listener));
+ synchronized (mLock) {
+ if (mUtListener != null && listener != null && Objects.equals(
+ mUtListener.getListenerInterface().asBinder(), listener.asBinder())) {
+ return;
+ }
+
+ if (listener == null) {
+ mUtListener = null;
+ } else if (listener != null && mUtListener == null) {
+ mUtListener = new ImsUtListener(listener);
+ } else {
+ // This is a limitation of the current API surface, there can only be one
+ // listener connected. Fail fast instead of silently overwriting the other
+ // listener.
+ throw new IllegalStateException("ImsUtImplBase#setListener: listener already "
+ + "set by another connected interface!");
+ }
+ }
+
+ ImsUtImplBase.this.setListener(mUtListener);
}
@Override
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 59e375fa3bd6..f474ec2c389c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -114,7 +114,8 @@ class CloseImeWindowToHomeTest(
enabled = !configuration.startRotation.isRotated())
navBarLayerIsAlwaysVisible()
statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+ visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE),
+ enabled = false)
imeLayerBecomesInvisible()
imeAppLayerBecomesInvisible(testApp)
diff --git a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
new file mode 100644
index 000000000000..87cfb345e5e0
--- /dev/null
+++ b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 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.net
+
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+private const val TEST_OWNER_UID = 123
+private const val TEST_IFACE = "test_tun0"
+private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+class UnderlyingNetworkInfoTest {
+ @Test
+ fun testParcelUnparcel() {
+ val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
+ assertEquals(TEST_OWNER_UID, testInfo.ownerUid)
+ assertEquals(TEST_IFACE, testInfo.iface)
+ assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces)
+ assertParcelSane(testInfo, 3)
+
+ val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
+ assertEquals(0, emptyInfo.ownerUid)
+ assertEquals(String(), emptyInfo.iface)
+ assertEquals(listOf(), emptyInfo.underlyingIfaces)
+ assertParcelSane(emptyInfo, 3)
+ }
+} \ No newline at end of file
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index f2dd27effe91..c2fddf3d9e82 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -32,6 +32,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
@@ -368,6 +369,12 @@ public class ConnectivityManagerTest {
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
eq(testPkgName), eq(null));
reset(mService);
+
+ manager.requestBackgroundNetwork(request, null, callback);
+ verify(mService).requestNetwork(eq(request.networkCapabilities),
+ eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(testPkgName), eq(null));
+ reset(mService);
}
static Message makeMessage(NetworkRequest req, int messageType) {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 137543a8147c..14229c5d000f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -201,8 +201,8 @@ import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
-import android.net.VpnInfo;
import android.net.VpnManager;
import android.net.metrics.IpConnectivityLog;
import android.net.shared.NetworkMonitorUtils;
@@ -1076,7 +1076,7 @@ public class ConnectivityServiceTest {
private boolean mAgentRegistered = false;
private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
- private VpnInfo mVpnInfo;
+ private UnderlyingNetworkInfo mUnderlyingNetworkInfo;
// These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
// TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
@@ -1250,14 +1250,15 @@ public class ConnectivityServiceTest {
}
@Override
- public synchronized VpnInfo getVpnInfo() {
- if (mVpnInfo != null) return mVpnInfo;
+ public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
+ if (mUnderlyingNetworkInfo != null) return mUnderlyingNetworkInfo;
- return super.getVpnInfo();
+ return super.getUnderlyingNetworkInfo();
}
- private synchronized void setVpnInfo(VpnInfo vpnInfo) {
- mVpnInfo = vpnInfo;
+ private synchronized void setUnderlyingNetworkInfo(
+ UnderlyingNetworkInfo underlyingNetworkInfo) {
+ mUnderlyingNetworkInfo = underlyingNetworkInfo;
}
}
@@ -3693,10 +3694,13 @@ public class ConnectivityServiceTest {
@Test
public void testBackgroundNetworks() throws Exception {
- // Create a background request. We can't do this ourselves because ConnectivityService
- // doesn't have an API for it. So just turn on mobile data always on.
- setAlwaysOnNetworks(true);
+ // Create a cellular background request.
grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
+ final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
+ mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build(), null, cellBgCallback);
+
+ // Make callbacks for monitoring.
final NetworkRequest request = new NetworkRequest.Builder().build();
final NetworkRequest fgRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_FOREGROUND).build();
@@ -3765,6 +3769,7 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(fgCallback);
+ mCm.unregisterNetworkCallback(cellBgCallback);
}
@Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
@@ -5195,20 +5200,22 @@ public class ConnectivityServiceTest {
private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
- ArgumentCaptor<VpnInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(VpnInfo[].class);
+ ArgumentCaptor<UnderlyingNetworkInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(
+ UnderlyingNetworkInfo[].class);
verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
- VpnInfo[] infos = vpnInfosCaptor.getValue();
+ UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue();
if (vpnUid != null) {
assertEquals("Should have exactly one VPN:", 1, infos.length);
- VpnInfo info = infos[0];
+ UnderlyingNetworkInfo info = infos[0];
assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid);
- assertEquals("Unexpected VPN interface:", vpnIfname, info.vpnIface);
- assertSameElementsNoDuplicates(underlyingIfaces, info.underlyingIfaces);
+ assertEquals("Unexpected VPN interface:", vpnIfname, info.iface);
+ assertSameElementsNoDuplicates(underlyingIfaces,
+ info.underlyingIfaces.toArray(new String[0]));
} else {
assertEquals(0, infos.length);
return;
@@ -5269,7 +5276,7 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mStatsService, never())
.forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
- eq(new VpnInfo[0]));
+ eq(new UnderlyingNetworkInfo[0]));
reset(mStatsService);
// Roaming change should update ifaces
@@ -5352,8 +5359,8 @@ public class ConnectivityServiceTest {
// network for the VPN...
verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
any(NetworkState[].class), any() /* anyString() doesn't match null */,
- argThat(infos -> infos[0].underlyingIfaces.length == 1
- && WIFI_IFNAME.equals(infos[0].underlyingIfaces[0])));
+ argThat(infos -> infos[0].underlyingIfaces.size() == 1
+ && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
verifyNoMoreInteractions(mStatsService);
reset(mStatsService);
@@ -5366,8 +5373,8 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mStatsService).forceUpdateIfaces(any(Network[].class),
any(NetworkState[].class), any() /* anyString() doesn't match null */,
- argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
- && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
+ argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
+ && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
mEthernetNetworkAgent.disconnect();
waitForIdle();
reset(mStatsService);
@@ -8347,8 +8354,9 @@ public class ConnectivityServiceTest {
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
mMockVpn.setVpnType(vpnType);
- final VpnInfo vpnInfo = new VpnInfo(vpnOwnerUid, null, null);
- mMockVpn.setVpnInfo(vpnInfo);
+ final UnderlyingNetworkInfo underlyingNetworkInfo =
+ new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
+ mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
}
private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
index 1b33930e96a9..a058a466a4ff 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
@@ -33,7 +33,9 @@ import static android.net.NetworkStats.TAG_NONE;
import static org.junit.Assert.assertEquals;
import android.net.NetworkStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
+
+import java.util.Arrays;
/** Superclass with utilities for NetworkStats(Service|Factory)Test */
abstract class NetworkStatsBaseTest {
@@ -107,11 +109,11 @@ abstract class NetworkStatsBaseTest {
assertEquals("unexpected operations", operations, entry.operations);
}
- static VpnInfo createVpnInfo(String[] underlyingIfaces) {
+ static UnderlyingNetworkInfo createVpnInfo(String[] underlyingIfaces) {
return createVpnInfo(TUN_IFACE, underlyingIfaces);
}
- static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
- return new VpnInfo(UID_VPN, vpnIface, underlyingIfaces);
+ static UnderlyingNetworkInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
+ return new UnderlyingNetworkInfo(UID_VPN, vpnIface, Arrays.asList(underlyingIfaces));
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index 76647a69de33..f3ae9b051e7c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -36,7 +36,7 @@ import static org.junit.Assert.fail;
import android.content.res.Resources;
import android.net.NetworkStats;
import android.net.TrafficStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -79,7 +79,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// related to networkStatsFactory is compiled to a minimal native library and loaded here.
System.loadLibrary("networkstatsfactorytestjni");
mFactory = new NetworkStatsFactory(mTestProc, false);
- mFactory.updateVpnInfos(new VpnInfo[0]);
+ mFactory.updateUnderlyingNetworkInfos(new UnderlyingNetworkInfo[0]);
}
@After
@@ -105,8 +105,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnRewriteTrafficThroughItself() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -134,8 +135,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithClat() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
+ createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
@@ -167,8 +169,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIface() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -191,8 +194,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -219,8 +223,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -242,8 +247,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is duplicating traffic across both WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -267,10 +273,10 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
public void testConcurrentVpns() throws Exception {
// Assume two VPNs are connected on two different network interfaces. VPN1 is using
// TEST_IFACE and VPN2 is using TEST_IFACE2.
- final VpnInfo[] vpnInfos = new VpnInfo[] {
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -308,8 +314,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -335,8 +342,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface:
// 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
@@ -357,8 +365,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
public void testVpnWithIncorrectUnderlyingIface() throws Exception {
// WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
// but has declared only WiFi (TEST_IFACE) in its underlying network set.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index b4e37de2267f..dde78aa54199 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -86,7 +86,7 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.ConditionVariable;
import android.os.Handler;
@@ -286,7 +286,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -328,7 +329,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -401,7 +403,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -441,7 +444,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -475,7 +479,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
forcePollAndWaitForIdle();
@@ -514,7 +519,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -581,7 +587,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
- new VpnInfo[0]);
+ new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -655,7 +661,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -713,7 +720,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
NetworkStats.Entry entry1 = new NetworkStats.Entry(
TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
@@ -756,7 +764,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
NetworkStats.Entry uidStats = new NetworkStats.Entry(
TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
@@ -810,7 +819,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -867,7 +877,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -906,7 +917,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -943,7 +955,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -999,7 +1012,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -1104,7 +1118,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
mService.registerNetworkStatsProvider("TEST", provider);
assertNotNull(cb);
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Verifies that one requestStatsUpdate will be called during iface update.
provider.expectOnRequestStatsUpdate(0 /* unused */);
@@ -1155,7 +1170,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
NetworkState[] states =
new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Register custom provider and retrieve callback.
final TestableNetworkStatsProviderBinder provider =
@@ -1204,7 +1220,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// 3G network comes online.
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
- new VpnInfo[0]);
+ new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -1274,7 +1290,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
NetworkState[] states = new NetworkState[]{
buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Create some traffic on mobile network.
incrementCurrentTime(HOUR_IN_MILLIS);
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 9c6b7194af35..f9db408462b7 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -18,14 +18,19 @@ package android.net.vcn;
import static androidx.test.InstrumentationRegistry.getContext;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
import org.junit.Before;
@@ -103,4 +108,28 @@ public class VcnManagerTest {
public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() {
mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null);
}
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy() throws Exception {
+ NetworkCapabilities nc = new NetworkCapabilities();
+ LinkProperties lp = new LinkProperties();
+ when(mMockVcnManagementService.getUnderlyingNetworkPolicy(eq(nc), eq(lp)))
+ .thenReturn(new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, nc));
+
+ VcnUnderlyingNetworkPolicy policy = mVcnManager.getUnderlyingNetworkPolicy(nc, lp);
+
+ assertFalse(policy.isTeardownRequested());
+ assertEquals(nc, policy.getMergedNetworkCapabilities());
+ verify(mMockVcnManagementService).getUnderlyingNetworkPolicy(eq(nc), eq(lp));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetUnderlyingNetworkPolicyNullNetworkCapabilities() throws Exception {
+ mVcnManager.getUnderlyingNetworkPolicy(null, new LinkProperties());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception {
+ mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null);
+ }
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index f0cdde33f822..e26bf19488d0 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -21,6 +21,8 @@ import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubsc
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -41,9 +43,12 @@ import static org.mockito.Mockito.verify;
import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnConfigTest;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
@@ -63,6 +68,7 @@ import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -192,6 +198,14 @@ public class VcnManagementServiceTest {
mTestLooper.dispatchAll();
}
+ @Before
+ public void setUp() {
+ doNothing()
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
+ }
+
private void setupMockedCarrierPrivilege(boolean isPrivileged) {
doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
.when(mSubMgr)
@@ -455,10 +469,6 @@ public class VcnManagementServiceTest {
@Test
public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
- doNothing()
- .when(mMockContext)
- .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
-
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
verify(mMockIBinder).linkToDeath(any(), anyInt());
@@ -468,17 +478,14 @@ public class VcnManagementServiceTest {
public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
doThrow(new SecurityException())
.when(mMockContext)
- .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
@Test
public void testRemoveVcnUnderlyingNetworkPolicyListener() {
- // verify listener added
- doNothing()
- .when(mMockContext)
- .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
@@ -488,4 +495,24 @@ public class VcnManagementServiceTest {
public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy() throws Exception {
+ VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ new NetworkCapabilities(), new LinkProperties());
+
+ assertFalse(policy.isTeardownRequested());
+ assertNotNull(policy.getMergedNetworkCapabilities());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testGetUnderlyingNetworkPolicyInvalidPermission() {
+ doThrow(new SecurityException())
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
+ }
}