summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp3
-rw-r--r--Android.mk33
-rw-r--r--api/current.txt39
-rw-r--r--api/system-current.txt133
-rw-r--r--api/test-current.txt12
-rw-r--r--cmds/incident_helper/src/ih_util.cpp75
-rw-r--r--cmds/incident_helper/src/ih_util.h11
-rw-r--r--cmds/incident_helper/src/main.cpp6
-rw-r--r--cmds/incident_helper/src/parsers/BatteryTypeParser.cpp60
-rw-r--r--cmds/incident_helper/src/parsers/BatteryTypeParser.h36
-rw-r--r--cmds/incident_helper/src/parsers/CpuInfoParser.cpp29
-rw-r--r--cmds/incident_helper/src/parsers/KernelWakesParser.cpp6
-rw-r--r--cmds/incident_helper/src/parsers/PsParser.cpp95
-rw-r--r--cmds/incident_helper/src/parsers/PsParser.h (renamed from core/java/android/service/autofill/Scorer.java)23
-rw-r--r--cmds/incident_helper/testdata/batterytype.txt1
-rw-r--r--cmds/incident_helper/testdata/ps.txt9
-rw-r--r--cmds/incident_helper/tests/BatteryTypeParser_test.cpp66
-rw-r--r--cmds/incident_helper/tests/PsParser_test.cpp300
-rw-r--r--cmds/incident_helper/tests/ih_util_test.cpp24
-rw-r--r--cmds/incidentd/Android.mk2
-rw-r--r--cmds/incidentd/src/Section.cpp2
-rw-r--r--cmds/statsd/src/HashableDimensionKey.cpp8
-rw-r--r--cmds/statsd/src/HashableDimensionKey.h1
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp15
-rw-r--r--cmds/statsd/src/StatsService.cpp23
-rw-r--r--cmds/statsd/src/StatsService.h10
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.cpp77
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.h14
-rw-r--r--cmds/statsd/src/atoms.proto8
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp30
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h4
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h14
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp40
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h6
-rw-r--r--cmds/statsd/src/config/ConfigKey.cpp17
-rw-r--r--cmds/statsd/src/config/ConfigKey.h16
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp149
-rw-r--r--cmds/statsd/src/dimension.cpp17
-rw-r--r--cmds/statsd/src/dimension.h2
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp49
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h24
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp12
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.h4
-rw-r--r--cmds/statsd/src/matchers/LogMatchingTracker.h12
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp10
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.h4
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp30
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp32
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp13
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp25
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp12
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h10
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp52
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h7
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp50
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h4
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h6
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp13
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp13
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp129
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h23
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp73
-rw-r--r--cmds/statsd/src/packages/UidMap.h2
-rw-r--r--cmds/statsd/src/stats_log.proto14
-rw-r--r--cmds/statsd/src/stats_util.h2
-rw-r--r--cmds/statsd/src/statsd_config.proto104
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp5
-rw-r--r--cmds/statsd/tests/ConfigManager_test.cpp73
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp140
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp8
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp9
-rw-r--r--cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp6
-rw-r--r--cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp73
-rw-r--r--cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp12
-rw-r--r--cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp6
-rw-r--r--cmds/statsd/tests/guardrail/StatsdStats_test.cpp70
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp29
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp6
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp19
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp19
-rw-r--r--cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp41
-rw-r--r--cmds/statsd/tests/metrics/OringDurationTracker_test.cpp54
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp33
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp45
-rw-r--r--cmds/statsd/tests/statsd_test_util.h2
-rw-r--r--cmds/statsd/tools/dogfood/Android.mk3
-rw-r--r--cmds/statsd/tools/dogfood/res/raw/statsd_baseline_configbin2416 -> 4785 bytes
-rw-r--r--cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java4
-rw-r--r--cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java5
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java22
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java4
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java6
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java16
-rw-r--r--core/java/android/app/ActivityManager.java20
-rw-r--r--core/java/android/app/ActivityManagerNative.java6
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/IActivityManager.aidl7
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java74
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/assist/AssistStructure.java26
-rw-r--r--core/java/android/app/servertransaction/ClientTransaction.java5
-rw-r--r--core/java/android/app/servertransaction/ObjectPool.java22
-rw-r--r--core/java/android/app/slice/Slice.java4
-rw-r--r--core/java/android/content/pm/PackageList.java74
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java51
-rw-r--r--core/java/android/hardware/display/BrightnessChangeEvent.java12
-rw-r--r--core/java/android/hardware/display/DisplayManager.java7
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java12
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java8
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl4
-rw-r--r--core/java/android/hardware/location/ContextHubClient.java41
-rw-r--r--core/java/android/hardware/location/ContextHubClientCallback.java36
-rw-r--r--core/java/android/hardware/location/ContextHubInfo.java12
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java159
-rw-r--r--core/java/android/hardware/location/ContextHubTransaction.java45
-rw-r--r--core/java/android/hardware/location/NanoAppBinary.java2
-rw-r--r--core/java/android/hardware/location/NanoAppInstanceInfo.java5
-rw-r--r--core/java/android/hardware/location/NanoAppMessage.java2
-rw-r--r--core/java/android/hardware/location/NanoAppState.java2
-rw-r--r--core/java/android/hardware/radio/RadioManager.java17
-rw-r--r--core/java/android/net/NetworkWatchlistManager.java18
-rw-r--r--core/java/android/os/BatteryStats.java92
-rw-r--r--core/java/android/os/Handler.java28
-rw-r--r--core/java/android/os/IStatsManager.aidl6
-rw-r--r--core/java/android/os/UserManager.java3
-rw-r--r--core/java/android/os/storage/StorageManager.java6
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java2
-rw-r--r--core/java/android/service/autofill/EditDistanceScorer.java67
-rw-r--r--core/java/android/service/autofill/FieldClassification.aidl19
-rw-r--r--core/java/android/service/autofill/FieldClassification.java33
-rw-r--r--core/java/android/service/autofill/InternalScorer.java40
-rw-r--r--core/java/android/service/autofill/UserData.aidl1
-rw-r--r--core/java/android/service/autofill/UserData.java69
-rw-r--r--core/java/android/service/euicc/EuiccService.java26
-rw-r--r--core/java/android/service/euicc/IEuiccService.aidl2
-rw-r--r--core/java/android/service/euicc/IGetOtaStatusCallback.aidl22
-rw-r--r--core/java/android/text/format/Formatter.java268
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/util/StatsManager.java6
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java839
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java558
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java95
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java663
-rw-r--r--core/java/android/util/apk/VerbatimX509Certificate.java38
-rw-r--r--core/java/android/util/apk/WrappedX509Certificate.java175
-rw-r--r--core/java/android/util/jar/StrictJarVerifier.java29
-rw-r--r--core/java/android/view/DisplayCutout.java13
-rw-r--r--core/java/android/view/View.java125
-rw-r--r--core/java/android/view/ViewGroup.java15
-rw-r--r--core/java/android/view/ViewStructure.java12
-rw-r--r--core/java/android/view/WindowManager.java54
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java370
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java59
-rw-r--r--core/java/android/view/autofill/AutofillManager.java48
-rw-r--r--core/java/android/view/autofill/IAutoFillManager.aidl2
-rw-r--r--core/java/android/widget/EditText.java5
-rw-r--r--core/java/android/widget/Magnifier.java2
-rw-r--r--core/java/android/widget/TextView.java30
-rw-r--r--core/java/com/android/internal/net/INetworkWatchlistManager.aidl1
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java125
-rw-r--r--core/java/com/android/internal/widget/ButtonBarLayout.java9
-rw-r--r--core/proto/android/graphics/pixelformat.proto34
-rw-r--r--core/proto/android/os/batterystats.proto41
-rw-r--r--core/proto/android/os/batterytype.proto25
-rw-r--r--core/proto/android/os/cpuinfo.proto4
-rw-r--r--core/proto/android/os/incident.proto16
-rw-r--r--core/proto/android/os/ps.proto110
-rw-r--r--core/proto/android/server/windowmanagerservice.proto31
-rw-r--r--core/proto/android/view/display.proto12
-rw-r--r--core/proto/android/view/displaycutout.proto27
-rw-r--r--core/proto/android/view/windowlayoutparams.proto42
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/values/attrs.xml7
-rw-r--r--core/res/res/values/colors_device_defaults.xml2
-rw-r--r--core/res/res/values/colors_material.xml4
-rw-r--r--core/res/res/values/config.xml43
-rw-r--r--core/res/res/values/strings.xml20
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java3
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java3
-rw-r--r--core/tests/coretests/src/android/text/format/FormatterTest.java21
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java68
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java206
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java11
-rw-r--r--graphics/java/android/graphics/Typeface.java2
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl3
-rw-r--r--keystore/java/android/security/keystore/AttestationUtils.java89
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp12
-rw-r--r--libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp8
-rw-r--r--libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp1
-rw-r--r--libs/hwui/tests/common/scenes/ListViewAnimation.cpp1
-rw-r--r--libs/hwui/tests/common/scenes/MagnifierAnimation.cpp1
-rw-r--r--libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp13
-rw-r--r--libs/hwui/tests/common/scenes/TextAnimation.cpp1
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp1
-rw-r--r--libs/hwui/tests/unit/FrameBuilderTests.cpp4
-rw-r--r--libs/hwui/tests/unit/RecordingCanvasTests.cpp11
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp1
-rw-r--r--libs/hwui/tests/unit/TextDropShadowCacheTests.cpp1
-rw-r--r--media/java/android/media/AudioFocusInfo.java2
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java18
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java21
-rw-r--r--packages/SystemUI/Android.mk7
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml19
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml17
-rw-r--r--packages/SystemUI/res-keyguard/values-h560dp/dimens.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-h650dp/dimens.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml19
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml14
-rw-r--r--packages/SystemUI/res/layout/pip_menu_activity.xml28
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java265
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java231
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java13
-rw-r--r--packages/SystemUI/tests/Android.mk7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java20
-rw-r--r--proto/src/metrics_constants.proto30
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java154
-rw-r--r--services/accessibility/java/com/android/server/accessibility/GestureUtils.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java27
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java30
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java124
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java18
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerConstants.java5
-rw-r--r--services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java2
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java37
-rw-r--r--services/core/java/com/android/server/EntropyMixer.java7
-rw-r--r--services/core/java/com/android/server/IpSecService.java7
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java45
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java31
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java124
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java9
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java17
-rw-r--r--services/core/java/com/android/server/am/ClientLifecycleManager.java9
-rw-r--r--services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java6
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java14
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/Convert.java72
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/Mutable.java46
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java53
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java66
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java137
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/Utils.java40
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java1
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java88
-rw-r--r--services/core/java/com/android/server/display/BrightnessTracker.java167
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java33
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java185
-rw-r--r--services/core/java/com/android/server/location/ContextHubServiceUtil.java2
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java5
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java2
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java23
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java1
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java1
-rw-r--r--services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java37
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java9
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistSettings.java211
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java79
-rw-r--r--services/core/java/com/android/server/pm/Settings.java2
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java43
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java87
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java15
-rw-r--r--services/core/java/com/android/server/updates/NetworkWatchlistInstallReceiver.java40
-rw-r--r--services/core/java/com/android/server/wm/AppWindowThumbnail.java7
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java39
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java62
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackWindowController.java4
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java46
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimationSpec.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java27
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java81
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java124
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java11
-rw-r--r--services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java80
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java185
-rw-r--r--services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java182
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java35
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java132
-rw-r--r--services/tests/servicestests/src/com/android/server/testutils/TestHandler.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java1
-rw-r--r--telephony/java/android/provider/Telephony.java (renamed from telephony/java/android/telephony/Telephony.java)0
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java54
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java3
-rw-r--r--telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl1
-rw-r--r--tests/DexLoggerIntegrationTests/Android.mk49
-rw-r--r--tests/DexLoggerIntegrationTests/AndroidManifest.xml35
-rw-r--r--tests/DexLoggerIntegrationTests/AndroidTest.xml29
-rw-r--r--tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java22
-rw-r--r--tests/DexLoggerIntegrationTests/src/com/android/server/pm/DexLoggerIntegrationTests.java151
-rw-r--r--tools/incident_section_gen/main.cpp58
-rw-r--r--tools/sdkparcelables/Android.bp22
-rw-r--r--tools/sdkparcelables/manifest.txt1
-rw-r--r--tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt28
-rw-r--r--tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt56
-rw-r--r--tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt52
-rw-r--r--tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt57
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java30
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareManager.java12
-rw-r--r--wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java56
-rw-r--r--wifi/java/android/net/wifi/rtt/ResponderConfig.java50
-rw-r--r--wifi/java/android/net/wifi/rtt/WifiRttManager.java4
-rw-r--r--wifi/tests/src/android/net/wifi/WifiScannerTest.java50
323 files changed, 9696 insertions, 4069 deletions
diff --git a/Android.bp b/Android.bp
index 2dcbc92974a9..69ee848cadad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -256,6 +256,7 @@ java_library {
"core/java/android/service/euicc/IGetEidCallback.aidl",
"core/java/android/service/euicc/IGetEuiccInfoCallback.aidl",
"core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl",
+ "core/java/android/service/euicc/IGetOtaStatusCallback.aidl",
"core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl",
"core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl",
"core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
@@ -721,11 +722,13 @@ gensrcs {
],
srcs: [
+ "core/proto/android/os/batterytype.proto",
"core/proto/android/os/cpufreq.proto",
"core/proto/android/os/cpuinfo.proto",
"core/proto/android/os/kernelwake.proto",
"core/proto/android/os/pagetypeinfo.proto",
"core/proto/android/os/procrank.proto",
+ "core/proto/android/os/ps.proto",
"core/proto/android/os/system_properties.proto",
],
diff --git a/Android.mk b/Android.mk
index a19f2d90d9bb..0e363d2491c8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -252,12 +252,26 @@ aidl_files := \
system/netd/server/binder/android/net/UidRange.aidl \
frameworks/base/telephony/java/android/telephony/PcoData.aidl \
+aidl_parcelables :=
+define stubs-to-aidl-parcelables
+ gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/$1.aidl
+ aidl_parcelables += $$(gen)
+ $$(gen): $(call java-lib-header-files,$1) | $(HOST_OUT_EXECUTABLES)/sdkparcelables
+ @echo Extract SDK parcelables: $$@
+ rm -f $$@
+ $(HOST_OUT_EXECUTABLES)/sdkparcelables $$< $$@
+endef
+
+$(foreach stubs,android_stubs_current android_test_stubs_current android_system_stubs_current,\
+ $(eval $(call stubs-to-aidl-parcelables,$(stubs))))
+
gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
-$(gen): PRIVATE_SRC_FILES := $(aidl_files)
-ALL_SDK_FILES += $(gen)
-$(gen): $(aidl_files) | $(AIDL)
- @echo Aidl Preprocess: $@
- $(hide) $(AIDL) --preprocess $@ $(PRIVATE_SRC_FILES)
+.KATI_RESTAT: $(gen)
+$(gen): $(aidl_parcelables)
+ @echo Combining SDK parcelables: $@
+ rm -f $@.tmp
+ cat $^ | sort -u > $@.tmp
+ $(call commit-change-for-toc,$@)
# the documentation
# ============================================================
@@ -554,8 +568,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(gen)
$(INTERNAL_PLATFORM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
@@ -591,8 +603,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(gen)
$(INTERNAL_PLATFORM_SYSTEM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
@@ -629,8 +639,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(gen)
$(INTERNAL_PLATFORM_TEST_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
@@ -660,9 +668,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
-$(full_target): $(gen)
-
# Run this for checkbuild
checkbuild: doc-comment-check-docs
# Check comment when you are updating the API
diff --git a/api/current.txt b/api/current.txt
index 104a7d967575..c57cf32992b1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6338,7 +6338,7 @@ package android.app.admin {
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
- method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec);
+ method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec, int);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public java.util.Set<java.lang.String> getAffiliationIds(android.content.ComponentName);
@@ -6572,6 +6572,10 @@ package android.app.admin {
field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
+ field public static final int ID_TYPE_BASE_INFO = 1; // 0x1
+ field public static final int ID_TYPE_IMEI = 4; // 0x4
+ field public static final int ID_TYPE_MEID = 8; // 0x8
+ field public static final int ID_TYPE_SERIAL = 2; // 0x2
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
field public static final int KEYGUARD_DISABLE_FINGERPRINT = 32; // 0x20
@@ -6749,6 +6753,7 @@ package android.app.assist {
method public java.lang.CharSequence getText();
method public int getTextBackgroundColor();
method public int getTextColor();
+ method public java.lang.String getTextIdEntry();
method public int[] getTextLineBaselines();
method public int[] getTextLineCharOffsets();
method public int getTextSelectionEnd();
@@ -7042,6 +7047,7 @@ package android.app.slice {
field public static final java.lang.String HINT_SUMMARY = "summary";
field public static final java.lang.String HINT_TITLE = "title";
field public static final java.lang.String SUBTYPE_COLOR = "color";
+ field public static final java.lang.String SUBTYPE_CONTENT_DESCRIPTION = "content_description";
field public static final java.lang.String SUBTYPE_MESSAGE = "message";
field public static final java.lang.String SUBTYPE_PRIORITY = "priority";
field public static final java.lang.String SUBTYPE_SLIDER = "slider";
@@ -31571,6 +31577,7 @@ package android.os {
method public final boolean postAtTime(java.lang.Runnable, long);
method public final boolean postAtTime(java.lang.Runnable, java.lang.Object, long);
method public final boolean postDelayed(java.lang.Runnable, long);
+ method public final boolean postDelayed(java.lang.Runnable, java.lang.Object, long);
method public final void removeCallbacks(java.lang.Runnable);
method public final void removeCallbacks(java.lang.Runnable, java.lang.Object);
method public final void removeCallbacksAndMessages(java.lang.Object);
@@ -37723,18 +37730,12 @@ package android.service.autofill {
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews);
}
- public final class EditDistanceScorer implements android.os.Parcelable android.service.autofill.Scorer {
- method public int describeContents();
- method public static android.service.autofill.EditDistanceScorer getInstance();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.service.autofill.EditDistanceScorer> CREATOR;
- }
-
public final class FieldClassification {
method public java.util.List<android.service.autofill.FieldClassification.Match> getMatches();
}
public static final class FieldClassification.Match {
+ method public java.lang.String getAlgorithm();
method public java.lang.String getRemoteId();
method public float getScore();
}
@@ -37886,9 +37887,6 @@ package android.service.autofill {
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
- public abstract interface Scorer {
- }
-
public final class TextValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
ctor public TextValueSanitizer(java.util.regex.Pattern, java.lang.String);
method public int describeContents();
@@ -37901,6 +37899,7 @@ package android.service.autofill {
public final class UserData implements android.os.Parcelable {
method public int describeContents();
+ method public java.lang.String getFieldClassificationAlgorithm();
method public static int getMaxFieldClassificationIdsSize();
method public static int getMaxUserDataSize();
method public static int getMaxValueLength();
@@ -37910,9 +37909,10 @@ package android.service.autofill {
}
public static final class UserData.Builder {
- ctor public UserData.Builder(android.service.autofill.Scorer, java.lang.String, java.lang.String);
+ ctor public UserData.Builder(java.lang.String, java.lang.String);
method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String);
method public android.service.autofill.UserData build();
+ method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithm(java.lang.String, android.os.Bundle);
}
public abstract interface Validator {
@@ -47258,6 +47258,7 @@ package android.view {
method public abstract void setSelected(boolean);
method public abstract void setText(java.lang.CharSequence);
method public abstract void setText(java.lang.CharSequence, int, int);
+ method public void setTextIdEntry(java.lang.String);
method public abstract void setTextLines(int[], int[]);
method public abstract void setTextStyle(float, int, int, int);
method public abstract void setTransformation(android.graphics.Matrix);
@@ -47777,6 +47778,7 @@ package android.view.accessibility {
method public java.lang.CharSequence getPackageName();
method public android.view.accessibility.AccessibilityRecord getRecord(int);
method public int getRecordCount();
+ method public int getWindowChanges();
method public void initFromParcel(android.os.Parcel);
method public static android.view.accessibility.AccessibilityEvent obtain(int);
method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
@@ -47821,6 +47823,17 @@ package android.view.accessibility {
field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
field public static final int TYPE_WINDOW_STATE_CHANGED = 32; // 0x20
+ field public static final int WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED = 128; // 0x80
+ field public static final int WINDOWS_CHANGE_ACTIVE = 32; // 0x20
+ field public static final int WINDOWS_CHANGE_ADDED = 1; // 0x1
+ field public static final int WINDOWS_CHANGE_BOUNDS = 8; // 0x8
+ field public static final int WINDOWS_CHANGE_CHILDREN = 512; // 0x200
+ field public static final int WINDOWS_CHANGE_FOCUSED = 64; // 0x40
+ field public static final int WINDOWS_CHANGE_LAYER = 16; // 0x10
+ field public static final int WINDOWS_CHANGE_PARENT = 256; // 0x100
+ field public static final int WINDOWS_CHANGE_PIP = 1024; // 0x400
+ field public static final int WINDOWS_CHANGE_REMOVED = 2; // 0x2
+ field public static final int WINDOWS_CHANGE_TITLE = 4; // 0x4
}
public abstract interface AccessibilityEventSource {
@@ -48532,6 +48545,8 @@ package android.view.autofill {
method public void commit();
method public void disableAutofillServices();
method public android.content.ComponentName getAutofillServiceComponentName();
+ method public java.util.List<java.lang.String> getAvailableFieldClassificationAlgorithms();
+ method public java.lang.String getDefaultFieldClassificationAlgorithm();
method public android.service.autofill.UserData getUserData();
method public boolean hasEnabledAutofillServices();
method public boolean isAutofillSupported();
diff --git a/api/system-current.txt b/api/system-current.txt
index 3e781670c784..596474c2f59f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1340,9 +1340,30 @@ package android.hardware.hdmi {
package android.hardware.location {
+ public class ContextHubClient implements java.io.Closeable {
+ method public void close();
+ method public android.hardware.location.ContextHubInfo getAttachedHub();
+ method public int sendMessageToNanoApp(android.hardware.location.NanoAppMessage);
+ }
+
+ public class ContextHubClientCallback {
+ ctor public ContextHubClientCallback();
+ method public void onHubReset(android.hardware.location.ContextHubClient);
+ method public void onMessageFromNanoApp(android.hardware.location.ContextHubClient, android.hardware.location.NanoAppMessage);
+ method public void onNanoAppAborted(android.hardware.location.ContextHubClient, long, int);
+ method public void onNanoAppDisabled(android.hardware.location.ContextHubClient, long);
+ method public void onNanoAppEnabled(android.hardware.location.ContextHubClient, long);
+ method public void onNanoAppLoaded(android.hardware.location.ContextHubClient, long);
+ method public void onNanoAppUnloaded(android.hardware.location.ContextHubClient, long);
+ }
+
public class ContextHubInfo implements android.os.Parcelable {
ctor public ContextHubInfo();
method public int describeContents();
+ method public byte getChreApiMajorVersion();
+ method public byte getChreApiMinorVersion();
+ method public short getChrePatchVersion();
+ method public long getChrePlatformId();
method public int getId();
method public int getMaxPacketLengthBytes();
method public android.hardware.location.MemoryRegion[] getMemoryRegions();
@@ -1362,19 +1383,27 @@ package android.hardware.location {
}
public final class ContextHubManager {
- method public int[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
- method public int[] getContextHubHandles();
- method public android.hardware.location.ContextHubInfo getContextHubInfo(int);
- method public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
- method public int loadNanoApp(int, android.hardware.location.NanoApp);
- method public int registerCallback(android.hardware.location.ContextHubManager.Callback);
- method public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
- method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
- method public int unloadNanoApp(int);
- method public int unregisterCallback(android.hardware.location.ContextHubManager.Callback);
- }
-
- public static abstract class ContextHubManager.Callback {
+ method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.hardware.location.ContextHubClientCallback, java.util.concurrent.Executor);
+ method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.hardware.location.ContextHubClientCallback);
+ method public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(android.hardware.location.ContextHubInfo, long);
+ method public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(android.hardware.location.ContextHubInfo, long);
+ method public deprecated int[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
+ method public deprecated int[] getContextHubHandles();
+ method public deprecated android.hardware.location.ContextHubInfo getContextHubInfo(int);
+ method public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
+ method public deprecated android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+ method public deprecated int loadNanoApp(int, android.hardware.location.NanoApp);
+ method public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(android.hardware.location.ContextHubInfo, android.hardware.location.NanoAppBinary);
+ method public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(android.hardware.location.ContextHubInfo);
+ method public deprecated int registerCallback(android.hardware.location.ContextHubManager.Callback);
+ method public deprecated int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
+ method public deprecated int sendMessage(int, int, android.hardware.location.ContextHubMessage);
+ method public deprecated int unloadNanoApp(int);
+ method public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(android.hardware.location.ContextHubInfo, long);
+ method public deprecated int unregisterCallback(android.hardware.location.ContextHubManager.Callback);
+ }
+
+ public static abstract deprecated class ContextHubManager.Callback {
ctor protected ContextHubManager.Callback();
method public abstract void onMessageReceipt(int, int, android.hardware.location.ContextHubMessage);
}
@@ -1392,6 +1421,37 @@ package android.hardware.location {
field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
}
+ public class ContextHubTransaction<T> {
+ method public int getType();
+ method public void setOnCompleteListener(android.hardware.location.ContextHubTransaction.OnCompleteListener<T>, java.util.concurrent.Executor);
+ method public void setOnCompleteListener(android.hardware.location.ContextHubTransaction.OnCompleteListener<T>);
+ method public static java.lang.String typeToString(int, boolean);
+ method public android.hardware.location.ContextHubTransaction.Response<T> waitForResponse(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+ field public static final int RESULT_FAILED_AT_HUB = 5; // 0x5
+ field public static final int RESULT_FAILED_BAD_PARAMS = 2; // 0x2
+ field public static final int RESULT_FAILED_BUSY = 4; // 0x4
+ field public static final int RESULT_FAILED_HAL_UNAVAILABLE = 8; // 0x8
+ field public static final int RESULT_FAILED_SERVICE_INTERNAL_FAILURE = 7; // 0x7
+ field public static final int RESULT_FAILED_TIMEOUT = 6; // 0x6
+ field public static final int RESULT_FAILED_UNINITIALIZED = 3; // 0x3
+ field public static final int RESULT_FAILED_UNKNOWN = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 0; // 0x0
+ field public static final int TYPE_DISABLE_NANOAPP = 3; // 0x3
+ field public static final int TYPE_ENABLE_NANOAPP = 2; // 0x2
+ field public static final int TYPE_LOAD_NANOAPP = 0; // 0x0
+ field public static final int TYPE_QUERY_NANOAPPS = 4; // 0x4
+ field public static final int TYPE_UNLOAD_NANOAPP = 1; // 0x1
+ }
+
+ public static abstract interface ContextHubTransaction.OnCompleteListener<L> {
+ method public abstract void onComplete(android.hardware.location.ContextHubTransaction<L>, android.hardware.location.ContextHubTransaction.Response<L>);
+ }
+
+ public static class ContextHubTransaction.Response<R> {
+ method public R getContents();
+ method public int getResult();
+ }
+
public final class GeofenceHardware {
method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
method public int[] getMonitoringTypes();
@@ -1508,6 +1568,25 @@ package android.hardware.location {
field public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
}
+ public final class NanoAppBinary implements android.os.Parcelable {
+ ctor public NanoAppBinary(byte[]);
+ method public int describeContents();
+ method public byte[] getBinary();
+ method public byte[] getBinaryNoHeader();
+ method public int getFlags();
+ method public int getHeaderVersion();
+ method public long getHwHubType();
+ method public long getNanoAppId();
+ method public int getNanoAppVersion();
+ method public byte getTargetChreApiMajorVersion();
+ method public byte getTargetChreApiMinorVersion();
+ method public boolean hasValidHeader();
+ method public boolean isEncrypted();
+ method public boolean isSigned();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppBinary> CREATOR;
+ }
+
public class NanoAppFilter {
ctor public NanoAppFilter(long, int, int, long);
method public int describeContents();
@@ -1541,6 +1620,28 @@ package android.hardware.location {
field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
}
+ public final class NanoAppMessage implements android.os.Parcelable {
+ method public static android.hardware.location.NanoAppMessage createMessageFromNanoApp(long, int, byte[], boolean);
+ method public static android.hardware.location.NanoAppMessage createMessageToNanoApp(long, int, byte[]);
+ method public int describeContents();
+ method public byte[] getMessageBody();
+ method public int getMessageType();
+ method public long getNanoAppId();
+ method public boolean isBroadcastMessage();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppMessage> CREATOR;
+ }
+
+ public final class NanoAppState implements android.os.Parcelable {
+ ctor public NanoAppState(long, int, boolean);
+ method public int describeContents();
+ method public long getNanoAppId();
+ method public long getNanoAppVersion();
+ method public boolean isEnabled();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppState> CREATOR;
+ }
+
}
package android.hardware.radio {
@@ -4368,10 +4469,10 @@ package android.util {
}
public final class StatsManager {
- method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
- method public byte[] getData(java.lang.String);
+ method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
+ method public byte[] getData(long);
method public byte[] getMetadata();
- method public boolean removeConfiguration(java.lang.String);
+ method public boolean removeConfiguration(long);
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index d56b0856c028..008832c09dcf 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -435,6 +435,10 @@ package android.provider {
field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
}
+ public static final class Settings.Global extends android.provider.Settings.NameValueTable {
+ field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
+ }
+
public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
@@ -473,7 +477,8 @@ package android.service.autofill {
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
}
- public final class EditDistanceScorer extends android.service.autofill.InternalScorer implements android.os.Parcelable android.service.autofill.Scorer {
+ public final class EditDistanceScorer {
+ method public static android.service.autofill.EditDistanceScorer getInstance();
method public float getScore(android.view.autofill.AutofillValue, java.lang.String);
}
@@ -489,11 +494,6 @@ package android.service.autofill {
ctor public InternalSanitizer();
}
- public abstract class InternalScorer implements android.os.Parcelable android.service.autofill.Scorer {
- ctor public InternalScorer();
- method public abstract float getScore(android.view.autofill.AutofillValue, java.lang.String);
- }
-
public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
ctor public InternalTransformation();
}
diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
index 4bf956a9a03d..e23e80ae21e8 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -52,6 +52,12 @@ static inline std::string trimHeader(const std::string& s) {
return toLowerStr(trimDefault(s));
}
+static inline bool isNumber(const std::string& s) {
+ std::string::const_iterator it = s.begin();
+ while (it != s.end() && std::isdigit(*it)) ++it;
+ return !s.empty() && it == s.end();
+}
+
// This is similiar to Split in android-base/file.h, but it won't add empty string
static void split(const std::string& line, std::vector<std::string>& words,
const trans_func& func, const std::string& delimiters) {
@@ -86,24 +92,80 @@ record_t parseRecord(const std::string& line, const std::string& delimiters) {
return record;
}
+bool getColumnIndices(std::vector<int>& indices, const char** headerNames, const std::string& line) {
+ indices.clear();
+
+ size_t lastIndex = 0;
+ int i = 0;
+ while (headerNames[i] != NULL) {
+ string s = headerNames[i];
+ lastIndex = line.find(s, lastIndex);
+ if (lastIndex == string::npos) {
+ fprintf(stderr, "Bad Task Header: %s\n", line.c_str());
+ return false;
+ }
+ lastIndex += s.length();
+ indices.push_back(lastIndex);
+ i++;
+ }
+
+ return true;
+}
+
record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters) {
record_t record;
int lastIndex = 0;
+ int lastBeginning = 0;
int lineSize = (int)line.size();
for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) {
int idx = *it;
- if (lastIndex > idx || idx > lineSize) {
- record.clear(); // The indices is wrong, return empty;
+ if (idx <= lastIndex) {
+ // We saved up until lastIndex last time, so we should start at
+ // lastIndex + 1 this time.
+ idx = lastIndex + 1;
+ }
+ if (idx > lineSize) {
+ if (lastIndex < idx && lastIndex < lineSize) {
+ // There's a little bit more for us to save, which we'll do
+ // outside of the loop.
+ break;
+ }
+ // If we're past the end of the line AND we've already saved everything up to the end.
+ fprintf(stderr, "index wrong: lastIndex: %d, idx: %d, lineSize: %d\n", lastIndex, idx, lineSize);
+ record.clear(); // The indices are wrong, return empty.
return record;
}
while (idx < lineSize && delimiters.find(line[idx++]) == std::string::npos);
record.push_back(trimDefault(line.substr(lastIndex, idx - lastIndex)));
+ lastBeginning = lastIndex;
lastIndex = idx;
}
- record.push_back(trimDefault(line.substr(lastIndex, lineSize - lastIndex)));
+ if (lineSize - lastIndex > 0) {
+ int beginning = lastIndex;
+ if (record.size() == indices.size()) {
+ // We've already encountered all of the columns...put whatever is
+ // left in the last column.
+ record.pop_back();
+ beginning = lastBeginning;
+ }
+ record.push_back(trimDefault(line.substr(beginning, lineSize - beginning)));
+ }
return record;
}
+void printRecord(const record_t& record) {
+ fprintf(stderr, "Record: { ");
+ if (record.size() == 0) {
+ fprintf(stderr, "}\n");
+ return;
+ }
+ for(size_t i = 0; i < record.size(); ++i) {
+ if(i != 0) fprintf(stderr, "\", ");
+ fprintf(stderr, "\"%s", record[i].c_str());
+ }
+ fprintf(stderr, "\" }\n");
+}
+
bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter) {
const auto head = line->find_first_not_of(DEFAULT_WHITESPACE);
if (head == std::string::npos) return false;
@@ -210,7 +272,10 @@ Table::~Table()
void
Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize)
{
- if (mFields.find(field) == mFields.end()) return;
+ if (mFields.find(field) == mFields.end()) {
+ fprintf(stderr, "Field '%s' not found", string(field).c_str());
+ return;
+ }
map<std::string, int> enu;
for (int i = 0; i < enumSize; i++) {
@@ -268,6 +333,8 @@ Table::insertField(ProtoOutputStream* proto, const std::string& name, const std:
}
} else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) {
proto->write(found, mEnumValuesByName[value]);
+ } else if (isNumber(value)) {
+ proto->write(found, toInt(value));
} else {
return false;
}
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index 58ef29044048..b063b2fe0bba 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -56,12 +56,23 @@ header_t parseHeader(const std::string& line, const std::string& delimiters = DE
record_t parseRecord(const std::string& line, const std::string& delimiters = DEFAULT_WHITESPACE);
/**
+ * Gets the list of end indices of each word in the line and places it in the given vector,
+ * clearing out the vector beforehand. These indices can be used with parseRecordByColumns.
+ * Will return false if there was a problem getting the indices. headerNames
+ * must be NULL terminated.
+ */
+bool getColumnIndices(std::vector<int>& indices, const char* headerNames[], const std::string& line);
+
+/**
* When a text-format table aligns by its vertical position, it is not possible to split them by purely delimiters.
* This function allows to parse record by its header's column position' indices, must in ascending order.
* At the same time, it still looks at the char at index, if it doesn't belong to delimiters, moves forward to find the delimiters.
*/
record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters = DEFAULT_WHITESPACE);
+/** Prints record_t to stderr */
+void printRecord(const record_t& record);
+
/**
* When the line starts/ends with the given key, the function returns true
* as well as the line argument is changed to the rest trimmed part of the original.
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index c8a0883d493c..8c6cd78d3bf2 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -16,11 +16,13 @@
#define LOG_TAG "incident_helper"
+#include "parsers/BatteryTypeParser.h"
#include "parsers/CpuFreqParser.h"
#include "parsers/CpuInfoParser.h"
#include "parsers/KernelWakesParser.h"
#include "parsers/PageTypeInfoParser.h"
#include "parsers/ProcrankParser.h"
+#include "parsers/PsParser.h"
#include "parsers/SystemPropertiesParser.h"
#include <android-base/file.h>
@@ -63,6 +65,10 @@ static TextParserBase* selectParser(int section) {
return new CpuInfoParser();
case 2004:
return new CpuFreqParser();
+ case 2005:
+ return new PsParser();
+ case 2006:
+ return new BatteryTypeParser();
default:
return NULL;
}
diff --git a/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp b/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
new file mode 100644
index 000000000000..ced6cf807e0d
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 LOG_TAG "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/batterytype.proto.h"
+#include "ih_util.h"
+#include "BatteryTypeParser.h"
+
+using namespace android::os;
+
+status_t
+BatteryTypeParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ string line;
+ bool readLine = false;
+
+ ProtoOutputStream proto;
+
+ // parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+
+ if (readLine) {
+ fprintf(stderr, "Multiple lines in file. Unsure what to do.\n");
+ break;
+ }
+
+ proto.write(BatteryTypeProto::TYPE, line);
+
+ readLine = true;
+ }
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
diff --git a/cmds/incident_helper/src/parsers/BatteryTypeParser.h b/cmds/incident_helper/src/parsers/BatteryTypeParser.h
new file mode 100644
index 000000000000..ac0c098965d3
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/BatteryTypeParser.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef BATTERY_TYPE_PARSER_H
+#define BATTERY_TYPE_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * Battery type parser, parses text in file
+ * /sys/class/power_supply/bms/battery_type.
+ */
+class BatteryTypeParser : public TextParserBase {
+public:
+ BatteryTypeParser() : TextParserBase(String8("BatteryTypeParser")) {};
+ ~BatteryTypeParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // BATTERY_TYPE_PARSER_H
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
index 3faca00c1b88..d73de54d8c5d 100644
--- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -49,6 +49,7 @@ CpuInfoParser::Parse(const int in, const int out) const
vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions.
record_t record;
int nline = 0;
+ int diff = 0;
bool nextToSwap = false;
bool nextToUsage = false;
@@ -107,18 +108,10 @@ CpuInfoParser::Parse(const int in, const int out) const
header = parseHeader(line, "[ %]");
nextToUsage = false;
- // NAME is not in the list since the last split index is default to the end of line.
- const char* headerNames[11] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD" };
- size_t lastIndex = 0;
- for (int i = 0; i < 11; i++) {
- string s = headerNames[i];
- lastIndex = line.find(s, lastIndex);
- if (lastIndex == string::npos) {
- fprintf(stderr, "Bad Task Header: %s\n", line.c_str());
- return -1;
- }
- lastIndex += s.length();
- columnIndices.push_back(lastIndex);
+ // NAME is not in the list since we need to modify the end of the CMD index.
+ const char* headerNames[] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD", NULL };
+ if (!getColumnIndices(columnIndices, headerNames, line)) {
+ return -1;
}
// Need to remove the end index of CMD and use the start index of NAME because CMD values contain spaces.
// for example: ... CMD NAME
@@ -128,12 +121,20 @@ CpuInfoParser::Parse(const int in, const int out) const
int endCMD = columnIndices.back();
columnIndices.pop_back();
columnIndices.push_back(line.find("NAME", endCMD) - 1);
+ // Add NAME index to complete the column list.
+ columnIndices.push_back(columnIndices.back() + 4);
continue;
}
record = parseRecordByColumns(line, columnIndices);
- if (record.size() != header.size()) {
- fprintf(stderr, "[%s]Line %d has missing fields:\n%s\n", this->name.string(), nline, line.c_str());
+ diff = record.size() - header.size();
+ if (diff < 0) {
+ fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str());
+ printRecord(record);
+ continue;
+ } else if (diff > 0) {
+ fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str());
+ printRecord(record);
continue;
}
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
index ada4a5d0ffe2..cae51abbe57f 100644
--- a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -47,10 +47,14 @@ KernelWakesParser::Parse(const int in, const int out) const
// parse for each record, the line delimiter is \t only!
record = parseRecord(line, TAB_DELIMITER);
- if (record.size() != header.size()) {
+ if (record.size() < header.size()) {
// TODO: log this to incident report!
fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline, line.c_str());
continue;
+ } else if (record.size() > header.size()) {
+ // TODO: log this to incident report!
+ fprintf(stderr, "[%s]Line %d has extra fields\n%s\n", this->name.string(), nline, line.c_str());
+ continue;
}
long long token = proto.start(KernelWakeSources::WAKEUP_SOURCES);
diff --git a/cmds/incident_helper/src/parsers/PsParser.cpp b/cmds/incident_helper/src/parsers/PsParser.cpp
new file mode 100644
index 000000000000..e9014cacfa0b
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/PsParser.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 LOG_TAG "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/ps.proto.h"
+#include "ih_util.h"
+#include "PsParser.h"
+
+using namespace android::os;
+
+status_t PsParser::Parse(const int in, const int out) const {
+ Reader reader(in);
+ string line;
+ header_t header; // the header of /d/wakeup_sources
+ vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions.
+ record_t record; // retain each record
+ int nline = 0;
+ int diff = 0;
+
+ ProtoOutputStream proto;
+ Table table(PsDumpProto::Process::_FIELD_NAMES, PsDumpProto::Process::_FIELD_IDS, PsDumpProto::Process::_FIELD_COUNT);
+ const char* pcyNames[] = { "fg", "bg", "ta" };
+ const int pcyValues[] = {PsDumpProto::Process::POLICY_FG, PsDumpProto::Process::POLICY_BG, PsDumpProto::Process::POLICY_TA};
+ table.addEnumTypeMap("pcy", pcyNames, pcyValues, 3);
+ const char* sNames[] = { "D", "R", "S", "T", "t", "X", "Z" };
+ const int sValues[] = {PsDumpProto::Process::STATE_D, PsDumpProto::Process::STATE_R, PsDumpProto::Process::STATE_S, PsDumpProto::Process::STATE_T, PsDumpProto::Process::STATE_TRACING, PsDumpProto::Process::STATE_X, PsDumpProto::Process::STATE_Z};
+ table.addEnumTypeMap("s", sNames, sValues, 7);
+
+ // Parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+
+ if (nline++ == 0) {
+ header = parseHeader(line, DEFAULT_WHITESPACE);
+
+ const char* headerNames[] = { "LABEL", "USER", "PID", "TID", "PPID", "VSZ", "RSS", "WCHAN", "ADDR", "S", "PRI", "NI", "RTPRIO", "SCH", "PCY", "TIME", "CMD", NULL };
+ if (!getColumnIndices(columnIndices, headerNames, line)) {
+ return -1;
+ }
+
+ continue;
+ }
+
+ record = parseRecordByColumns(line, columnIndices);
+
+ diff = record.size() - header.size();
+ if (diff < 0) {
+ // TODO: log this to incident report!
+ fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str());
+ printRecord(record);
+ continue;
+ } else if (diff > 0) {
+ // TODO: log this to incident report!
+ fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str());
+ printRecord(record);
+ continue;
+ }
+
+ long long token = proto.start(PsDumpProto::PROCESSES);
+ for (int i=0; i<(int)record.size(); i++) {
+ if (!table.insertField(&proto, header[i], record[i])) {
+ fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
+ this->name.string(), nline, header[i].c_str(), record[i].c_str());
+ }
+ }
+ proto.end(token);
+ }
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
diff --git a/core/java/android/service/autofill/Scorer.java b/cmds/incident_helper/src/parsers/PsParser.h
index c4018558b3ed..9488e40e88fe 100644
--- a/core/java/android/service/autofill/Scorer.java
+++ b/cmds/incident_helper/src/parsers/PsParser.h
@@ -13,16 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.autofill;
+
+#ifndef PS_PARSER_H
+#define PS_PARSER_H
+
+#include "TextParserBase.h"
/**
- * Helper class used to calculate a score.
- *
- * <p>Typically used to calculate the
- * <a href="AutofillService.html#FieldClassification">field classification</a> score between an
- * actual {@link android.view.autofill.AutofillValue} filled by the user and the expected value
- * predicted by an autofill service.
+ * PS parser, parses output of 'ps' command to protobuf.
*/
-public interface Scorer {
+class PsParser : public TextParserBase {
+public:
+ PsParser() : TextParserBase(String8("Ps")) {};
+ ~PsParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
-}
+#endif // PS_PARSER_H
diff --git a/cmds/incident_helper/testdata/batterytype.txt b/cmds/incident_helper/testdata/batterytype.txt
new file mode 100644
index 000000000000..c763d36ad811
--- /dev/null
+++ b/cmds/incident_helper/testdata/batterytype.txt
@@ -0,0 +1 @@
+random_battery_type_string
diff --git a/cmds/incident_helper/testdata/ps.txt b/cmds/incident_helper/testdata/ps.txt
new file mode 100644
index 000000000000..72dafc2c4378
--- /dev/null
+++ b/cmds/incident_helper/testdata/ps.txt
@@ -0,0 +1,9 @@
+LABEL USER PID TID PPID VSZ RSS WCHAN ADDR S PRI NI RTPRIO SCH PCY TIME CMD
+u:r:init:s0 root 1 1 0 15816 2636 SyS_epoll_wait 0 S 19 0 - 0 fg 00:00:01 init
+u:r:kernel:s0 root 2 2 0 0 0 kthreadd 0 S 19 0 - 0 fg 00:00:00 kthreadd
+u:r:surfaceflinger:s0 system 499 534 1 73940 22024 futex_wait_queue_me 0 S 42 -9 2 1 fg 00:00:00 EventThread
+u:r:hal_gnss_default:s0 gps 670 2004 1 43064 7272 poll_schedule_timeout 0 S 19 0 - 0 fg 00:00:00 Loc_hal_worker
+u:r:platform_app:s0:c512,c768 u0_a48 1660 1976 806 4468612 138328 binder_thread_read 0 S 35 -16 - 0 ta 00:00:00 HwBinder:1660_1
+u:r:perfd:s0 root 1939 1946 1 18132 2088 __skb_recv_datagram 7b9782fd14 S 19 0 - 0 00:00:00 perfd
+u:r:perfd:s0 root 1939 1955 1 18132 2088 do_sigtimedwait 7b9782ff6c S 19 0 - 0 00:00:00 POSIX timer 0
+u:r:shell:s0 shell 2645 2645 802 11664 2972 0 7f67a2f8b4 R 19 0 - 0 fg 00:00:00 ps
diff --git a/cmds/incident_helper/tests/BatteryTypeParser_test.cpp b/cmds/incident_helper/tests/BatteryTypeParser_test.cpp
new file mode 100644
index 000000000000..7fbe22df4b0a
--- /dev/null
+++ b/cmds/incident_helper/tests/BatteryTypeParser_test.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#include "BatteryTypeParser.h"
+
+#include "frameworks/base/core/proto/android/os/batterytype.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message_lite.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class BatteryTypeParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ ASSERT_TRUE(tf.fd != -1);
+ }
+
+protected:
+ TemporaryFile tf;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(BatteryTypeParserTest, Success) {
+ const string testFile = kTestDataPath + "batterytype.txt";
+ BatteryTypeParser parser;
+ BatteryTypeProto expected;
+
+ expected.set_type("random_battery_type_string");
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
+ close(fd);
+}
diff --git a/cmds/incident_helper/tests/PsParser_test.cpp b/cmds/incident_helper/tests/PsParser_test.cpp
new file mode 100644
index 000000000000..1f03a7f3a332
--- /dev/null
+++ b/cmds/incident_helper/tests/PsParser_test.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ */
+
+#include "PsParser.h"
+
+#include "frameworks/base/core/proto/android/os/ps.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message_lite.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class PsParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ ASSERT_TRUE(tf.fd != -1);
+ }
+
+protected:
+ TemporaryFile tf;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(PsParserTest, Normal) {
+ const string testFile = kTestDataPath + "ps.txt";
+ PsParser parser;
+ PsDumpProto expected;
+ PsDumpProto got;
+
+ PsDumpProto::Process* record1 = expected.add_processes();
+ record1->set_label("u:r:init:s0");
+ record1->set_user("root");
+ record1->set_pid(1);
+ record1->set_tid(1);
+ record1->set_ppid(0);
+ record1->set_vsz(15816);
+ record1->set_rss(2636);
+ record1->set_wchan("SyS_epoll_wait");
+ record1->set_addr("0");
+ record1->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record1->set_pri(19);
+ record1->set_ni(0);
+ record1->set_rtprio("-");
+ record1->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record1->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record1->set_time("00:00:01");
+ record1->set_cmd("init");
+
+ PsDumpProto::Process* record2 = expected.add_processes();
+ record2->set_label("u:r:kernel:s0");
+ record2->set_user("root");
+ record2->set_pid(2);
+ record2->set_tid(2);
+ record2->set_ppid(0);
+ record2->set_vsz(0);
+ record2->set_rss(0);
+ record2->set_wchan("kthreadd");
+ record2->set_addr("0");
+ record2->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record2->set_pri(19);
+ record2->set_ni(0);
+ record2->set_rtprio("-");
+ record2->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record2->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record2->set_time("00:00:00");
+ record2->set_cmd("kthreadd");
+
+ PsDumpProto::Process* record3 = expected.add_processes();
+ record3->set_label("u:r:surfaceflinger:s0");
+ record3->set_user("system");
+ record3->set_pid(499);
+ record3->set_tid(534);
+ record3->set_ppid(1);
+ record3->set_vsz(73940);
+ record3->set_rss(22024);
+ record3->set_wchan("futex_wait_queue_me");
+ record3->set_addr("0");
+ record3->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record3->set_pri(42);
+ record3->set_ni(-9);
+ record3->set_rtprio("2");
+ record3->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_FIFO);
+ record3->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record3->set_time("00:00:00");
+ record3->set_cmd("EventThread");
+
+ PsDumpProto::Process* record4 = expected.add_processes();
+ record4->set_label("u:r:hal_gnss_default:s0");
+ record4->set_user("gps");
+ record4->set_pid(670);
+ record4->set_tid(2004);
+ record4->set_ppid(1);
+ record4->set_vsz(43064);
+ record4->set_rss(7272);
+ record4->set_wchan("poll_schedule_timeout");
+ record4->set_addr("0");
+ record4->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record4->set_pri(19);
+ record4->set_ni(0);
+ record4->set_rtprio("-");
+ record4->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record4->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record4->set_time("00:00:00");
+ record4->set_cmd("Loc_hal_worker");
+
+ PsDumpProto::Process* record5 = expected.add_processes();
+ record5->set_label("u:r:platform_app:s0:c512,c768");
+ record5->set_user("u0_a48");
+ record5->set_pid(1660);
+ record5->set_tid(1976);
+ record5->set_ppid(806);
+ record5->set_vsz(4468612);
+ record5->set_rss(138328);
+ record5->set_wchan("binder_thread_read");
+ record5->set_addr("0");
+ record5->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record5->set_pri(35);
+ record5->set_ni(-16);
+ record5->set_rtprio("-");
+ record5->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record5->set_pcy(PsDumpProto::Process::POLICY_TA);
+ record5->set_time("00:00:00");
+ record5->set_cmd("HwBinder:1660_1");
+
+ PsDumpProto::Process* record6 = expected.add_processes();
+ record6->set_label("u:r:perfd:s0");
+ record6->set_user("root");
+ record6->set_pid(1939);
+ record6->set_tid(1946);
+ record6->set_ppid(1);
+ record6->set_vsz(18132);
+ record6->set_rss(2088);
+ record6->set_wchan("__skb_recv_datagram");
+ record6->set_addr("7b9782fd14");
+ record6->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record6->set_pri(19);
+ record6->set_ni(0);
+ record6->set_rtprio("-");
+ record6->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record6->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record6->set_time("00:00:00");
+ record6->set_cmd("perfd");
+
+ PsDumpProto::Process* record7 = expected.add_processes();
+ record7->set_label("u:r:perfd:s0");
+ record7->set_user("root");
+ record7->set_pid(1939);
+ record7->set_tid(1955);
+ record7->set_ppid(1);
+ record7->set_vsz(18132);
+ record7->set_rss(2088);
+ record7->set_wchan("do_sigtimedwait");
+ record7->set_addr("7b9782ff6c");
+ record7->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record7->set_pri(19);
+ record7->set_ni(0);
+ record7->set_rtprio("-");
+ record7->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record7->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record7->set_time("00:00:00");
+ record7->set_cmd("POSIX timer 0");
+
+ PsDumpProto::Process* record8 = expected.add_processes();
+ record8->set_label("u:r:shell:s0");
+ record8->set_user("shell");
+ record8->set_pid(2645);
+ record8->set_tid(2645);
+ record8->set_ppid(802);
+ record8->set_vsz(11664);
+ record8->set_rss(2972);
+ record8->set_wchan("0");
+ record8->set_addr("7f67a2f8b4");
+ record8->set_s(PsDumpProto_Process_ProcessStateCode_STATE_R);
+ record8->set_pri(19);
+ record8->set_ni(0);
+ record8->set_rtprio("-");
+ record8->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record8->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record8->set_time("00:00:00");
+ record8->set_cmd("ps");
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ got.ParseFromString(GetCapturedStdout());
+ bool matches = true;
+
+ if (got.processes_size() != expected.processes_size()) {
+ fprintf(stderr, "Got %d processes, want %d\n", got.processes_size(), expected.processes_size());
+ matches = false;
+ } else {
+ int n = got.processes_size();
+ for (int i = 0; i < n; i++) {
+ PsDumpProto::Process g = got.processes(i);
+ PsDumpProto::Process e = expected.processes(i);
+
+ if (g.label() != e.label()) {
+ fprintf(stderr, "prcs[%d]: Invalid label. Got %s, want %s\n", i, g.label().c_str(), e.label().c_str());
+ matches = false;
+ }
+ if (g.user() != e.user()) {
+ fprintf(stderr, "prcs[%d]: Invalid user. Got %s, want %s\n", i, g.user().c_str(), e.user().c_str());
+ matches = false;
+ }
+ if (g.pid() != e.pid()) {
+ fprintf(stderr, "prcs[%d]: Invalid pid. Got %d, want %d\n", i, g.pid(), e.pid());
+ matches = false;
+ }
+ if (g.tid() != e.tid()) {
+ fprintf(stderr, "prcs[%d]: Invalid tid. Got %d, want %d\n", i, g.tid(), e.tid());
+ matches = false;
+ }
+ if (g.ppid() != e.ppid()) {
+ fprintf(stderr, "prcs[%d]: Invalid ppid. Got %d, want %d\n", i, g.ppid(), e.ppid());
+ matches = false;
+ }
+ if (g.vsz() != e.vsz()) {
+ fprintf(stderr, "prcs[%d]: Invalid vsz. Got %d, want %d\n", i, g.vsz(), e.vsz());
+ matches = false;
+ }
+ if (g.rss() != e.rss()) {
+ fprintf(stderr, "prcs[%d]: Invalid rss. Got %d, want %d\n", i, g.rss(), e.rss());
+ matches = false;
+ }
+ if (g.wchan() != e.wchan()) {
+ fprintf(stderr, "prcs[%d]: Invalid wchan. Got %s, want %s\n", i, g.wchan().c_str(), e.wchan().c_str());
+ matches = false;
+ }
+ if (g.addr() != e.addr()) {
+ fprintf(stderr, "prcs[%d]: Invalid addr. Got %s, want %s\n", i, g.addr().c_str(), e.addr().c_str());
+ matches = false;
+ }
+ if (g.s() != e.s()) {
+ fprintf(stderr, "prcs[%d]: Invalid s. Got %u, want %u\n", i, g.s(), e.s());
+ matches = false;
+ }
+ if (g.pri() != e.pri()) {
+ fprintf(stderr, "prcs[%d]: Invalid pri. Got %d, want %d\n", i, g.pri(), e.pri());
+ matches = false;
+ }
+ if (g.ni() != e.ni()) {
+ fprintf(stderr, "prcs[%d]: Invalid ni. Got %d, want %d\n", i, g.ni(), e.ni());
+ matches = false;
+ }
+ if (g.rtprio() != e.rtprio()) {
+ fprintf(stderr, "prcs[%d]: Invalid rtprio. Got %s, want %s\n", i, g.rtprio().c_str(), e.rtprio().c_str());
+ matches = false;
+ }
+ if (g.sch() != e.sch()) {
+ fprintf(stderr, "prcs[%d]: Invalid sch. Got %u, want %u\n", i, g.sch(), e.sch());
+ matches = false;
+ }
+ if (g.pcy() != e.pcy()) {
+ fprintf(stderr, "prcs[%d]: Invalid pcy. Got %u, want %u\n", i, g.pcy(), e.pcy());
+ matches = false;
+ }
+ if (g.time() != e.time()) {
+ fprintf(stderr, "prcs[%d]: Invalid time. Got %s, want %s\n", i, g.time().c_str(), e.time().c_str());
+ matches = false;
+ }
+ if (g.cmd() != e.cmd()) {
+ fprintf(stderr, "prcs[%d]: Invalid cmd. Got %s, want %s\n", i, g.cmd().c_str(), e.cmd().c_str());
+ matches = false;
+ }
+ }
+ }
+
+ EXPECT_TRUE(matches);
+ close(fd);
+}
diff --git a/cmds/incident_helper/tests/ih_util_test.cpp b/cmds/incident_helper/tests/ih_util_test.cpp
index 5740b330d949..7b8cf52c8bee 100644
--- a/cmds/incident_helper/tests/ih_util_test.cpp
+++ b/cmds/incident_helper/tests/ih_util_test.cpp
@@ -71,11 +71,29 @@ TEST(IhUtilTest, ParseRecordByColumns) {
EXPECT_EQ(expected, result);
result = parseRecordByColumns("abc \t2345 6789 ", indices);
- expected = { "abc", "2345", "6789" };
+ expected = { "abc", "2345 6789" };
EXPECT_EQ(expected, result);
- result = parseRecordByColumns("abc \t23456789 bob", indices);
- expected = { "abc", "23456789", "bob" };
+ std::string extraColumn1 = "abc \t23456789 bob";
+ std::string emptyMidColm = "abc \t bob";
+ std::string longFirstClm = "abcdefgt\t6789 bob";
+ std::string lngFrstEmpty = "abcdefgt\t bob";
+
+ result = parseRecordByColumns(extraColumn1, indices);
+ expected = { "abc", "23456789 bob" };
+ EXPECT_EQ(expected, result);
+
+ // 2nd column should be treated as an empty entry.
+ result = parseRecordByColumns(emptyMidColm, indices);
+ expected = { "abc", "bob" };
+ EXPECT_EQ(expected, result);
+
+ result = parseRecordByColumns(longFirstClm, indices);
+ expected = { "abcdefgt", "6789 bob" };
+ EXPECT_EQ(expected, result);
+
+ result = parseRecordByColumns(lngFrstEmpty, indices);
+ expected = { "abcdefgt", "bob" };
EXPECT_EQ(expected, result);
}
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index fb8ef6338d90..11d3e4911761 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -72,9 +72,7 @@ LOCAL_GENERATED_SOURCES += $(GEN)
gen_src_dir:=
GEN:=
-ifeq ($(BUILD_WITH_INCIDENTD_RC), true)
LOCAL_INIT_RC := incidentd.rc
-endif
include $(BUILD_EXECUTABLE)
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 1bf795bb6557..22053ef3c53a 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -521,7 +521,7 @@ CommandSection::Execute(ReportRequestSet* requests) const
ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(), strerror(errno));
_exit(EXIT_FAILURE);
}
- execv(this->mCommand[0], (char *const *) this->mCommand);
+ execvp(this->mCommand[0], (char *const *) this->mCommand);
int err = errno; // record command error code
ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(), strerror(errno));
_exit(err); // exit with command error code
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 6da12438926c..288ebe9dbbe9 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -21,8 +21,8 @@ namespace android {
namespace os {
namespace statsd {
-android::hash_t hashDimensionsValue(const DimensionsValue& value) {
- android::hash_t hash = 0;
+android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value) {
+ android::hash_t hash = seed;
hash = android::JenkinsHashMix(hash, android::hash_type(value.field()));
hash = android::JenkinsHashMix(hash, android::hash_type((int)value.value_case()));
@@ -63,6 +63,10 @@ android::hash_t hashDimensionsValue(const DimensionsValue& value) {
return JenkinsHashWhiten(hash);
}
+android::hash_t hashDimensionsValue(const DimensionsValue& value) {
+ return hashDimensionsValue(0, value);
+}
+
using std::string;
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 3a4ffce1aadd..85c317f8cf1f 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -53,6 +53,7 @@ private:
DimensionsValue mDimensionsValue;
};
+android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value);
android::hash_t hashDimensionsValue(const DimensionsValue& value);
} // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 13f332ed34c3..991badcdddac 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -54,7 +54,7 @@ const int FIELD_ID_CONFIG_KEY = 1;
const int FIELD_ID_REPORTS = 2;
// for ConfigKey
const int FIELD_ID_UID = 1;
-const int FIELD_ID_NAME = 2;
+const int FIELD_ID_ID = 2;
// for ConfigMetricsReport
const int FIELD_ID_METRICS = 1;
const int FIELD_ID_UID_MAP = 2;
@@ -127,7 +127,7 @@ void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig
if (newMetricsManager->isConfigValid()) {
mUidMap->OnConfigUpdated(key);
newMetricsManager->setAnomalyMonitor(mAnomalyMonitor);
- if (config.log_source().package().size() > 0) {
+ if (newMetricsManager->shouldAddUidMapListener()) {
// We have to add listener after the MetricsManager is constructed because it's
// not safe to create wp or sp from this pointer inside its constructor.
mUidMap->addListener(newMetricsManager.get());
@@ -150,14 +150,15 @@ size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) const {
return it->second->byteSize();
}
-void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs, ConfigMetricsReportList* report) {
+void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs,
+ ConfigMetricsReportList* report) {
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end()) {
ALOGW("Config source %s does not exist", key.ToString().c_str());
return;
}
report->mutable_config_key()->set_uid(key.GetUid());
- report->mutable_config_key()->set_name(key.GetName());
+ report->mutable_config_key()->set_id(key.GetId());
ConfigMetricsReport* configMetricsReport = report->add_reports();
it->second->onDumpReport(dumpTimeStampNs, configMetricsReport);
// TODO: dump uid mapping.
@@ -181,7 +182,7 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, vector<uint8_t>* outD
// Start of ConfigKey.
long long configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
- proto.write(FIELD_TYPE_STRING | FIELD_ID_NAME, key.GetName());
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
proto.end(configKeyToken);
// End of ConfigKey.
@@ -278,8 +279,8 @@ void StatsLogProcessor::WriteDataToDisk() {
vector<uint8_t> data;
onDumpReport(key, &data);
// TODO: Add a guardrail to prevent accumulation of file on disk.
- string file_name = StringPrintf("%s/%d-%s-%ld", STATS_DATA_DIR, key.GetUid(),
- key.GetName().c_str(), time(nullptr));
+ string file_name = StringPrintf("%s/%d-%lld-%ld", STATS_DATA_DIR, key.GetUid(),
+ (long long)key.GetId(), time(nullptr));
StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
}
}
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index e8b0bd284570..45f1ea1bb183 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -335,7 +335,7 @@ status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
print_cmd_help(out);
return UNKNOWN_ERROR;
}
- auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, name));
+ auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, StrToInt64(name)));
sp<IStatsCompanionService> sc = getStatsCompanionService();
if (sc != nullptr) {
sc->sendBroadcast(String16(receiver.first.c_str()), String16(receiver.second.c_str()));
@@ -404,13 +404,13 @@ status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8
}
// Add / update the config.
- mConfigManager->UpdateConfig(ConfigKey(uid, name), config);
+ mConfigManager->UpdateConfig(ConfigKey(uid, StrToInt64(name)), config);
} else {
if (argCount == 2) {
cmd_remove_all_configs(out);
} else {
// Remove the config.
- mConfigManager->RemoveConfig(ConfigKey(uid, name));
+ mConfigManager->RemoveConfig(ConfigKey(uid, StrToInt64(name)));
}
}
@@ -459,7 +459,7 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String
}
if (good) {
vector<uint8_t> data;
- mProcessor->onDumpReport(ConfigKey(uid, name), &data);
+ mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), &data);
// TODO: print the returned StatsLogReport to file instead of printing to logcat.
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
@@ -699,12 +699,11 @@ void StatsService::OnLogEvent(const LogEvent& event) {
mProcessor->OnLogEvent(event);
}
-Status StatsService::getData(const String16& key, vector<uint8_t>* output) {
+Status StatsService::getData(int64_t key, vector<uint8_t>* output) {
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
if (checkCallingPermission(String16(kPermissionDump))) {
- string keyStr = string(String8(key).string());
- ConfigKey configKey(ipc->getCallingUid(), keyStr);
+ ConfigKey configKey(ipc->getCallingUid(), key);
mProcessor->onDumpReport(configKey, output);
return Status::ok();
} else {
@@ -724,14 +723,13 @@ Status StatsService::getMetadata(vector<uint8_t>* output) {
}
}
-Status StatsService::addConfiguration(const String16& key,
+Status StatsService::addConfiguration(int64_t key,
const vector <uint8_t>& config,
const String16& package, const String16& cls,
bool* success) {
IPCThreadState* ipc = IPCThreadState::self();
if (checkCallingPermission(String16(kPermissionDump))) {
- string keyString = string(String8(key).string());
- ConfigKey configKey(ipc->getCallingUid(), keyString);
+ ConfigKey configKey(ipc->getCallingUid(), key);
StatsdConfig cfg;
if (!cfg.ParseFromArray(&config[0], config.size())) {
*success = false;
@@ -748,11 +746,10 @@ Status StatsService::addConfiguration(const String16& key,
}
}
-Status StatsService::removeConfiguration(const String16& key, bool* success) {
+Status StatsService::removeConfiguration(int64_t key, bool* success) {
IPCThreadState* ipc = IPCThreadState::self();
if (checkCallingPermission(String16(kPermissionDump))) {
- string keyStr = string(String8(key).string());
- mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), keyStr));
+ mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), key));
*success = true;
return Status::ok();
} else {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 08fcdac27539..c0424f39a1fd 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -77,25 +77,27 @@ public:
/**
* Binder call for clients to request data for this configuration key.
*/
- virtual Status getData(const String16& key, vector<uint8_t>* output) override;
+ virtual Status getData(int64_t key, vector<uint8_t>* output) override;
+
/**
* Binder call for clients to get metadata across all configs in statsd.
*/
virtual Status getMetadata(vector<uint8_t>* output) override;
+
/**
* Binder call to let clients send a configuration and indicate they're interested when they
* should requestData for this configuration.
*/
- virtual Status addConfiguration(const String16& key, const vector <uint8_t>& config,
- const String16& package, const String16& cls, bool* success)
+ virtual Status addConfiguration(int64_t key, const vector <uint8_t>& config,
+ const String16& package, const String16& cls, bool* success)
override;
/**
* Binder call to allow clients to remove the specified configuration.
*/
- virtual Status removeConfiguration(const String16& key, bool* success) override;
+ virtual Status removeConfiguration(int64_t key, bool* success) override;
// TODO: public for testing since statsd doesn't run when system starts. Change to private
// later.
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index f8a941362648..05c68e1fa471 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -34,11 +34,11 @@ namespace statsd {
AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
: mAlert(alert),
mConfigKey(configKey),
- mNumOfPastBuckets(mAlert.number_of_buckets() - 1) {
+ mNumOfPastBuckets(mAlert.num_buckets() - 1) {
VLOG("AnomalyTracker() called");
- if (mAlert.number_of_buckets() <= 0) {
+ if (mAlert.num_buckets() <= 0) {
ALOGE("Cannot create AnomalyTracker with %lld buckets",
- (long long)mAlert.number_of_buckets());
+ (long long)mAlert.num_buckets());
return;
}
if (!mAlert.has_trigger_if_sum_gt()) {
@@ -205,23 +205,21 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs) {
// TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
// if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
- if (mAlert.has_incidentd_details()) {
- if (mAlert.has_name()) {
- ALOGI("An anomaly (%s) has occurred! Informing incidentd.",
- mAlert.name().c_str());
+ if (!mSubscriptions.empty()) {
+ if (mAlert.has_id()) {
+ ALOGI("An anomaly (%llu) has occurred! Informing subscribers.",mAlert.id());
+ informSubscribers();
} else {
- // TODO: Can construct a name based on the criteria (and/or relay the criteria).
- ALOGI("An anomaly (nameless) has occurred! Informing incidentd.");
+ ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
}
- informIncidentd();
} else {
- ALOGI("An anomaly has occurred! (But informing incidentd not requested.)");
+ ALOGI("An anomaly has occurred! (But no subscriber for that alert.)");
}
- StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.name());
+ StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
- mConfigKey.GetName().c_str(), mAlert.name().c_str());
+ mConfigKey.GetId(), mAlert.id());
}
void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
@@ -246,27 +244,46 @@ bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs) const {
timestampNs - mLastAnomalyTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC;
}
-void AnomalyTracker::informIncidentd() {
- VLOG("informIncidentd called.");
- if (!mAlert.has_incidentd_details()) {
- ALOGE("Attempted to call incidentd without any incidentd_details.");
- return;
- }
- sp<IIncidentManager> service = interface_cast<IIncidentManager>(
- defaultServiceManager()->getService(android::String16("incident")));
- if (service == NULL) {
- ALOGW("Couldn't get the incident service.");
+void AnomalyTracker::informSubscribers() {
+ VLOG("informSubscribers called.");
+ if (mSubscriptions.empty()) {
+ ALOGE("Attempt to call with no subscribers.");
return;
}
- IncidentReportArgs incidentReport;
- const Alert::IncidentdDetails& details = mAlert.incidentd_details();
- for (int i = 0; i < details.section_size(); i++) {
- incidentReport.addSection(details.section(i));
+ std::set<int> incidentdSections;
+ for (const Subscription& subscription : mSubscriptions) {
+ switch (subscription.subscriber_information_case()) {
+ case Subscription::SubscriberInformationCase::kIncidentdDetails:
+ for (int i = 0; i < subscription.incidentd_details().section_size(); i++) {
+ incidentdSections.insert(subscription.incidentd_details().section(i));
+ }
+ break;
+ case Subscription::SubscriberInformationCase::kPerfettoDetails:
+ ALOGW("Perfetto reports not implemented.");
+ break;
+ default:
+ break;
+ }
+ }
+ if (!incidentdSections.empty()) {
+ sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+ defaultServiceManager()->getService(android::String16("incident")));
+ if (service != NULL) {
+ IncidentReportArgs incidentReport;
+ for (const auto section : incidentdSections) {
+ incidentReport.addSection(section);
+ }
+ int64_t alertId = mAlert.id();
+ std::vector<uint8_t> header;
+ uint8_t* src = static_cast<uint8_t*>(static_cast<void*>(&alertId));
+ header.insert(header.end(), src, src + sizeof(int64_t));
+ incidentReport.addHeader(header);
+ service->reportIncident(incidentReport);
+ } else {
+ ALOGW("Couldn't get the incident service.");
+ }
}
- // TODO: Pass in mAlert.name() into the addHeader?
-
- service->reportIncident(incidentReport);
}
} // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 48f02036517f..2d5ab867da00 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -40,6 +40,11 @@ public:
virtual ~AnomalyTracker();
+ // Add subscriptions that depend on this alert.
+ void addSubscription(const Subscription& subscription) {
+ mSubscriptions.push_back(subscription);
+ }
+
// Adds a bucket.
// Bucket index starts from 0.
void addPastBucket(std::shared_ptr<DimToValMap> bucketValues, const int64_t& bucketNum);
@@ -97,6 +102,9 @@ protected:
// statsd_config.proto Alert message that defines this tracker.
const Alert mAlert;
+ // The subscriptions that depend on this alert.
+ std::vector<Subscription> mSubscriptions;
+
// A reference to the Alert's config key.
const ConfigKey& mConfigKey;
@@ -104,7 +112,7 @@ protected:
// for the anomaly detection (since the current bucket is not in the past).
int mNumOfPastBuckets;
- // The exisiting bucket list.
+ // The existing bucket list.
std::vector<shared_ptr<DimToValMap>> mPastBuckets;
// Sum over all existing buckets cached in mPastBuckets.
@@ -133,8 +141,8 @@ protected:
// Resets all bucket data. For use when all the data gets stale.
virtual void resetStorage();
- // Informs the incident service that an anomaly has occurred.
- void informIncidentd();
+ // Informs the subscribers that an anomaly has occurred.
+ void informSubscribers();
FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 1ee86f05ca29..221a55438f73 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -845,11 +845,11 @@ message AnomalyDetected {
// Uid that owns the config whose anomaly detection alert fired.
optional int32 config_uid = 1;
- // Name of the config whose anomaly detection alert fired.
- optional string config_name = 2;
+ // Id of the config whose anomaly detection alert fired.
+ optional int64 config_id = 2;
- // Name of the alert (i.e. name of the anomaly that was detected).
- optional string alert_name = 3;
+ // Id of the alert (i.e. name of the anomaly that was detected).
+ optional int64 alert_id = 3;
}
/**
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 52b83d875caa..afa26f6da08a 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -30,20 +30,20 @@ using std::unique_ptr;
using std::unordered_map;
using std::vector;
-CombinationConditionTracker::CombinationConditionTracker(const string& name, const int index)
- : ConditionTracker(name, index) {
- VLOG("creating CombinationConditionTracker %s", mName.c_str());
+CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index)
+ : ConditionTracker(id, index) {
+ VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId);
}
CombinationConditionTracker::~CombinationConditionTracker() {
- VLOG("~CombinationConditionTracker() %s", mName.c_str());
+ VLOG("~CombinationConditionTracker() %lld", (long long)mConditionId);
}
bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
- const unordered_map<string, int>& conditionNameIndexMap,
+ const unordered_map<int64_t, int>& conditionIdIndexMap,
vector<bool>& stack) {
- VLOG("Combination predicate init() %s", mName.c_str());
+ VLOG("Combination predicate init() %lld", (long long)mConditionId);
if (mInitialized) {
return true;
}
@@ -62,11 +62,11 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
return false;
}
- for (string child : combinationCondition.predicate()) {
- auto it = conditionNameIndexMap.find(child);
+ for (auto child : combinationCondition.predicate()) {
+ auto it = conditionIdIndexMap.find(child);
- if (it == conditionNameIndexMap.end()) {
- ALOGW("Predicate %s not found in the config", child.c_str());
+ if (it == conditionIdIndexMap.end()) {
+ ALOGW("Predicate %lld not found in the config", (long long)child);
return false;
}
@@ -79,13 +79,13 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
}
bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
- conditionNameIndexMap, stack);
+ conditionIdIndexMap, stack);
if (!initChildSucceeded) {
- ALOGW("Child initialization failed %s ", child.c_str());
+ ALOGW("Child initialization failed %lld ", (long long)child);
return false;
} else {
- ALOGW("Child initialization success %s ", child.c_str());
+ ALOGW("Child initialization success %lld ", (long long)child);
}
mChildren.push_back(childIndex);
@@ -154,8 +154,8 @@ void CombinationConditionTracker::evaluateCondition(
}
}
nonSlicedConditionCache[mIndex] = ConditionState::kUnknown;
- ALOGD("CombinationPredicate %s sliced may changed? %d", mName.c_str(),
- conditionChangedCache[mIndex] == true);
+ ALOGD("CombinationPredicate %lld sliced may changed? %d", (long long)mConditionId,
+ conditionChangedCache[mIndex] == true);
}
}
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 894283323c78..dfd3837f31f4 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -26,13 +26,13 @@ namespace statsd {
class CombinationConditionTracker : public virtual ConditionTracker {
public:
- CombinationConditionTracker(const std::string& name, const int index);
+ CombinationConditionTracker(const int64_t& id, const int index);
~CombinationConditionTracker();
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
- const std::unordered_map<std::string, int>& conditionNameIndexMap,
+ const std::unordered_map<int64_t, int>& conditionIdIndexMap,
std::vector<bool>& stack) override;
void evaluateCondition(const LogEvent& event,
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 1154b6fed177..773860f429b1 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -32,8 +32,8 @@ namespace statsd {
class ConditionTracker : public virtual RefBase {
public:
- ConditionTracker(const std::string& name, const int index)
- : mName(name),
+ ConditionTracker(const int64_t& id, const int index)
+ : mConditionId(id),
mIndex(index),
mInitialized(false),
mTrackerIndex(),
@@ -42,7 +42,7 @@ public:
virtual ~ConditionTracker(){};
- inline const string& getName() { return mName; }
+ inline const int64_t& getId() { return mConditionId; }
// Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
// be done in the constructor, but we do it separately because (1) easy to return a bool to
@@ -50,11 +50,11 @@ public:
// allConditionConfig: the list of all Predicate config from statsd_config.
// allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
// need to call init() on children conditions)
- // conditionNameIndexMap: the mapping from condition name to its index.
+ // conditionIdIndexMap: the mapping from condition id to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
virtual bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
- const std::unordered_map<std::string, int>& conditionNameIndexMap,
+ const std::unordered_map<int64_t, int>& conditionIdIndexMap,
std::vector<bool>& stack) = 0;
// evaluate current condition given the new event.
@@ -99,9 +99,7 @@ public:
}
protected:
- // We don't really need the string name, but having a name here makes log messages
- // easy to debug.
- const std::string mName;
+ const int64_t mConditionId;
// the index of this condition in the manager's condition list.
const int mIndex;
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 1803cbb6f500..25257213a5d0 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -33,17 +33,17 @@ using std::unordered_map;
using std::vector;
SimpleConditionTracker::SimpleConditionTracker(
- const ConfigKey& key, const string& name, const int index,
+ const ConfigKey& key, const int64_t& id, const int index,
const SimplePredicate& simplePredicate,
- const unordered_map<string, int>& trackerNameIndexMap)
- : ConditionTracker(name, index), mConfigKey(key) {
- VLOG("creating SimpleConditionTracker %s", mName.c_str());
+ const unordered_map<int64_t, int>& trackerNameIndexMap)
+ : ConditionTracker(id, index), mConfigKey(key) {
+ VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
mCountNesting = simplePredicate.count_nesting();
if (simplePredicate.has_start()) {
auto pair = trackerNameIndexMap.find(simplePredicate.start());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Start matcher %s not found in the config", simplePredicate.start().c_str());
+ ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
return;
}
mStartLogMatcherIndex = pair->second;
@@ -55,7 +55,7 @@ SimpleConditionTracker::SimpleConditionTracker(
if (simplePredicate.has_stop()) {
auto pair = trackerNameIndexMap.find(simplePredicate.stop());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop matcher %s not found in the config", simplePredicate.stop().c_str());
+ ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
return;
}
mStopLogMatcherIndex = pair->second;
@@ -67,7 +67,7 @@ SimpleConditionTracker::SimpleConditionTracker(
if (simplePredicate.has_stop_all()) {
auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop all matcher %s not found in the config", simplePredicate.stop().c_str());
+ ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all());
return;
}
mStopAllLogMatcherIndex = pair->second;
@@ -99,15 +99,15 @@ SimpleConditionTracker::~SimpleConditionTracker() {
bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
- const unordered_map<string, int>& conditionNameIndexMap,
+ const unordered_map<int64_t, int>& conditionIdIndexMap,
vector<bool>& stack) {
// SimpleConditionTracker does not have dependency on other conditions, thus we just return
// if the initialization was successful.
return mInitialized;
}
-void print(map<HashableDimensionKey, int>& conditions, const string& name) {
- VLOG("%s DUMP:", name.c_str());
+void print(map<HashableDimensionKey, int>& conditions, const int64_t& id) {
+ VLOG("%lld DUMP:", (long long)id);
for (const auto& pair : conditions) {
VLOG("\t%s : %d", pair.first.c_str(), pair.second);
}
@@ -135,10 +135,11 @@ bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// 1. Report the tuple count if the tuple count > soft limit
if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mSlicedConditionState.size() + 1;
- StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mName, newTupleCount);
+ StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("Predicate %s dropping data for dimension key %s", mName.c_str(), newKey.c_str());
+ ALOGE("Predicate %lld dropping data for dimension key %s",
+ (long long)mConditionId, newKey.c_str());
return true;
}
}
@@ -222,13 +223,13 @@ void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& ou
// dump all dimensions for debugging
if (DEBUG) {
- print(mSlicedConditionState, mName);
+ print(mSlicedConditionState, mConditionId);
}
conditionChangedCache[mIndex] = changed;
conditionCache[mIndex] = newCondition;
- VLOG("SimplePredicate %s nonSlicedChange? %d", mName.c_str(),
+ VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
conditionChangedCache[mIndex] == true);
}
@@ -239,7 +240,8 @@ void SimpleConditionTracker::evaluateCondition(const LogEvent& event,
vector<bool>& conditionChangedCache) {
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
// it has been evaluated.
- VLOG("Yes, already evaluated, %s %d", mName.c_str(), conditionCache[mIndex]);
+ VLOG("Yes, already evaluated, %lld %d",
+ (long long)mConditionId, conditionCache[mIndex]);
return;
}
@@ -320,11 +322,11 @@ void SimpleConditionTracker::isConditionMet(
const ConditionKey& conditionParameters,
const vector<sp<ConditionTracker>>& allConditions,
vector<ConditionState>& conditionCache) const {
- const auto pair = conditionParameters.find(mName);
+ const auto pair = conditionParameters.find(mConditionId);
if (pair == conditionParameters.end() && mOutputDimensions.child_size() > 0) {
- ALOGE("Predicate %s output has dimension, but it's not specified in the query!",
- mName.c_str());
+ ALOGE("Predicate %lld output has dimension, but it's not specified in the query!",
+ (long long)mConditionId);
conditionCache[mIndex] = mInitialValue;
return;
}
@@ -343,7 +345,7 @@ void SimpleConditionTracker::isConditionMet(
}
}
conditionCache[mIndex] = conditionState;
- VLOG("Predicate %s return %d", mName.c_str(), conditionCache[mIndex]);
+ VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
}
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 50486358db66..815b445a8c5b 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -29,15 +29,15 @@ namespace statsd {
class SimpleConditionTracker : public virtual ConditionTracker {
public:
- SimpleConditionTracker(const ConfigKey& key, const std::string& name, const int index,
+ SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
const SimplePredicate& simplePredicate,
- const std::unordered_map<std::string, int>& trackerNameIndexMap);
+ const std::unordered_map<int64_t, int>& trackerNameIndexMap);
~SimpleConditionTracker();
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
- const std::unordered_map<std::string, int>& conditionNameIndexMap,
+ const std::unordered_map<int64_t, int>& conditionIdIndexMap,
std::vector<bool>& stack) override;
void evaluateCondition(const LogEvent& event,
diff --git a/cmds/statsd/src/config/ConfigKey.cpp b/cmds/statsd/src/config/ConfigKey.cpp
index a365dc0b9189..d791f8632f3c 100644
--- a/cmds/statsd/src/config/ConfigKey.cpp
+++ b/cmds/statsd/src/config/ConfigKey.cpp
@@ -27,10 +27,10 @@ using std::ostringstream;
ConfigKey::ConfigKey() {
}
-ConfigKey::ConfigKey(const ConfigKey& that) : mName(that.mName), mUid(that.mUid) {
+ConfigKey::ConfigKey(const ConfigKey& that) : mId(that.mId), mUid(that.mUid) {
}
-ConfigKey::ConfigKey(int uid, const string& name) : mName(name), mUid(uid) {
+ConfigKey::ConfigKey(int uid, const int64_t& id) : mId(id), mUid(uid) {
}
ConfigKey::~ConfigKey() {
@@ -38,10 +38,21 @@ ConfigKey::~ConfigKey() {
string ConfigKey::ToString() const {
ostringstream out;
- out << '(' << mUid << ',' << mName << ')';
+ out << '(' << mUid << ',' << mId << ')';
return out.str();
}
+
+int64_t StrToInt64(const string& str) {
+ char* endp;
+ int64_t value;
+ value = strtoll(str.c_str(), &endp, 0);
+ if (endp == str.c_str() || *endp != '\0') {
+ value = 0;
+ }
+ return value;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
index 3489c43c8052..3ad0eed3f2b9 100644
--- a/cmds/statsd/src/config/ConfigKey.h
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -37,14 +37,14 @@ class ConfigKey {
public:
ConfigKey();
explicit ConfigKey(const ConfigKey& that);
- ConfigKey(int uid, const string& name);
+ ConfigKey(int uid, const int64_t& id);
~ConfigKey();
inline int GetUid() const {
return mUid;
}
- inline const string& GetName() const {
- return mName;
+ inline const int64_t& GetId() const {
+ return mId;
}
inline bool operator<(const ConfigKey& that) const {
@@ -54,17 +54,17 @@ public:
if (mUid > that.mUid) {
return false;
}
- return mName < that.mName;
+ return mId < that.mId;
};
inline bool operator==(const ConfigKey& that) const {
- return mUid == that.mUid && mName == that.mName;
+ return mUid == that.mUid && mId == that.mId;
};
string ToString() const;
private:
- string mName;
+ int64_t mId;
int mUid;
};
@@ -72,6 +72,8 @@ inline ostream& operator<<(ostream& os, const ConfigKey& config) {
return os << config.ToString();
}
+int64_t StrToInt64(const string& str);
+
} // namespace statsd
} // namespace os
} // namespace android
@@ -87,7 +89,7 @@ using android::os::statsd::ConfigKey;
template <>
struct hash<ConfigKey> {
std::size_t operator()(const ConfigKey& key) const {
- return (7 * key.GetUid()) ^ ((hash<string>()(key.GetName())));
+ return (7 * key.GetUid()) ^ ((hash<long long>()(key.GetId())));
}
};
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index addc1111a93d..c41301aecb98 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -103,7 +103,7 @@ void ConfigManager::RemoveConfig(const ConfigKey& key) {
}
void ConfigManager::remove_saved_configs(const ConfigKey& key) {
- string prefix = StringPrintf("%d-%s", key.GetUid(), key.GetName().c_str());
+ string prefix = StringPrintf("%d-%lld", key.GetUid(), (long long)key.GetId());
StorageManager::deletePrefixedFiles(STATS_SERVICE_DIR, prefix.c_str());
}
@@ -173,7 +173,7 @@ void ConfigManager::Dump(FILE* out) {
fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
fprintf(out, " uid name\n");
for (const auto& key : mConfigs) {
- fprintf(out, " %6d %s\n", key.GetUid(), key.GetName().c_str());
+ fprintf(out, " %6d %lld\n", key.GetUid(), (long long)key.GetId());
auto receiverIt = mConfigReceivers.find(key);
if (receiverIt != mConfigReceivers.end()) {
fprintf(out, " -> received by %s, %s\n", receiverIt->second.first.c_str(),
@@ -189,8 +189,8 @@ void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfi
remove_saved_configs(key);
// Then we save the latest config.
- string file_name = StringPrintf("%s/%d-%s-%ld", STATS_SERVICE_DIR, key.GetUid(),
- key.GetName().c_str(), time(nullptr));
+ string file_name = StringPrintf("%s/%d-%lld-%ld", STATS_SERVICE_DIR, key.GetUid(),
+ (long long)key.GetId(), time(nullptr));
const int numBytes = config.ByteSize();
vector<uint8_t> buffer(numBytes);
config.SerializeToArray(&buffer[0], numBytes);
@@ -200,7 +200,7 @@ void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfi
StatsdConfig build_fake_config() {
// HACK: Hard code a test metric for counting screen on events...
StatsdConfig config;
- config.set_name("CONFIG_12345");
+ config.set_id(12345);
int WAKE_LOCK_TAG_ID = 1111; // put a fake id here to make testing easier.
int WAKE_LOCK_UID_KEY_ID = 1;
@@ -232,14 +232,14 @@ StatsdConfig build_fake_config() {
// Count Screen ON events.
CountMetric* metric = config.add_count_metric();
- metric->set_name("METRIC_1");
- metric->set_what("SCREEN_TURNED_ON");
+ metric->set_id(1); // METRIC_1
+ metric->set_what(102); // "SCREEN_TURNED_ON"
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
// Anomaly threshold for screen-on count.
// TODO(b/70627390): Uncomment once the bug is fixed.
/*Alert* alert = config.add_alert();
- alert->set_name("ALERT_1");
+ alert->set_id("ALERT_1");
alert->set_metric_name("METRIC_1");
alert->set_number_of_buckets(6);
alert->set_trigger_if_sum_gt(10);
@@ -248,16 +248,16 @@ StatsdConfig build_fake_config() {
details->add_section(12);
details->add_section(13);*/
- AllowedLogSource* logSource = config.mutable_log_source();
- logSource->add_uid(1000);
- logSource->add_uid(0);
- logSource->add_package("com.android.statsd.dogfood");
- logSource->add_package("com.android.bluetooth");
+ config.add_allowed_log_source("AID_ROOT");
+ config.add_allowed_log_source("AID_SYSTEM");
+ config.add_allowed_log_source("AID_BLUETOOTH");
+ config.add_allowed_log_source("com.android.statsd.dogfood");
+ config.add_allowed_log_source("com.android.systemui");
// Count process state changes, slice by uid.
metric = config.add_count_metric();
- metric->set_name("METRIC_2");
- metric->set_what("PROCESS_STATE_CHANGE");
+ metric->set_id(2); // "METRIC_2"
+ metric->set_what(104);
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
FieldMatcher* dimensions = metric->mutable_dimensions();
dimensions->set_field(UID_PROCESS_STATE_TAG_ID);
@@ -267,7 +267,7 @@ StatsdConfig build_fake_config() {
// TODO(b/70627390): Uncomment once the bug is fixed.
/*
alert = config.add_alert();
- alert->set_name("ALERT_2");
+ alert->set_id("ALERT_2");
alert->set_metric_name("METRIC_2");
alert->set_number_of_buckets(4);
alert->set_trigger_if_sum_gt(30);
@@ -278,28 +278,28 @@ StatsdConfig build_fake_config() {
// Count process state changes, slice by uid, while SCREEN_IS_OFF
metric = config.add_count_metric();
- metric->set_name("METRIC_3");
- metric->set_what("PROCESS_STATE_CHANGE");
+ metric->set_id(3);
+ metric->set_what(104);
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
dimensions = metric->mutable_dimensions();
dimensions->set_field(UID_PROCESS_STATE_TAG_ID);
dimensions->add_child()->set_field(UID_PROCESS_STATE_UID_KEY);
- metric->set_condition("SCREEN_IS_OFF");
+ metric->set_condition(202);
// Count wake lock, slice by uid, while SCREEN_IS_ON and app in background
metric = config.add_count_metric();
- metric->set_name("METRIC_4");
- metric->set_what("APP_GET_WL");
+ metric->set_id(4);
+ metric->set_what(107);
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
dimensions = metric->mutable_dimensions();
dimensions->set_field(WAKE_LOCK_TAG_ID);
dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
- metric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ metric->set_condition(204);
MetricConditionLink* link = metric->add_links();
- link->set_condition("APP_IS_BACKGROUND");
+ link->set_condition(203);
link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -307,16 +307,16 @@ StatsdConfig build_fake_config() {
// Duration of an app holding any wl, while screen on and app in background, slice by uid
DurationMetric* durationMetric = config.add_duration_metric();
- durationMetric->set_name("METRIC_5");
+ durationMetric->set_id(5);
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
dimensions = durationMetric->mutable_dimensions();
dimensions->set_field(WAKE_LOCK_TAG_ID);
dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
- durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
- durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_what(205);
+ durationMetric->set_condition(204);
link = durationMetric->add_links();
- link->set_condition("APP_IS_BACKGROUND");
+ link->set_condition(203);
link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -324,16 +324,16 @@ StatsdConfig build_fake_config() {
// max Duration of an app holding any wl, while screen on and app in background, slice by uid
durationMetric = config.add_duration_metric();
- durationMetric->set_name("METRIC_6");
+ durationMetric->set_id(6);
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
dimensions = durationMetric->mutable_dimensions();
dimensions->set_field(WAKE_LOCK_TAG_ID);
dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
- durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
- durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_what(205);
+ durationMetric->set_condition(204);
link = durationMetric->add_links();
- link->set_condition("APP_IS_BACKGROUND");
+ link->set_condition(203);
link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -341,13 +341,13 @@ StatsdConfig build_fake_config() {
// Duration of an app holding any wl, while screen on and app in background
durationMetric = config.add_duration_metric();
- durationMetric->set_name("METRIC_7");
+ durationMetric->set_id(7);
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
- durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
- durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_what(205);
+ durationMetric->set_condition(204);
link = durationMetric->add_links();
- link->set_condition("APP_IS_BACKGROUND");
+ link->set_condition(203);
link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -356,17 +356,17 @@ StatsdConfig build_fake_config() {
// Duration of screen on time.
durationMetric = config.add_duration_metric();
- durationMetric->set_name("METRIC_8");
+ durationMetric->set_id(8);
durationMetric->mutable_bucket()->set_bucket_size_millis(10 * 1000L);
durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
- durationMetric->set_what("SCREEN_IS_ON");
+ durationMetric->set_what(201);
// Anomaly threshold for background count.
// TODO(b/70627390): Uncomment once the bug is fixed.
/*
alert = config.add_alert();
- alert->set_name("ALERT_8");
- alert->set_metric_name("METRIC_8");
+ alert->set_id(308);
+ alert->set_metric_id(8);
alert->set_number_of_buckets(4);
alert->set_trigger_if_sum_gt(2000000000); // 2 seconds
alert->set_refractory_period_secs(120);
@@ -375,10 +375,11 @@ StatsdConfig build_fake_config() {
// Value metric to count KERNEL_WAKELOCK when screen turned on
ValueMetric* valueMetric = config.add_value_metric();
- valueMetric->set_name("METRIC_6");
- valueMetric->set_what("KERNEL_WAKELOCK");
- valueMetric->set_value_field(KERNEL_WAKELOCK_COUNT_KEY);
- valueMetric->set_condition("SCREEN_IS_ON");
+ valueMetric->set_id(11);
+ valueMetric->set_what(109);
+ valueMetric->mutable_value_field()->set_field(KERNEL_WAKELOCK_TAG_ID);
+ valueMetric->mutable_value_field()->add_child()->set_field(KERNEL_WAKELOCK_COUNT_KEY);
+ valueMetric->set_condition(201);
dimensions = valueMetric->mutable_dimensions();
dimensions->set_field(KERNEL_WAKELOCK_TAG_ID);
dimensions->add_child()->set_field(KERNEL_WAKELOCK_NAME_KEY);
@@ -387,13 +388,13 @@ StatsdConfig build_fake_config() {
// Add an EventMetric to log process state change events.
EventMetric* eventMetric = config.add_event_metric();
- eventMetric->set_name("METRIC_9");
- eventMetric->set_what("SCREEN_TURNED_ON");
+ eventMetric->set_id(9);
+ eventMetric->set_what(102); // "SCREEN_TURNED_ON"
// Add an GaugeMetric.
GaugeMetric* gaugeMetric = config.add_gauge_metric();
- gaugeMetric->set_name("METRIC_10");
- gaugeMetric->set_what("DEVICE_TEMPERATURE");
+ gaugeMetric->set_id(10);
+ gaugeMetric->set_what(101);
auto gaugeFieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(DEVICE_TEMPERATURE_TAG_ID);
gaugeFieldMatcher->add_child()->set_field(DEVICE_TEMPERATURE_KEY);
@@ -401,12 +402,12 @@ StatsdConfig build_fake_config() {
// Event matchers.
AtomMatcher* temperatureAtomMatcher = config.add_atom_matcher();
- temperatureAtomMatcher->set_name("DEVICE_TEMPERATURE");
+ temperatureAtomMatcher->set_id(101); // "DEVICE_TEMPERATURE"
temperatureAtomMatcher->mutable_simple_atom_matcher()->set_atom_id(
DEVICE_TEMPERATURE_TAG_ID);
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_TURNED_ON");
+ eventMatcher->set_id(102); // "SCREEN_TURNED_ON"
SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(SCREEN_EVENT_TAG_ID);
FieldValueMatcher* fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -414,7 +415,7 @@ StatsdConfig build_fake_config() {
fieldValueMatcher->set_eq_int(SCREEN_EVENT_ON_VALUE);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_TURNED_OFF");
+ eventMatcher->set_id(103); // "SCREEN_TURNED_OFF"
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(SCREEN_EVENT_TAG_ID);
fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -422,12 +423,12 @@ StatsdConfig build_fake_config() {
fieldValueMatcher->set_eq_int(SCREEN_EVENT_OFF_VALUE);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("PROCESS_STATE_CHANGE");
+ eventMatcher->set_id(104); // "PROCESS_STATE_CHANGE"
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(UID_PROCESS_STATE_TAG_ID);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("APP_GOES_BACKGROUND");
+ eventMatcher->set_id(105); // "APP_GOES_BACKGROUND"
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(APP_USAGE_TAG_ID);
fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -435,7 +436,7 @@ StatsdConfig build_fake_config() {
fieldValueMatcher->set_eq_int(APP_USAGE_BACKGROUND);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("APP_GOES_FOREGROUND");
+ eventMatcher->set_id(106); // "APP_GOES_FOREGROUND"
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(APP_USAGE_TAG_ID);
fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -443,7 +444,7 @@ StatsdConfig build_fake_config() {
fieldValueMatcher->set_eq_int(APP_USAGE_FOREGROUND);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("APP_GET_WL");
+ eventMatcher->set_id(107); // "APP_GET_WL"
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(WAKE_LOCK_TAG_ID);
fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -451,7 +452,7 @@ StatsdConfig build_fake_config() {
fieldValueMatcher->set_eq_int(WAKE_LOCK_ACQUIRE_VALUE);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("APP_RELEASE_WL");
+ eventMatcher->set_id(108); //"APP_RELEASE_WL"
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(WAKE_LOCK_TAG_ID);
fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -460,47 +461,47 @@ StatsdConfig build_fake_config() {
// pulled events
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("KERNEL_WAKELOCK");
+ eventMatcher->set_id(109); // "KERNEL_WAKELOCK"
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(KERNEL_WAKELOCK_TAG_ID);
// Predicates.............
Predicate* predicate = config.add_predicate();
- predicate->set_name("SCREEN_IS_ON");
+ predicate->set_id(201); // "SCREEN_IS_ON"
SimplePredicate* simplePredicate = predicate->mutable_simple_predicate();
- simplePredicate->set_start("SCREEN_TURNED_ON");
- simplePredicate->set_stop("SCREEN_TURNED_OFF");
+ simplePredicate->set_start(102); // "SCREEN_TURNED_ON"
+ simplePredicate->set_stop(103);
simplePredicate->set_count_nesting(false);
predicate = config.add_predicate();
- predicate->set_name("SCREEN_IS_OFF");
+ predicate->set_id(202); // "SCREEN_IS_OFF"
simplePredicate = predicate->mutable_simple_predicate();
- simplePredicate->set_start("SCREEN_TURNED_OFF");
- simplePredicate->set_stop("SCREEN_TURNED_ON");
+ simplePredicate->set_start(103);
+ simplePredicate->set_stop(102); // "SCREEN_TURNED_ON"
simplePredicate->set_count_nesting(false);
predicate = config.add_predicate();
- predicate->set_name("APP_IS_BACKGROUND");
+ predicate->set_id(203); // "APP_IS_BACKGROUND"
simplePredicate = predicate->mutable_simple_predicate();
- simplePredicate->set_start("APP_GOES_BACKGROUND");
- simplePredicate->set_stop("APP_GOES_FOREGROUND");
+ simplePredicate->set_start(105);
+ simplePredicate->set_stop(106);
FieldMatcher* predicate_dimension1 = simplePredicate->mutable_dimensions();
predicate_dimension1->set_field(APP_USAGE_TAG_ID);
predicate_dimension1->add_child()->set_field(APP_USAGE_UID_KEY_ID);
simplePredicate->set_count_nesting(false);
predicate = config.add_predicate();
- predicate->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ predicate->set_id(204); // "APP_IS_BACKGROUND_AND_SCREEN_ON"
Predicate_Combination* combination_predicate = predicate->mutable_combination();
combination_predicate->set_operation(LogicalOperation::AND);
- combination_predicate->add_predicate("APP_IS_BACKGROUND");
- combination_predicate->add_predicate("SCREEN_IS_ON");
+ combination_predicate->add_predicate(203);
+ combination_predicate->add_predicate(201);
predicate = config.add_predicate();
- predicate->set_name("WL_HELD_PER_APP_PER_NAME");
+ predicate->set_id(205); // "WL_HELD_PER_APP_PER_NAME"
simplePredicate = predicate->mutable_simple_predicate();
- simplePredicate->set_start("APP_GET_WL");
- simplePredicate->set_stop("APP_RELEASE_WL");
+ simplePredicate->set_start(107);
+ simplePredicate->set_stop(108);
FieldMatcher* predicate_dimension = simplePredicate->mutable_dimensions();
predicate_dimension1->set_field(WAKE_LOCK_TAG_ID);
predicate_dimension->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
@@ -508,10 +509,10 @@ StatsdConfig build_fake_config() {
simplePredicate->set_count_nesting(true);
predicate = config.add_predicate();
- predicate->set_name("WL_HELD_PER_APP");
+ predicate->set_id(206); // "WL_HELD_PER_APP"
simplePredicate = predicate->mutable_simple_predicate();
- simplePredicate->set_start("APP_GET_WL");
- simplePredicate->set_stop("APP_RELEASE_WL");
+ simplePredicate->set_start(107);
+ simplePredicate->set_stop(108);
simplePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
predicate_dimension = simplePredicate->mutable_dimensions();
predicate_dimension->set_field(WAKE_LOCK_TAG_ID);
diff --git a/cmds/statsd/src/dimension.cpp b/cmds/statsd/src/dimension.cpp
index 886a33bf540f..8c0ae978fcb8 100644
--- a/cmds/statsd/src/dimension.cpp
+++ b/cmds/statsd/src/dimension.cpp
@@ -351,6 +351,23 @@ bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub
}
}
+long getLongFromDimenValue(const DimensionsValue& dimensionValue) {
+ switch (dimensionValue.value_case()) {
+ case DimensionsValue::ValueCase::kValueInt:
+ return dimensionValue.value_int();
+ case DimensionsValue::ValueCase::kValueLong:
+ return dimensionValue.value_long();
+ case DimensionsValue::ValueCase::kValueBool:
+ return dimensionValue.value_bool() ? 1 : 0;
+ case DimensionsValue::ValueCase::kValueFloat:
+ return (int64_t)dimensionValue.value_float();
+ case DimensionsValue::ValueCase::kValueTuple:
+ case DimensionsValue::ValueCase::kValueStr:
+ case DimensionsValue::ValueCase::VALUE_NOT_SET:
+ return 0;
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/dimension.h b/cmds/statsd/src/dimension.h
index c866958fdaae..5bb64a9cf5ee 100644
--- a/cmds/statsd/src/dimension.h
+++ b/cmds/statsd/src/dimension.h
@@ -56,6 +56,8 @@ void DimensionsValueToString(const DimensionsValue& value, std::string *flattene
bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub);
+// Helper function to get long value from the DimensionsValue proto.
+long getLongFromDimenValue(const DimensionsValue& dimensionValue);
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index bf277f0a383d..33927aa9b44c 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -80,7 +80,7 @@ void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int
StatsdStatsReport_ConfigStats configStats;
configStats.set_uid(key.GetUid());
- configStats.set_name(key.GetName());
+ configStats.set_id(key.GetId());
configStats.set_creation_time_sec(nowTimeSec);
configStats.set_metric_count(metricsCount);
configStats.set_condition_count(conditionsCount);
@@ -196,34 +196,34 @@ void StatsdStats::setCurrentUidMapMemory(int bytes) {
mUidMapStats.set_bytes_used(bytes);
}
-void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) {
+void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size) {
lock_guard<std::mutex> lock(mLock);
// if name doesn't exist before, it will create the key with count 0.
auto& conditionSizeMap = mConditionStats[key];
- if (size > conditionSizeMap[name]) {
- conditionSizeMap[name] = size;
+ if (size > conditionSizeMap[id]) {
+ conditionSizeMap[id] = size;
}
}
-void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const string& name, int size) {
+void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size) {
lock_guard<std::mutex> lock(mLock);
// if name doesn't exist before, it will create the key with count 0.
auto& metricsDimensionMap = mMetricsStats[key];
- if (size > metricsDimensionMap[name]) {
- metricsDimensionMap[name] = size;
+ if (size > metricsDimensionMap[id]) {
+ metricsDimensionMap[id] = size;
}
}
-void StatsdStats::noteMatcherMatched(const ConfigKey& key, const string& name) {
+void StatsdStats::noteMatcherMatched(const ConfigKey& key, const int64_t& id) {
lock_guard<std::mutex> lock(mLock);
auto& matcherStats = mMatcherStats[key];
- matcherStats[name]++;
+ matcherStats[id]++;
}
-void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const string& name) {
+void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const int64_t& id) {
lock_guard<std::mutex> lock(mLock);
auto& alertStats = mAlertStats[key];
- alertStats[name]++;
+ alertStats[id]++;
}
void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
@@ -279,9 +279,10 @@ void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key,
const auto& matcherStats = mMatcherStats[key];
for (const auto& stats : matcherStats) {
auto output = configStats.add_matcher_stats();
- output->set_name(stats.first);
+ output->set_id(stats.first);
output->set_matched_times(stats.second);
- VLOG("matcher %s matched %d times", stats.first.c_str(), stats.second);
+ VLOG("matcher %lld matched %d times",
+ (long long)stats.first, stats.second);
}
}
// Add condition stats
@@ -289,9 +290,10 @@ void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key,
const auto& conditionStats = mConditionStats[key];
for (const auto& stats : conditionStats) {
auto output = configStats.add_condition_stats();
- output->set_name(stats.first);
+ output->set_id(stats.first);
output->set_max_tuple_counts(stats.second);
- VLOG("condition %s max output tuple size %d", stats.first.c_str(), stats.second);
+ VLOG("condition %lld max output tuple size %d",
+ (long long)stats.first, stats.second);
}
}
// Add metrics stats
@@ -299,9 +301,10 @@ void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key,
const auto& conditionStats = mMetricsStats[key];
for (const auto& stats : conditionStats) {
auto output = configStats.add_metric_stats();
- output->set_name(stats.first);
+ output->set_id(stats.first);
output->set_max_tuple_counts(stats.second);
- VLOG("metrics %s max output tuple size %d", stats.first.c_str(), stats.second);
+ VLOG("metrics %lld max output tuple size %d",
+ (long long)stats.first, stats.second);
}
}
// Add anomaly detection alert stats
@@ -309,9 +312,9 @@ void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key,
const auto& alertStats = mAlertStats[key];
for (const auto& stats : alertStats) {
auto output = configStats.add_alert_stats();
- output->set_name(stats.first);
+ output->set_id(stats.first);
output->set_alerted_times(stats.second);
- VLOG("alert %s declared %d times", stats.first.c_str(), stats.second);
+ VLOG("alert %lld declared %d times", (long long)stats.first, stats.second);
}
}
}
@@ -343,9 +346,9 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
// in production.
if (DEBUG) {
VLOG("*****ICEBOX*****");
- VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+ VLOG("Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
"#matcher=%d, #alert=%d, #valid=%d",
- configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(),
+ configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
configStats.deletion_time_sec(), configStats.metric_count(),
configStats.condition_count(), configStats.matcher_count(),
configStats.alert_count(), configStats.is_valid());
@@ -364,9 +367,9 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
auto& configStats = pair.second;
if (DEBUG) {
VLOG("********Active Configs***********");
- VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+ VLOG("Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
"#matcher=%d, #alert=%d, #valid=%d",
- configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(),
+ configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
configStats.deletion_time_sec(), configStats.metric_count(),
configStats.condition_count(), configStats.matcher_count(),
configStats.alert_count(), configStats.is_valid());
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index cb868e1fd8c6..45aa192318a4 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -99,10 +99,10 @@ public:
* count > kDimensionKeySizeSoftLimit.
*
* [key]: The config key that this condition belongs to.
- * [name]: The name of the condition.
+ * [id]: The id of the condition.
* [size]: The output tuple size.
*/
- void noteConditionDimensionSize(const ConfigKey& key, const std::string& name, int size);
+ void noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size);
/**
* Report the size of output tuple of a metric.
@@ -111,26 +111,26 @@ public:
* count > kDimensionKeySizeSoftLimit.
*
* [key]: The config key that this metric belongs to.
- * [name]: The name of the metric.
+ * [id]: The id of the metric.
* [size]: The output tuple size.
*/
- void noteMetricDimensionSize(const ConfigKey& key, const std::string& name, int size);
+ void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size);
/**
* Report a matcher has been matched.
*
* [key]: The config key that this matcher belongs to.
- * [name]: The name of the matcher.
+ * [id]: The id of the matcher.
*/
- void noteMatcherMatched(const ConfigKey& key, const std::string& name);
+ void noteMatcherMatched(const ConfigKey& key, const int64_t& id);
/**
* Report that an anomaly detection alert has been declared.
*
* [key]: The config key that this alert belongs to.
- * [name]: The name of the alert.
+ * [id]: The id of the alert.
*/
- void noteAnomalyDeclared(const ConfigKey& key, const std::string& name);
+ void noteAnomalyDeclared(const ConfigKey& key, const int64_t& id);
/**
* Report an atom event has been logged.
@@ -187,12 +187,12 @@ private:
// Stores the number of output tuple of condition trackers when it's bigger than
// kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
// it means some data has been dropped.
- std::map<const ConfigKey, std::map<const std::string, int>> mConditionStats;
+ std::map<const ConfigKey, std::map<const int64_t, int>> mConditionStats;
// Stores the number of output tuple of metric producers when it's bigger than
// kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
// it means some data has been dropped.
- std::map<const ConfigKey, std::map<const std::string, int>> mMetricsStats;
+ std::map<const ConfigKey, std::map<const int64_t, int>> mMetricsStats;
// Stores the number of times a pushed atom is logged.
// The size of the vector is the largest pushed atom id in atoms.proto + 1. Atoms
@@ -206,10 +206,10 @@ private:
// Stores the number of times an anomaly detection alert has been declared
// (per config, per alert name).
- std::map<const ConfigKey, std::map<const std::string, int>> mAlertStats;
+ std::map<const ConfigKey, std::map<const int64_t, int>> mAlertStats;
// Stores how many times a matcher have been matched.
- std::map<const ConfigKey, std::map<const std::string, int>> mMatcherStats;
+ std::map<const ConfigKey, std::map<const int64_t, int>> mMatcherStats;
void noteConfigRemovedInternalLocked(const ConfigKey& key);
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index bd5e3cbce07c..15c067ee936d 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -29,8 +29,8 @@ using std::unique_ptr;
using std::unordered_map;
using std::vector;
-CombinationLogMatchingTracker::CombinationLogMatchingTracker(const string& name, const int index)
- : LogMatchingTracker(name, index) {
+CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index)
+ : LogMatchingTracker(id, index) {
}
CombinationLogMatchingTracker::~CombinationLogMatchingTracker() {
@@ -38,7 +38,7 @@ CombinationLogMatchingTracker::~CombinationLogMatchingTracker() {
bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers,
const vector<sp<LogMatchingTracker>>& allTrackers,
- const unordered_map<string, int>& matcherMap,
+ const unordered_map<int64_t, int>& matcherMap,
vector<bool>& stack) {
if (mInitialized) {
return true;
@@ -60,10 +60,10 @@ bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatche
return false;
}
- for (const string& child : matcher.matcher()) {
+ for (const auto& child : matcher.matcher()) {
auto pair = matcherMap.find(child);
if (pair == matcherMap.end()) {
- ALOGW("Matcher %s not found in the config", child.c_str());
+ ALOGW("Matcher %lld not found in the config", (long long)child);
return false;
}
@@ -76,7 +76,7 @@ bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatche
}
if (!allTrackers[childIndex]->init(allLogMatchers, allTrackers, matcherMap, stack)) {
- ALOGW("child matcher init failed %s", child.c_str());
+ ALOGW("child matcher init failed %lld", (long long)child);
return false;
}
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index 81f6e8052ebc..2a3f08da7b96 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -31,11 +31,11 @@ namespace statsd {
// Represents a AtomMatcher_Combination in the StatsdConfig.
class CombinationLogMatchingTracker : public virtual LogMatchingTracker {
public:
- CombinationLogMatchingTracker(const std::string& name, const int index);
+ CombinationLogMatchingTracker(const int64_t& id, const int index);
bool init(const std::vector<AtomMatcher>& allLogMatchers,
const std::vector<sp<LogMatchingTracker>>& allTrackers,
- const std::unordered_map<std::string, int>& matcherMap,
+ const std::unordered_map<int64_t, int>& matcherMap,
std::vector<bool>& stack);
~CombinationLogMatchingTracker();
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index 567944fce8a6..4f30a047e256 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -33,8 +33,8 @@ namespace statsd {
class LogMatchingTracker : public virtual RefBase {
public:
- LogMatchingTracker(const std::string& name, const int index)
- : mName(name), mIndex(index), mInitialized(false){};
+ LogMatchingTracker(const int64_t& id, const int index)
+ : mId(id), mIndex(index), mInitialized(false){};
virtual ~LogMatchingTracker(){};
@@ -48,7 +48,7 @@ public:
// circle dependency.
virtual bool init(const std::vector<AtomMatcher>& allLogMatchers,
const std::vector<sp<LogMatchingTracker>>& allTrackers,
- const std::unordered_map<std::string, int>& matcherMap,
+ const std::unordered_map<int64_t, int>& matcherMap,
std::vector<bool>& stack) = 0;
// Called when a log event comes.
@@ -69,13 +69,13 @@ public:
return mAtomIds;
}
- const std::string& getName() const {
- return mName;
+ const int64_t& getId() const {
+ return mId;
}
protected:
// Name of this matching. We don't really need the name, but it makes log message easy to debug.
- const std::string mName;
+ const int64_t mId;
// Index of this LogMatchingTracker in MetricsManager's container.
const int mIndex;
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index 91ef0344da91..31b3db524e80 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -29,10 +29,10 @@ using std::unordered_map;
using std::vector;
-SimpleLogMatchingTracker::SimpleLogMatchingTracker(const string& name, const int index,
+SimpleLogMatchingTracker::SimpleLogMatchingTracker(const int64_t& id, const int index,
const SimpleAtomMatcher& matcher,
const UidMap& uidMap)
- : LogMatchingTracker(name, index), mMatcher(matcher), mUidMap(uidMap) {
+ : LogMatchingTracker(id, index), mMatcher(matcher), mUidMap(uidMap) {
if (!matcher.has_atom_id()) {
mInitialized = false;
} else {
@@ -46,7 +46,7 @@ SimpleLogMatchingTracker::~SimpleLogMatchingTracker() {
bool SimpleLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers,
const vector<sp<LogMatchingTracker>>& allTrackers,
- const unordered_map<string, int>& matcherMap,
+ const unordered_map<int64_t, int>& matcherMap,
vector<bool>& stack) {
// no need to do anything.
return mInitialized;
@@ -56,7 +56,7 @@ void SimpleLogMatchingTracker::onLogEvent(const LogEvent& event,
const vector<sp<LogMatchingTracker>>& allTrackers,
vector<MatchingState>& matcherResults) {
if (matcherResults[mIndex] != MatchingState::kNotComputed) {
- VLOG("Matcher %s already evaluated ", mName.c_str());
+ VLOG("Matcher %lld already evaluated ", (long long)mId);
return;
}
@@ -67,7 +67,7 @@ void SimpleLogMatchingTracker::onLogEvent(const LogEvent& event,
bool matched = matchesSimple(mUidMap, mMatcher, event);
matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
- VLOG("Stats SimpleLogMatcher %s matched? %d", mName.c_str(), matched);
+ VLOG("Stats SimpleLogMatcher %lld matched? %d", (long long)mId, matched);
}
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index 68518f8a224d..28b339caa466 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -32,7 +32,7 @@ namespace statsd {
class SimpleLogMatchingTracker : public virtual LogMatchingTracker {
public:
- SimpleLogMatchingTracker(const std::string& name, const int index,
+ SimpleLogMatchingTracker(const int64_t& id, const int index,
const SimpleAtomMatcher& matcher,
const UidMap& uidMap);
@@ -40,7 +40,7 @@ public:
bool init(const std::vector<AtomMatcher>& allLogMatchers,
const std::vector<sp<LogMatchingTracker>>& allTrackers,
- const std::unordered_map<std::string, int>& matcherMap,
+ const std::unordered_map<int64_t, int>& matcherMap,
std::vector<bool>& stack) override;
void onLogEvent(const LogEvent& event,
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 5bf3cffd8bab..a24364df0fb2 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -43,7 +43,7 @@ namespace os {
namespace statsd {
// for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_COUNT_METRICS = 5;
@@ -61,7 +61,7 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
const int conditionIndex,
const sp<ConditionWizard>& wizard,
const uint64_t startTimeNs)
- : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard) {
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
// TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
@@ -78,7 +78,7 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
mConditionSliced = true;
}
- VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+ VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -87,12 +87,12 @@ CountMetricProducer::~CountMetricProducer() {
}
void CountMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
- VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+ VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
flushIfNeededLocked(dumpTimeNs);
- report->set_metric_name(mName);
+ report->set_metric_id(mMetricId);
report->set_start_report_nanos(mStartTimeNs);
auto count_metrics = report->mutable_count_metrics();
@@ -112,11 +112,11 @@ void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
flushIfNeededLocked(dumpTimeNs);
- protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
- VLOG("metric %s dump report now...", mName.c_str());
+ VLOG("metric %lld dump report now...",(long long)mMetricId);
for (const auto& counter : mPastBuckets) {
const HashableDimensionKey& hashableKey = counter.first;
@@ -158,7 +158,7 @@ void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
const uint64_t eventTime) {
- VLOG("Metric %s onConditionChanged", mName.c_str());
+ VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
mCondition = conditionMet;
}
@@ -170,11 +170,11 @@ bool CountMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey)
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedCounter->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedCounter->size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("CountMetric %s dropping data for dimension key %s", mName.c_str(),
- newKey.c_str());
+ ALOGE("CountMetric %lld dropping data for dimension key %s",
+ (long long)mMetricId, newKey.c_str());
return true;
}
}
@@ -215,7 +215,7 @@ void CountMetricProducer::onMatchedLogEventInternalLocked(
mCurrentSlicedCounter->find(eventKey)->second);
}
- VLOG("metric %s %s->%lld", mName.c_str(), eventKey.c_str(),
+ VLOG("metric %lld %s->%lld", (long long)mMetricId, eventKey.c_str(),
(long long)(*mCurrentSlicedCounter)[eventKey]);
}
@@ -234,8 +234,8 @@ void CountMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
info.mCount = counter.second;
auto& bucketList = mPastBuckets[counter.first];
bucketList.push_back(info);
- VLOG("metric %s, dump key value: %s -> %lld", mName.c_str(), counter.first.c_str(),
- (long long)counter.second);
+ VLOG("metric %lld, dump key value: %s -> %lld",
+ (long long)mMetricId, counter.first.c_str(), (long long)counter.second);
}
for (auto& tracker : mAnomalyTrackers) {
@@ -247,7 +247,7 @@ void CountMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
uint64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
mCurrentBucketNum += numBucketsForward;
- VLOG("metric %s: new bucket start time: %lld", mName.c_str(),
+ VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
(long long)mCurrentBucketStartTimeNs);
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 30b105c71500..0117b6d7faa5 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -42,7 +42,7 @@ namespace os {
namespace statsd {
// for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_DURATION_METRICS = 6;
@@ -63,7 +63,7 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
const sp<ConditionWizard>& wizard,
const FieldMatcher& internalDimensions,
const uint64_t startTimeNs)
- : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard),
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
mAggregationType(metric.aggregation_type()),
mStartIndex(startIndex),
mStopIndex(stopIndex),
@@ -88,7 +88,7 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
mConditionSliced = true;
}
- VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+ VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -98,9 +98,9 @@ DurationMetricProducer::~DurationMetricProducer() {
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
std::lock_guard<std::mutex> lock(mMutex);
- if (alert.trigger_if_sum_gt() > alert.number_of_buckets() * mBucketSizeNs) {
- ALOGW("invalid alert: threshold (%lld) > possible recordable value (%d x %lld)",
- alert.trigger_if_sum_gt(), alert.number_of_buckets(),
+ if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
+ ALOGW("invalid alert: threshold (%f) > possible recordable value (%d x %lld)",
+ alert.trigger_if_sum_gt(), alert.num_buckets(),
(long long)mBucketSizeNs);
return nullptr;
}
@@ -116,17 +116,17 @@ unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
switch (mAggregationType) {
case DurationMetric_AggregationType_SUM:
return make_unique<OringDurationTracker>(
- mConfigKey, mName, eventKey, mWizard, mConditionTrackerIndex, mNested,
+ mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
case DurationMetric_AggregationType_MAX_SPARSE:
return make_unique<MaxDurationTracker>(
- mConfigKey, mName, eventKey, mWizard, mConditionTrackerIndex, mNested,
+ mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
}
}
void DurationMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
- VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+ VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
flushIfNeededLocked(eventTime);
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& pair : mCurrentSlicedDuration) {
@@ -136,7 +136,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eve
void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
const uint64_t eventTime) {
- VLOG("Metric %s onConditionChanged", mName.c_str());
+ VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
mCondition = conditionMet;
flushIfNeededLocked(eventTime);
// TODO: need to populate the condition change time from the event which triggers the condition
@@ -148,7 +148,7 @@ void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
flushIfNeededLocked(dumpTimeNs);
- report->set_metric_name(mName);
+ report->set_metric_id(mMetricId);
report->set_start_report_nanos(mStartTimeNs);
auto duration_metrics = report->mutable_duration_metrics();
@@ -168,11 +168,11 @@ void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
flushIfNeededLocked(dumpTimeNs);
- protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
- VLOG("metric %s dump report now...", mName.c_str());
+ VLOG("metric %lld dump report now...", (long long)mMetricId);
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
@@ -237,11 +237,11 @@ bool DurationMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newK
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedDuration.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedDuration.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("DurationMetric %s dropping data for dimension key %s", mName.c_str(),
- newKey.c_str());
+ ALOGE("DurationMetric %lld dropping data for dimension key %s",
+ (long long)mMetricId, newKey.c_str());
return true;
}
}
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index c8138d3a7d9a..821d8ea48aef 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -41,7 +41,7 @@ namespace os {
namespace statsd {
// for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_EVENT_METRICS = 4;
@@ -55,7 +55,7 @@ EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric
const int conditionIndex,
const sp<ConditionWizard>& wizard,
const uint64_t startTimeNs)
- : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard) {
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
if (metric.links().size() > 0) {
mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
metric.links().end());
@@ -64,7 +64,7 @@ EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric
startNewProtoOutputStreamLocked();
- VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+ VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -102,12 +102,13 @@ void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLog
void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
- protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
size_t bufferSize = mProto->size();
- VLOG("metric %s dump report now... proto size: %zu ", mName.c_str(), bufferSize);
+ VLOG("metric %lld dump report now... proto size: %zu ",
+ (long long)mMetricId, bufferSize);
std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked(*mProto);
protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
@@ -119,7 +120,7 @@ void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
const uint64_t eventTime) {
- VLOG("Metric %s onConditionChanged", mName.c_str());
+ VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
mCondition = conditionMet;
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 51fd9fcb335b..eaf1de238e8d 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -44,7 +44,7 @@ namespace os {
namespace statsd {
// for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_GAUGE_METRICS = 8;
@@ -63,7 +63,7 @@ GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric
const sp<ConditionWizard>& wizard, const int atomTagId,
const int pullTagId, const uint64_t startTimeNs,
shared_ptr<StatsPullerManager> statsPullerManager)
- : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard),
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
mStatsPullerManager(statsPullerManager),
mPullTagId(pullTagId),
mAtomTagId(atomTagId) {
@@ -92,7 +92,7 @@ GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric
metric.bucket().bucket_size_millis());
}
- VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+ VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -118,11 +118,11 @@ void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLog
void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
- VLOG("gauge metric %s dump report now...", mName.c_str());
+ VLOG("gauge metric %lld report now...", (long long)mMetricId);
flushIfNeededLocked(dumpTimeNs);
- protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
@@ -166,7 +166,7 @@ void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
const uint64_t eventTime) {
- VLOG("Metric %s onConditionChanged", mName.c_str());
+ VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
flushIfNeededLocked(eventTime);
mCondition = conditionMet;
@@ -194,7 +194,7 @@ void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
}
void GaugeMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
- VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+ VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
std::shared_ptr<FieldValueMap> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
@@ -223,11 +223,11 @@ bool GaugeMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey)
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedBucket->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("GaugeMetric %s dropping data for dimension key %s", mName.c_str(),
- newKey.c_str());
+ ALOGE("GaugeMetric %lld dropping data for dimension key %s",
+ (long long)mMetricId, newKey.c_str());
return true;
}
}
@@ -314,7 +314,8 @@ void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
info.mGaugeFields = slice.second;
auto& bucketList = mPastBuckets[slice.first];
bucketList.push_back(info);
- VLOG("gauge metric %s, dump key value: %s", mName.c_str(), slice.first.c_str());
+ VLOG("gauge metric %lld, dump key value: %s",
+ (long long)mMetricId, slice.first.c_str());
}
// Reset counters
@@ -331,7 +332,7 @@ void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
mCurrentBucketNum += numBucketsForward;
- VLOG("metric %s: new bucket start time: %lld", mName.c_str(),
+ VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
(long long)mCurrentBucketStartTimeNs);
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 4ed8289ab133..d620a7ebee00 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -29,13 +29,13 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
}
bool condition;
- map<string, std::vector<HashableDimensionKey>> conditionKeys;
+ ConditionKey conditionKey;
if (mConditionSliced) {
for (const auto& link : mConditionLinks) {
- conditionKeys.insert(std::make_pair(link.condition(),
- getDimensionKeysForCondition(event, link)));
+ conditionKey.insert(std::make_pair(link.condition(),
+ getDimensionKeysForCondition(event, link)));
}
- if (mWizard->query(mConditionTrackerIndex, conditionKeys) != ConditionState::kTrue) {
+ if (mWizard->query(mConditionTrackerIndex, conditionKey) != ConditionState::kTrue) {
condition = false;
} else {
condition = true;
@@ -48,11 +48,11 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
vector<DimensionsValue> dimensionValues = getDimensionKeys(event, mDimensions);
for (const DimensionsValue& dimensionValue : dimensionValues) {
onMatchedLogEventInternalLocked(
- matcherIndex, HashableDimensionKey(dimensionValue), conditionKeys, condition, event);
+ matcherIndex, HashableDimensionKey(dimensionValue), conditionKey, condition, event);
}
} else {
onMatchedLogEventInternalLocked(
- matcherIndex, DEFAULT_DIMENSION_KEY, conditionKeys, condition, event);
+ matcherIndex, DEFAULT_DIMENSION_KEY, conditionKey, condition, event);
}
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index fe1a53bef735..3779c4487d23 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -39,9 +39,9 @@ namespace statsd {
// be a no-op.
class MetricProducer : public virtual PackageInfoListener {
public:
- MetricProducer(const std::string& name, const ConfigKey& key, const int64_t startTimeNs,
+ MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t startTimeNs,
const int conditionIndex, const sp<ConditionWizard>& wizard)
- : mName(name),
+ : mMetricId(metricId),
mConfigKey(key),
mStartTimeNs(startTimeNs),
mCurrentBucketStartTimeNs(startTimeNs),
@@ -117,8 +117,8 @@ public:
return mBucketSizeNs;
}
- inline const string& getName() {
- return mName;
+ inline const int64_t& getMetricId() {
+ return mMetricId;
}
protected:
@@ -129,7 +129,7 @@ protected:
virtual void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) = 0;
virtual size_t byteSizeLocked() const = 0;
- const std::string mName;
+ const int64_t mMetricId;
const ConfigKey mConfigKey;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 9749e0f4af4f..f92951703030 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -51,9 +51,9 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mConfigValid =
initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
- mTrackerToMetricMap, mTrackerToConditionMap);
+ mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
- if (!config.has_log_source()) {
+ if (config.allowed_log_source_size() == 0) {
// TODO(b/70794411): uncomment the following line and remove the hard coded log source
// after all configs have the log source added.
// mConfigValid = false;
@@ -63,10 +63,14 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mAllowedUid.push_back(0);
mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
} else {
- mAllowedUid.insert(mAllowedUid.begin(), config.log_source().uid().begin(),
- config.log_source().uid().end());
- mAllowedPkg.insert(mAllowedPkg.begin(), config.log_source().package().begin(),
- config.log_source().package().end());
+ for (const auto& source : config.allowed_log_source()) {
+ auto it = UidMap::sAidToUidMapping.find(source);
+ if (it != UidMap::sAidToUidMapping.end()) {
+ mAllowedUid.push_back(it->second);
+ } else {
+ mAllowedPkg.push_back(source);
+ }
+ }
if (mAllowedUid.size() + mAllowedPkg.size() > StatsdStats::kMaxLogSourceCount) {
ALOGE("Too many log sources. This is likely to be an error in the config.");
@@ -143,8 +147,10 @@ void MetricsManager::onUidMapReceived() {
}
void MetricsManager::onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetricsReport* report) {
- for (auto& producer : mAllMetricProducers) {
- producer->onDumpReport(dumpTimeStampNs, report->add_metrics());
+ for (const auto& producer : mAllMetricProducers) {
+ if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
+ producer->onDumpReport(dumpTimeStampNs, report->add_metrics());
+ }
}
}
@@ -152,11 +158,13 @@ void MetricsManager::onDumpReport(ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
uint64_t dumpTimeStampNs = time(nullptr) * NS_PER_SEC;
// one StatsLogReport per MetricProduer
- for (auto& metric : mAllMetricProducers) {
- long long token =
- protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
- metric->onDumpReport(dumpTimeStampNs, protoOutput);
- protoOutput->end(token);
+ for (const auto& producer : mAllMetricProducers) {
+ if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
+ long long token =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
+ producer->onDumpReport(dumpTimeStampNs, protoOutput);
+ protoOutput->end(token);
+ }
}
VLOG("=========================Metric Reports End==========================");
}
@@ -173,6 +181,22 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
VLOG("log source %d not on the whitelist", event.GetUid());
return;
}
+ } else { // Check that app hook fields are valid.
+ // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
+
+ // Label is 2nd from last field and must be from [0, 15].
+ status_t err = NO_ERROR;
+ long label = event.GetLong(event.size()-1, &err);
+ if (err != NO_ERROR || label < 0 || label > 15) {
+ VLOG("App hook does not have valid label %ld", label);
+ return;
+ }
+ // The state must be from 0,3. This part of code must be manually updated.
+ long apphookState = event.GetLong(event.size(), &err);
+ if (err != NO_ERROR || apphookState < 0 || apphookState > 3) {
+ VLOG("App hook does not have valid state %ld", apphookState);
+ return;
+ }
}
int tagId = event.GetTagId();
@@ -240,7 +264,7 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
for (size_t i = 0; i < mAllAtomMatchers.size(); i++) {
if (matcherCache[i] == MatchingState::kMatched) {
StatsdStats::getInstance().noteMatcherMatched(mConfigKey,
- mAllAtomMatchers[i]->getName());
+ mAllAtomMatchers[i]->getId());
auto pair = mTrackerToMetricMap.find(i);
if (pair != mTrackerToMetricMap.end()) {
auto& metricList = pair->second;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 51c4c90fe2ac..a03047f3aff2 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -57,6 +57,10 @@ public:
void onUidMapReceived() override;
+ bool shouldAddUidMapListener() const {
+ return !mAllowedPkg.empty();
+ }
+
// Config source owner can call onDumpReport() to get all the metrics collected.
virtual void onDumpReport(android::util::ProtoOutputStream* protoOutput);
virtual void onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetricsReport* report);
@@ -131,6 +135,9 @@ private:
void initLogSourceWhiteList();
+ // The metrics that don't need to be uploaded or even reported.
+ std::set<int64_t> mNoReportMetricIds;
+
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
};
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index b58dc689fed4..5f7d76140397 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -17,6 +17,7 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
+#include "dimension.h"
#include "ValueMetricProducer.h"
#include "guardrail/StatsdStats.h"
#include "stats_log_util.h"
@@ -46,7 +47,7 @@ namespace os {
namespace statsd {
// for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_VALUE_METRICS = 7;
@@ -68,7 +69,7 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric
const sp<ConditionWizard>& wizard, const int pullTagId,
const uint64_t startTimeNs,
shared_ptr<StatsPullerManager> statsPullerManager)
- : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard),
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
mValueField(metric.value_field()),
mStatsPullerManager(statsPullerManager),
mPullTagId(pullTagId) {
@@ -92,8 +93,8 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric
mStatsPullerManager->RegisterReceiver(mPullTagId, this,
metric.bucket().bucket_size_millis());
}
- VLOG("value metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
- (long long)mBucketSizeNs, (long long)mStartTimeNs);
+ VLOG("value metric %lld created. bucket size %lld start_time: %lld",
+ (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs);
}
// for testing
@@ -113,12 +114,12 @@ ValueMetricProducer::~ValueMetricProducer() {
}
void ValueMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
- VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+ VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
flushIfNeededLocked(dumpTimeNs);
- report->set_metric_name(mName);
+ report->set_metric_id(mMetricId);
report->set_start_report_nanos(mStartTimeNs);
auto value_metrics = report->mutable_value_metrics();
for (const auto& pair : mPastBuckets) {
@@ -135,9 +136,9 @@ void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLog
void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
- VLOG("metric %s dump report now...", mName.c_str());
+ VLOG("metric %lld dump report now...", (long long)mMetricId);
flushIfNeededLocked(dumpTimeNs);
- protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
@@ -171,7 +172,7 @@ void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
protoOutput->end(protoToken);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
- VLOG("metric %s dump report now...", mName.c_str());
+ VLOG("metric %lld dump report now...", (long long)mMetricId);
mPastBuckets.clear();
mStartTimeNs = mCurrentBucketStartTimeNs;
// TODO: Clear mDimensionKeyMap once the report is dumped.
@@ -218,7 +219,8 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
// For scheduled pulled data, the effective event time is snap to the nearest
// bucket boundary to make bucket finalize.
uint64_t realEventTime = allData.at(0)->GetTimestampNs();
- uint64_t eventTime = mStartTimeNs + ((realEventTime - mStartTimeNs)/mBucketSizeNs) * mBucketSizeNs;
+ uint64_t eventTime = mStartTimeNs +
+ ((realEventTime - mStartTimeNs)/mBucketSizeNs) * mBucketSizeNs;
mCondition = false;
for (const auto& data : allData) {
@@ -242,11 +244,11 @@ bool ValueMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey)
}
if (mCurrentSlicedBucket.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("ValueMetric %s dropping data for dimension key %s", mName.c_str(),
- newKey.c_str());
+ ALOGE("ValueMetric %lld dropping data for dimension key %s",
+ (long long)mMetricId, newKey.c_str());
return true;
}
}
@@ -272,7 +274,11 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
}
Interval& interval = mCurrentSlicedBucket[eventKey];
- long value = get_value(event);
+ std::shared_ptr<FieldValueMap> valueFieldMap = getValueFields(event);
+ if (valueFieldMap->empty() || valueFieldMap->size() > 1) {
+ return;
+ }
+ const long value = getLongFromDimenValue(valueFieldMap->begin()->second);
if (mPullTagId != -1) { // for pulled events
if (mCondition == true) {
@@ -296,15 +302,11 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
}
}
-long ValueMetricProducer::get_value(const LogEvent& event) {
- status_t err = NO_ERROR;
- long val = event.GetLong(mValueField, &err);
- if (err == NO_ERROR) {
- return val;
- } else {
- VLOG("Can't find value in message. %s", event.ToString().c_str());
- return 0;
- }
+std::shared_ptr<FieldValueMap> ValueMetricProducer::getValueFields(const LogEvent& event) {
+ std::shared_ptr<FieldValueMap> valueFields =
+ std::make_shared<FieldValueMap>(event.getFieldValueMap());
+ filterFields(mValueField, valueFields.get());
+ return valueFields;
}
void ValueMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
@@ -346,7 +348,7 @@ void ValueMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
if (numBucketsForward > 1) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
}
- VLOG("metric %s: new bucket start time: %lld", mName.c_str(),
+ VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
(long long)mCurrentBucketStartTimeNs);
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 6f3b1d1c67d7..3e7032d8cf2d 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -70,7 +70,7 @@ private:
// Util function to flush the old packet.
void flushIfNeededLocked(const uint64_t& eventTime);
- const int32_t mValueField;
+ const FieldMatcher mValueField;
std::shared_ptr<StatsPullerManager> mStatsPullerManager;
@@ -103,7 +103,7 @@ private:
// TODO: Add a lock to mPastBuckets.
std::unordered_map<HashableDimensionKey, std::vector<ValueBucket>> mPastBuckets;
- long get_value(const LogEvent& event);
+ std::shared_ptr<FieldValueMap> getValueFields(const LogEvent& event);
// Util function to check whether the specified dimension hits the guardrail.
bool hitGuardRailLocked(const HashableDimensionKey& newKey);
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 9192d12fa982..842581ed1a9f 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -60,12 +60,12 @@ struct DurationBucket {
class DurationTracker {
public:
- DurationTracker(const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
+ DurationTracker(const ConfigKey& key, const int64_t& id, const HashableDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
: mConfigKey(key),
- mName(name),
+ mTrackerId(id),
mEventKey(eventKey),
mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
@@ -145,7 +145,7 @@ protected:
// A reference to the DurationMetricProducer's config key.
const ConfigKey& mConfigKey;
- const std::string mName;
+ const int64_t mTrackerId;
HashableDimensionKey mEventKey;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index d8a8e238fa5c..94f98ada7014 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -24,12 +24,12 @@ namespace android {
namespace os {
namespace statsd {
-MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const string& name,
+MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
const HashableDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
- : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
+ : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
bucketSizeNs, anomalyTrackers) {
}
@@ -42,12 +42,13 @@ bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// 1. Report the tuple count if the tuple count > soft limit
if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mInfos.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey.toString(),
- newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(
+ mConfigKey, hashDimensionsValue(mTrackerId, mEventKey.getDimensionsValue()),
+ newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("MaxDurTracker %s dropping data for dimension key %s", mName.c_str(),
- newKey.c_str());
+ ALOGE("MaxDurTracker %lld dropping data for dimension key %s",
+ (long long)mTrackerId, newKey.c_str());
return true;
}
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index 76f486e0c713..68c48cb10a4d 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -28,7 +28,7 @@ namespace statsd {
// they stop or bucket expires.
class MaxDurationTracker : public DurationTracker {
public:
- MaxDurationTracker(const ConfigKey& key, const string& name,
+ MaxDurationTracker(const ConfigKey& key, const int64_t& id,
const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index c347d5ca0f8b..c77d0b70507b 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -25,11 +25,11 @@ namespace statsd {
using std::pair;
OringDurationTracker::OringDurationTracker(
- const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
+ const ConfigKey& key, const int64_t& id, const HashableDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs, const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
- : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
+ : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
bucketSizeNs, anomalyTrackers),
mStarted(),
mPaused() {
@@ -44,12 +44,13 @@ bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
}
if (mConditionKeyMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mConditionKeyMap.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey.toString(),
- newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(
+ mConfigKey, hashDimensionsValue(mTrackerId, mEventKey.getDimensionsValue()),
+ newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("OringDurTracker %s dropping data for dimension key %s", mName.c_str(),
- newKey.c_str());
+ ALOGE("OringDurTracker %lld dropping data for dimension key %s",
+ (long long)mTrackerId, newKey.c_str());
return true;
}
}
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index dcf04dbcc8af..7fe649c436e2 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -27,7 +27,7 @@ namespace statsd {
// Tracks the "Or'd" duration -- if 2 durations are overlapping, they won't be double counted.
class OringDurationTracker : public DurationTracker {
public:
- OringDurationTracker(const ConfigKey& key, const string& name,
+ OringDurationTracker(const ConfigKey& key, const int64_t& id,
const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 97dbf7a4f7a1..89d54c7bc7ee 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -38,21 +38,21 @@ namespace android {
namespace os {
namespace statsd {
-bool handleMetricWithLogTrackers(const string what, const int metricIndex,
+bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex,
const bool usedForDimension,
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
- const unordered_map<string, int>& logTrackerMap,
+ const unordered_map<int64_t, int>& logTrackerMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
int& logTrackerIndex) {
auto logTrackerIt = logTrackerMap.find(what);
if (logTrackerIt == logTrackerMap.end()) {
- ALOGW("cannot find the AtomMatcher \"%s\" in config", what.c_str());
+ ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)what);
return false;
}
if (usedForDimension && allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) {
- ALOGE("AtomMatcher \"%s\" has more than one tag ids. When a metric has dimension, "
+ ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, "
"the \"what\" can only about one atom type.",
- what.c_str());
+ (long long)what);
return false;
}
logTrackerIndex = logTrackerIt->second;
@@ -62,22 +62,22 @@ bool handleMetricWithLogTrackers(const string what, const int metricIndex,
}
bool handleMetricWithConditions(
- const string condition, const int metricIndex,
- const unordered_map<string, int>& conditionTrackerMap,
+ const int64_t condition, const int metricIndex,
+ const unordered_map<int64_t, int>& conditionTrackerMap,
const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>&
links,
vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
unordered_map<int, std::vector<int>>& conditionToMetricMap) {
auto condition_it = conditionTrackerMap.find(condition);
if (condition_it == conditionTrackerMap.end()) {
- ALOGW("cannot find Predicate \"%s\" in the config", condition.c_str());
+ ALOGW("cannot find Predicate \"%lld\" in the config", (long long)condition);
return false;
}
for (const auto& link : links) {
auto it = conditionTrackerMap.find(link.condition());
if (it == conditionTrackerMap.end()) {
- ALOGW("cannot find Predicate \"%s\" in the config", link.condition().c_str());
+ ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition());
return false;
}
allConditionTrackers[condition_it->second]->setSliced(true);
@@ -93,7 +93,7 @@ bool handleMetricWithConditions(
}
bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
- unordered_map<string, int>& logTrackerMap,
+ unordered_map<int64_t, int>& logTrackerMap,
vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
vector<AtomMatcher> matcherConfigs;
const int atomMatcherCount = config.atom_matcher_size();
@@ -107,22 +107,22 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
switch (logMatcher.contents_case()) {
case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
allAtomMatchers.push_back(new SimpleLogMatchingTracker(
- logMatcher.name(), index, logMatcher.simple_atom_matcher(), uidMap));
+ logMatcher.id(), index, logMatcher.simple_atom_matcher(), uidMap));
break;
case AtomMatcher::ContentsCase::kCombination:
allAtomMatchers.push_back(
- new CombinationLogMatchingTracker(logMatcher.name(), index));
+ new CombinationLogMatchingTracker(logMatcher.id(), index));
break;
default:
- ALOGE("Matcher \"%s\" malformed", logMatcher.name().c_str());
+ ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
return false;
// continue;
}
- if (logTrackerMap.find(logMatcher.name()) != logTrackerMap.end()) {
+ if (logTrackerMap.find(logMatcher.id()) != logTrackerMap.end()) {
ALOGE("Duplicate AtomMatcher found!");
return false;
}
- logTrackerMap[logMatcher.name()] = index;
+ logTrackerMap[logMatcher.id()] = index;
matcherConfigs.push_back(logMatcher);
}
@@ -139,8 +139,8 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
}
bool initConditions(const ConfigKey& key, const StatsdConfig& config,
- const unordered_map<string, int>& logTrackerMap,
- unordered_map<string, int>& conditionTrackerMap,
+ const unordered_map<int64_t, int>& logTrackerMap,
+ unordered_map<int64_t, int>& conditionTrackerMap,
vector<sp<ConditionTracker>>& allConditionTrackers,
unordered_map<int, std::vector<int>>& trackerToConditionMap) {
vector<Predicate> conditionConfigs;
@@ -154,23 +154,23 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
switch (condition.contents_case()) {
case Predicate::ContentsCase::kSimplePredicate: {
allConditionTrackers.push_back(new SimpleConditionTracker(
- key, condition.name(), index, condition.simple_predicate(), logTrackerMap));
+ key, condition.id(), index, condition.simple_predicate(), logTrackerMap));
break;
}
case Predicate::ContentsCase::kCombination: {
allConditionTrackers.push_back(
- new CombinationConditionTracker(condition.name(), index));
+ new CombinationConditionTracker(condition.id(), index));
break;
}
default:
- ALOGE("Predicate \"%s\" malformed", condition.name().c_str());
+ ALOGE("Predicate \"%lld\" malformed", (long long)condition.id());
return false;
}
- if (conditionTrackerMap.find(condition.name()) != conditionTrackerMap.end()) {
+ if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
ALOGE("Duplicate Predicate found!");
return false;
}
- conditionTrackerMap[condition.name()] = index;
+ conditionTrackerMap[condition.id()] = index;
conditionConfigs.push_back(condition);
}
@@ -190,14 +190,15 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
}
bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
- const unordered_map<string, int>& logTrackerMap,
- const unordered_map<string, int>& conditionTrackerMap,
+ const unordered_map<int64_t, int>& logTrackerMap,
+ const unordered_map<int64_t, int>& conditionTrackerMap,
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
- unordered_map<string, int>& metricMap) {
+ unordered_map<int64_t, int>& metricMap,
+ std::set<int64_t> &noReportMetricIds) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
config.event_metric_size() + config.value_metric_size();
@@ -219,12 +220,12 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti
for (int i = 0; i < config.count_metric_size(); i++) {
const CountMetric& metric = config.count_metric(i);
if (!metric.has_what()) {
- ALOGW("cannot find \"what\" in CountMetric \"%s\"", metric.name().c_str());
+ ALOGW("cannot find \"what\" in CountMetric \"%lld\"", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
- metricMap.insert({metric.name(), metricIndex});
+ metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.has_dimensions(),
allAtomMatchers, logTrackerMap, trackerToMetricMap,
@@ -256,7 +257,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti
for (int i = 0; i < config.duration_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const DurationMetric& metric = config.duration_metric(i);
- metricMap.insert({metric.name(), metricIndex});
+ metricMap.insert({metric.id(), metricIndex});
auto what_it = conditionTrackerMap.find(metric.what());
if (what_it == conditionTrackerMap.end()) {
@@ -327,8 +328,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti
for (int i = 0; i < config.event_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const EventMetric& metric = config.event_metric(i);
- metricMap.insert({metric.name(), metricIndex});
- if (!metric.has_name() || !metric.has_what()) {
+ metricMap.insert({metric.id(), metricIndex});
+ if (!metric.has_id() || !metric.has_what()) {
ALOGW("cannot find the metric name or what in config");
return false;
}
@@ -363,12 +364,12 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti
for (int i = 0; i < config.value_metric_size(); i++) {
const ValueMetric& metric = config.value_metric(i);
if (!metric.has_what()) {
- ALOGW("cannot find \"what\" in ValueMetric \"%s\"", metric.name().c_str());
+ ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
- metricMap.insert({metric.name(), metricIndex});
+ metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.has_dimensions(),
allAtomMatchers, logTrackerMap, trackerToMetricMap,
@@ -408,25 +409,25 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti
for (int i = 0; i < config.gauge_metric_size(); i++) {
const GaugeMetric& metric = config.gauge_metric(i);
if (!metric.has_what()) {
- ALOGW("cannot find \"what\" in GaugeMetric \"%s\"", metric.name().c_str());
+ ALOGW("cannot find \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
return false;
}
if ((!metric.gauge_fields_filter().has_include_all() ||
(metric.gauge_fields_filter().include_all() == false)) &&
!hasLeafNode(metric.gauge_fields_filter().fields())) {
- ALOGW("Incorrect field filter setting in GaugeMetric %s", metric.name().c_str());
+ ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
return false;
}
if ((metric.gauge_fields_filter().has_include_all() &&
metric.gauge_fields_filter().include_all() == true) &&
hasLeafNode(metric.gauge_fields_filter().fields())) {
- ALOGW("Incorrect field filter setting in GaugeMetric %s", metric.name().c_str());
+ ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
- metricMap.insert({metric.name(), metricIndex});
+ metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.has_dimensions(),
allAtomMatchers, logTrackerMap, trackerToMetricMap,
@@ -461,49 +462,77 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti
key, metric, conditionIndex, wizard, pullTagId, atomTagId, startTimeNs);
allMetricProducers.push_back(gaugeProducer);
}
+ for (int i = 0; i < config.no_report_metric_size(); ++i) {
+ const auto no_report_metric = config.no_report_metric(i);
+ if (metricMap.find(no_report_metric) == metricMap.end()) {
+ ALOGW("no_report_metric %lld not exist", no_report_metric);
+ return false;
+ }
+ noReportMetricIds.insert(no_report_metric);
+ }
return true;
}
bool initAlerts(const StatsdConfig& config,
- const unordered_map<string, int>& metricProducerMap,
+ const unordered_map<int64_t, int>& metricProducerMap,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
+ unordered_map<int64_t, int> anomalyTrackerMap;
for (int i = 0; i < config.alert_size(); i++) {
const Alert& alert = config.alert(i);
- const auto& itr = metricProducerMap.find(alert.metric_name());
+ const auto& itr = metricProducerMap.find(alert.metric_id());
if (itr == metricProducerMap.end()) {
- ALOGW("alert \"%s\" has unknown metric name: \"%s\"", alert.name().c_str(),
- alert.metric_name().c_str());
+ ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
+ (long long)alert.metric_id());
return false;
}
- if (alert.trigger_if_sum_gt() < 0 || alert.number_of_buckets() <= 0) {
- ALOGW("invalid alert: threshold=%lld num_buckets= %d",
- alert.trigger_if_sum_gt(), alert.number_of_buckets());
+ if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
+ ALOGW("invalid alert: threshold=%f num_buckets= %d",
+ alert.trigger_if_sum_gt(), alert.num_buckets());
return false;
}
const int metricIndex = itr->second;
sp<MetricProducer> metric = allMetricProducers[metricIndex];
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert);
if (anomalyTracker != nullptr) {
+ anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
allAnomalyTrackers.push_back(anomalyTracker);
}
}
+ for (int i = 0; i < config.subscription_size(); ++i) {
+ const Subscription& subscription = config.subscription(i);
+ if (subscription.subscriber_information_case() ==
+ Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
+ ALOGW("subscription \"%lld\" has no subscriber info.\"",
+ (long long)subscription.id());
+ return false;
+ }
+ const auto& itr = anomalyTrackerMap.find(subscription.rule_id());
+ if (itr == anomalyTrackerMap.end()) {
+ ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
+ (long long)subscription.id(), (long long)subscription.rule_id());
+ return false;
+ }
+ const int anomalyTrackerIndex = itr->second;
+ allAnomalyTrackers[anomalyTrackerIndex]->addSubscription(subscription);
+ }
return true;
}
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
- const UidMap& uidMap,
- const long timeBaseSec, set<int>& allTagIds,
+ const UidMap& uidMap,
+ const long timeBaseSec, set<int>& allTagIds,
vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
- unordered_map<int, std::vector<int>>& trackerToConditionMap) {
- unordered_map<string, int> logTrackerMap;
- unordered_map<string, int> conditionTrackerMap;
- unordered_map<string, int> metricProducerMap;
+ unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ std::set<int64_t> &noReportMetricIds) {
+ unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> conditionTrackerMap;
+ unordered_map<int64_t, int> metricProducerMap;
if (!initLogTrackers(config, uidMap, logTrackerMap, allAtomMatchers, allTagIds)) {
ALOGE("initLogMatchingTrackers failed");
@@ -519,7 +548,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
if (!initMetrics(key, config, timeBaseSec, logTrackerMap, conditionTrackerMap, allAtomMatchers,
allConditionTrackers, allMetricProducers, conditionToMetricMap,
- trackerToMetricMap, metricProducerMap)) {
+ trackerToMetricMap, metricProducerMap, noReportMetricIds)) {
ALOGE("initMetricProducers failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 9ad5176ee6fd..4f19ada5b022 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -43,8 +43,8 @@ namespace statsd {
// [allAtomMatchers]: should store the sp to all the LogMatchingTracker
// [allTagIds]: contains the set of all interesting tag ids to this config.
bool initLogTrackers(const StatsdConfig& config,
- const UidMap& uidMap,
- std::unordered_map<std::string, int>& logTrackerMap,
+ const UidMap& uidMap,
+ std::unordered_map<int64_t, int>& logTrackerMap,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::set<int>& allTagIds);
@@ -59,8 +59,8 @@ bool initLogTrackers(const StatsdConfig& config,
// [trackerToConditionMap]: contain the mapping from index of
// log tracker to condition trackers that use the log tracker
bool initConditions(const ConfigKey& key, const StatsdConfig& config,
- const std::unordered_map<std::string, int>& logTrackerMap,
- std::unordered_map<std::string, int>& conditionTrackerMap,
+ const std::unordered_map<int64_t, int>& logTrackerMap,
+ std::unordered_map<int64_t, int>& conditionTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks);
@@ -79,28 +79,29 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
// [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
bool initMetrics(
const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
- const std::unordered_map<std::string, int>& logTrackerMap,
- const std::unordered_map<std::string, int>& conditionTrackerMap,
+ const std::unordered_map<int64_t, int>& logTrackerMap,
+ const std::unordered_map<int64_t, int>& conditionTrackerMap,
const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
- std::unordered_map<int, std::vector<int>>& trackerToMetricMap);
+ std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
+ std::set<int64_t> &noReportMetricIds);
// Initialize MetricsManager from StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
-
- const UidMap& uidMap,
- const long timeBaseSec, std::set<int>& allTagIds,
+ const UidMap& uidMap,
+ const long timeBaseSec, std::set<int>& allTagIds,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
- std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
+ std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ std::set<int64_t> &noReportMetricIds);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 416b87b36c54..517d21d6dcce 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -402,6 +402,79 @@ set<int32_t> UidMap::getAppUid(const string& package) const {
return results;
}
+// Note not all the following AIDs are used as uids. Some are used only for gids.
+// It's ok to leave them in the map, but we won't ever see them in the log's uid field.
+// App's uid starts from 10000, and will not overlap with the following AIDs.
+const std::map<string, uint32_t> UidMap::sAidToUidMapping = {{"AID_ROOT", 0},
+ {"AID_SYSTEM", 1000},
+ {"AID_RADIO", 1001},
+ {"AID_BLUETOOTH", 1002},
+ {"AID_GRAPHICS", 1003},
+ {"AID_INPUT", 1004},
+ {"AID_AUDIO", 1005},
+ {"AID_CAMERA", 1006},
+ {"AID_LOG", 1007},
+ {"AID_COMPASS", 1008},
+ {"AID_MOUNT", 1009},
+ {"AID_WIFI", 1010},
+ {"AID_ADB", 1011},
+ {"AID_INSTALL", 1012},
+ {"AID_MEDIA", 1013},
+ {"AID_DHCP", 1014},
+ {"AID_SDCARD_RW", 1015},
+ {"AID_VPN", 1016},
+ {"AID_KEYSTORE", 1017},
+ {"AID_USB", 1018},
+ {"AID_DRM", 1019},
+ {"AID_MDNSR", 1020},
+ {"AID_GPS", 1021},
+ // {"AID_UNUSED1", 1022},
+ {"AID_MEDIA_RW", 1023},
+ {"AID_MTP", 1024},
+ // {"AID_UNUSED2", 1025},
+ {"AID_DRMRPC", 1026},
+ {"AID_NFC", 1027},
+ {"AID_SDCARD_R", 1028},
+ {"AID_CLAT", 1029},
+ {"AID_LOOP_RADIO", 1030},
+ {"AID_MEDIA_DRM", 1031},
+ {"AID_PACKAGE_INFO", 1032},
+ {"AID_SDCARD_PICS", 1033},
+ {"AID_SDCARD_AV", 1034},
+ {"AID_SDCARD_ALL", 1035},
+ {"AID_LOGD", 1036},
+ {"AID_SHARED_RELRO", 1037},
+ {"AID_DBUS", 1038},
+ {"AID_TLSDATE", 1039},
+ {"AID_MEDIA_EX", 1040},
+ {"AID_AUDIOSERVER", 1041},
+ {"AID_METRICS_COLL", 1042},
+ {"AID_METRICSD", 1043},
+ {"AID_WEBSERV", 1044},
+ {"AID_DEBUGGERD", 1045},
+ {"AID_MEDIA_CODEC", 1046},
+ {"AID_CAMERASERVER", 1047},
+ {"AID_FIREWALL", 1048},
+ {"AID_TRUNKS", 1049},
+ {"AID_NVRAM", 1050},
+ {"AID_DNS", 1051},
+ {"AID_DNS_TETHER", 1052},
+ {"AID_WEBVIEW_ZYGOTE", 1053},
+ {"AID_VEHICLE_NETWORK", 1054},
+ {"AID_MEDIA_AUDIO", 1055},
+ {"AID_MEDIA_VIDEO", 1056},
+ {"AID_MEDIA_IMAGE", 1057},
+ {"AID_TOMBSTONED", 1058},
+ {"AID_MEDIA_OBB", 1059},
+ {"AID_ESE", 1060},
+ {"AID_OTA_UPDATE", 1061},
+ {"AID_AUTOMOTIVE_EVS", 1062},
+ {"AID_LOWPAN", 1063},
+ {"AID_HSM", 1064},
+ {"AID_SHELL", 2000},
+ {"AID_CACHE", 2001},
+ {"AID_DIAG", 2002}};
+
} // namespace statsd
} // namespace os
} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 02dea54f1b50..07e13e02498c 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -51,7 +51,7 @@ class UidMap : public virtual android::RefBase {
public:
UidMap();
~UidMap();
-
+ static const std::map<std::string, uint32_t> sAidToUidMapping;
/*
* All three inputs must be the same size, and the jth element in each array refers to the same
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index f5282eaaecd4..0b369bb2fdbc 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -137,7 +137,7 @@ message UidMapping {
}
message StatsLogReport {
- optional string metric_name = 1;
+ optional int64 metric_id = 1;
optional int64 start_report_nanos = 2;
@@ -178,7 +178,7 @@ message ConfigMetricsReport {
message ConfigMetricsReportList {
message ConfigKey {
optional int32 uid = 1;
- optional string name = 2;
+ optional int64 id = 2;
}
optional ConfigKey config_key = 1;
@@ -191,28 +191,28 @@ message StatsdStatsReport {
optional int32 stats_end_time_sec = 2;
message MatcherStats {
- optional string name = 1;
+ optional int64 id = 1;
optional int32 matched_times = 2;
}
message ConditionStats {
- optional string name = 1;
+ optional int64 id = 1;
optional int32 max_tuple_counts = 2;
}
message MetricStats {
- optional string name = 1;
+ optional int64 id = 1;
optional int32 max_tuple_counts = 2;
}
message AlertStats {
- optional string name = 1;
+ optional int64 id = 1;
optional int32 alerted_times = 2;
}
message ConfigStats {
optional int32 uid = 1;
- optional string name = 2;
+ optional int64 id = 2;
optional int32 creation_time_sec = 3;
optional int32 deletion_time_sec = 4;
optional int32 metric_count = 5;
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index e46b8ebe0021..160b1f40243f 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -32,7 +32,7 @@ const HashableDimensionKey DEFAULT_DIMENSION_KEY = HashableDimensionKey();
// Minimum bucket size in seconds
const long kMinBucketSizeSec = 5 * 60;
-typedef std::map<std::string, std::vector<HashableDimensionKey>> ConditionKey;
+typedef std::map<int64_t, std::vector<HashableDimensionKey>> ConditionKey;
typedef std::unordered_map<HashableDimensionKey, int64_t> DimToValMap;
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 1ed1e05ba272..1e0a437f30c2 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -84,12 +84,12 @@ message SimpleAtomMatcher {
}
message AtomMatcher {
- optional string name = 1;
+ optional int64 id = 1;
message Combination {
optional LogicalOperation operation = 1;
- repeated string matcher = 2;
+ repeated int64 matcher = 2;
}
oneof contents {
SimpleAtomMatcher simple_atom_matcher = 2;
@@ -98,13 +98,13 @@ message AtomMatcher {
}
message SimplePredicate {
- optional string start = 1;
+ optional int64 start = 1;
- optional string stop = 2;
+ optional int64 stop = 2;
optional bool count_nesting = 3 [default = true];
- optional string stop_all = 4;
+ optional int64 stop_all = 4;
enum InitialValue {
UNKNOWN = 0;
@@ -116,12 +116,12 @@ message SimplePredicate {
}
message Predicate {
- optional string name = 1;
+ optional int64 id = 1;
message Combination {
optional LogicalOperation operation = 1;
- repeated string predicate = 2;
+ repeated int64 predicate = 2;
}
oneof contents {
@@ -135,7 +135,7 @@ message Bucket {
}
message MetricConditionLink {
- optional string condition = 1;
+ optional int64 condition = 1;
optional FieldMatcher dimensions_in_what = 2;
@@ -148,21 +148,21 @@ message FieldFilter {
}
message EventMetric {
- optional string name = 1;
+ optional int64 id = 1;
- optional string what = 2;
+ optional int64 what = 2;
- optional string condition = 3;
+ optional int64 condition = 3;
repeated MetricConditionLink links = 4;
}
message CountMetric {
- optional string name = 1;
+ optional int64 id = 1;
- optional string what = 2;
+ optional int64 what = 2;
- optional string condition = 3;
+ optional int64 condition = 3;
optional FieldMatcher dimensions = 4;
@@ -172,11 +172,11 @@ message CountMetric {
}
message DurationMetric {
- optional string name = 1;
+ optional int64 id = 1;
- optional string what = 2;
+ optional int64 what = 2;
- optional string condition = 3;
+ optional int64 condition = 3;
repeated MetricConditionLink links = 4;
@@ -193,13 +193,13 @@ message DurationMetric {
}
message GaugeMetric {
- optional string name = 1;
+ optional int64 id = 1;
- optional string what = 2;
+ optional int64 what = 2;
optional FieldFilter gauge_fields_filter = 3;
- optional string condition = 4;
+ optional int64 condition = 4;
optional FieldMatcher dimensions = 5;
@@ -209,13 +209,13 @@ message GaugeMetric {
}
message ValueMetric {
- optional string name = 1;
+ optional int64 id = 1;
- optional string what = 2;
+ optional int64 what = 2;
- optional int32 value_field = 3;
+ optional FieldMatcher value_field = 3;
- optional string condition = 4;
+ optional int64 condition = 4;
optional FieldMatcher dimensions = 5;
@@ -228,29 +228,51 @@ message ValueMetric {
}
message Alert {
- optional string name = 1;
+ optional int64 id = 1;
- optional string metric_name = 2;
+ optional int64 metric_id = 2;
- message IncidentdDetails {
- repeated int32 section = 1;
- }
- optional IncidentdDetails incidentd_details = 3;
+ optional int32 num_buckets = 3;
+
+ optional int32 refractory_period_secs = 4;
- optional int32 number_of_buckets = 4;
+ optional double trigger_if_sum_gt = 5;
+}
- optional int32 refractory_period_secs = 5;
+message Alarm {
+ optional int64 id = 1;
+ optional int64 offset_millis = 2;
+ optional int64 period_millis = 3;
+}
- optional int64 trigger_if_sum_gt = 6;
+message IncidentdDetails {
+ repeated int32 section = 1;
}
-message AllowedLogSource {
- repeated int32 uid = 1;
- repeated string package = 2;
+message PerfettoDetails {
+ optional int32 perfetto_stuff = 1;
+}
+
+message Subscription {
+ optional int64 id = 1;
+
+ enum RuleType {
+ RULE_TYPE_UNSPECIFIED = 0;
+ ALARM = 1;
+ ALERT = 2;
+ }
+ optional RuleType rule_type = 2;
+
+ optional int64 rule_id = 3;
+
+ oneof subscriber_information {
+ IncidentdDetails incidentd_details = 4;
+ PerfettoDetails perfetto_details = 5;
+ }
}
message StatsdConfig {
- optional string name = 1;
+ optional int64 id = 1;
repeated EventMetric event_metric = 2;
@@ -268,5 +290,11 @@ message StatsdConfig {
repeated Alert alert = 9;
- optional AllowedLogSource log_source = 10;
+ repeated Alarm alarm = 10;
+
+ repeated Subscription subscription = 11;
+
+ repeated string allowed_log_source = 12;
+
+ repeated int64 no_report_metric = 13;
}
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 9919abf7532a..c542db2312ea 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -124,7 +124,7 @@ void StorageManager::sendBroadcast(const char* path,
}
if (index < 2) continue;
- sendBroadcast(ConfigKey(uid, configName));
+ sendBroadcast(ConfigKey(uid, StrToInt64(configName)));
}
}
@@ -198,6 +198,7 @@ void StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap
index++;
}
if (index < 2) continue;
+
string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
VLOG("full file %s", file_name.c_str());
int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
@@ -206,7 +207,7 @@ void StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap
if (android::base::ReadFdToString(fd, &content)) {
StatsdConfig config;
if (config.ParseFromString(content)) {
- configsMap[ConfigKey(uid, configName)] = config;
+ configsMap[ConfigKey(uid, StrToInt64(configName))] = config;
VLOG("map key uid=%d|name=%s", uid, name);
}
}
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 3d923e246e71..3eac5d213c22 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -14,6 +14,7 @@
#include "src/config/ConfigManager.h"
#include "src/metrics/MetricsManager.h"
+#include "statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -31,7 +32,7 @@ namespace os {
namespace statsd {
static ostream& operator<<(ostream& os, const StatsdConfig& config) {
- return os << "StatsdConfig{name=" << config.name().c_str() << "}";
+ return os << "StatsdConfig{id=" << config.id() << "}";
}
} // namespace statsd
@@ -50,19 +51,21 @@ public:
/**
* Validate that the ConfigKey is the one we wanted.
*/
-MATCHER_P2(ConfigKeyEq, uid, name, "") {
- return arg.GetUid() == uid && arg.GetName() == name;
+MATCHER_P2(ConfigKeyEq, uid, id, "") {
+ return arg.GetUid() == uid && (long long)arg.GetId() == (long long)id;
}
/**
* Validate that the StatsdConfig is the one we wanted.
*/
-MATCHER_P(StatsdConfigEq, name, "") {
- return arg.name() == name;
+MATCHER_P(StatsdConfigEq, id, 0) {
+ return (long long)arg.id() == (long long)id;
}
+const int64_t testConfigId = 12345;
+
TEST(ConfigManagerTest, TestFakeConfig) {
- auto metricsManager = std::make_unique<MetricsManager>(ConfigKey(0, "test"),
+ auto metricsManager = std::make_unique<MetricsManager>(ConfigKey(0, testConfigId),
build_fake_config(), 1000, new UidMap());
EXPECT_TRUE(metricsManager->isConfigValid());
}
@@ -77,13 +80,13 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) {
manager->AddListener(listener);
StatsdConfig config91;
- config91.set_name("91");
+ config91.set_id(91);
StatsdConfig config92;
- config92.set_name("92");
+ config92.set_id(92);
StatsdConfig config93;
- config93.set_name("93");
+ config93.set_id(93);
StatsdConfig config94;
- config94.set_name("94");
+ config94.set_id(94);
{
InSequence s;
@@ -91,42 +94,46 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) {
manager->Startup();
// Add another one
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq("91")))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+ StatsdConfigEq(91)))
.RetiresOnSaturation();
- manager->UpdateConfig(ConfigKey(1, "zzz"), config91);
+ manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91);
// Update It
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq("92")))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+ StatsdConfigEq(92)))
.RetiresOnSaturation();
- manager->UpdateConfig(ConfigKey(1, "zzz"), config92);
+ manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92);
// Add one with the same uid but a different name
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "yyy"), StatsdConfigEq("93")))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("yyy")),
+ StatsdConfigEq(93)))
.RetiresOnSaturation();
- manager->UpdateConfig(ConfigKey(1, "yyy"), config93);
+ manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93);
// Add one with the same name but a different uid
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, "zzz"), StatsdConfigEq("94")))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, StringToId("zzz")),
+ StatsdConfigEq(94)))
.RetiresOnSaturation();
- manager->UpdateConfig(ConfigKey(2, "zzz"), config94);
+ manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94);
// Remove (1,yyy)
- EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "yyy")))
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, StringToId("yyy"))))
.RetiresOnSaturation();
- manager->RemoveConfig(ConfigKey(1, "yyy"));
+ manager->RemoveConfig(ConfigKey(1, StringToId("yyy")));
// Remove (2,zzz)
- EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")))
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))))
.RetiresOnSaturation();
- manager->RemoveConfig(ConfigKey(2, "zzz"));
+ manager->RemoveConfig(ConfigKey(2, StringToId("zzz")));
// Remove (1,zzz)
- EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "zzz")))
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, StringToId("zzz"))))
.RetiresOnSaturation();
- manager->RemoveConfig(ConfigKey(1, "zzz"));
+ manager->RemoveConfig(ConfigKey(1, StringToId("zzz")));
// Remove (2,zzz) again and we shouldn't get the callback
- manager->RemoveConfig(ConfigKey(2, "zzz"));
+ manager->RemoveConfig(ConfigKey(2, StringToId("zzz")));
}
}
@@ -142,16 +149,16 @@ TEST(ConfigManagerTest, TestRemoveUid) {
StatsdConfig config;
EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _)).Times(5);
- EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "xxx")));
- EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "yyy")));
- EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")));
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx"))));
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy"))));
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))));
manager->Startup();
- manager->UpdateConfig(ConfigKey(1, "aaa"), config);
- manager->UpdateConfig(ConfigKey(2, "xxx"), config);
- manager->UpdateConfig(ConfigKey(2, "yyy"), config);
- manager->UpdateConfig(ConfigKey(2, "zzz"), config);
- manager->UpdateConfig(ConfigKey(3, "bbb"), config);
+ manager->UpdateConfig(ConfigKey(1, StringToId("aaa")), config);
+ manager->UpdateConfig(ConfigKey(2, StringToId("xxx")), config);
+ manager->UpdateConfig(ConfigKey(2, StringToId("yyy")), config);
+ manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config);
+ manager->UpdateConfig(ConfigKey(3, StringToId("bbb")), config);
manager->RemoveConfigs(2);
}
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 6cd31dd100c8..cb212a76a1dd 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -21,6 +21,7 @@
#include "src/metrics/MetricProducer.h"
#include "src/metrics/ValueMetricProducer.h"
#include "src/metrics/metrics_manager_util.h"
+#include "statsd_test_util.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -40,16 +41,16 @@ using android::os::statsd::Predicate;
// TODO: ADD MORE TEST CASES.
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
const long timeBaseSec = 1000;
StatsdConfig buildGoodConfig() {
StatsdConfig config;
- config.set_name("12345");
+ config.set_id(12345);
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_IS_ON");
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -59,7 +60,7 @@ StatsdConfig buildGoodConfig() {
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_IS_OFF");
+ eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -69,24 +70,26 @@ StatsdConfig buildGoodConfig() {
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_ON_OR_OFF");
+ eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
- combination->add_matcher("SCREEN_IS_ON");
- combination->add_matcher("SCREEN_IS_OFF");
+ combination->add_matcher(StringToId("SCREEN_IS_ON"));
+ combination->add_matcher(StringToId("SCREEN_IS_OFF"));
CountMetric* metric = config.add_count_metric();
- metric->set_name("3");
- metric->set_what("SCREEN_IS_ON");
+ metric->set_id(3);
+ metric->set_what(StringToId("SCREEN_IS_ON"));
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
metric->mutable_dimensions()->set_field(2 /*SCREEN_STATE_CHANGE*/);
metric->mutable_dimensions()->add_child()->set_field(1);
+ config.add_no_report_metric(3);
+
auto alert = config.add_alert();
- alert->set_name("3");
- alert->set_metric_name("3");
- alert->set_number_of_buckets(10);
+ alert->set_id(3);
+ alert->set_metric_id(3);
+ alert->set_num_buckets(10);
alert->set_refractory_period_secs(100);
alert->set_trigger_if_sum_gt(100);
return config;
@@ -94,10 +97,10 @@ StatsdConfig buildGoodConfig() {
StatsdConfig buildCircleMatchers() {
StatsdConfig config;
- config.set_name("12345");
+ config.set_id(12345);
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_IS_ON");
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -107,35 +110,35 @@ StatsdConfig buildCircleMatchers() {
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_ON_OR_OFF");
+ eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
- combination->add_matcher("SCREEN_IS_ON");
+ combination->add_matcher(StringToId("SCREEN_IS_ON"));
// Circle dependency
- combination->add_matcher("SCREEN_ON_OR_OFF");
+ combination->add_matcher(StringToId("SCREEN_ON_OR_OFF"));
return config;
}
StatsdConfig buildAlertWithUnknownMetric() {
StatsdConfig config;
- config.set_name("12345");
+ config.set_id(12345);
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_IS_ON");
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
CountMetric* metric = config.add_count_metric();
- metric->set_name("3");
- metric->set_what("SCREEN_IS_ON");
+ metric->set_id(3);
+ metric->set_what(StringToId("SCREEN_IS_ON"));
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
metric->mutable_dimensions()->set_field(2 /*SCREEN_STATE_CHANGE*/);
metric->mutable_dimensions()->add_child()->set_field(1);
auto alert = config.add_alert();
- alert->set_name("3");
- alert->set_metric_name("2");
- alert->set_number_of_buckets(10);
+ alert->set_id(3);
+ alert->set_metric_id(2);
+ alert->set_num_buckets(10);
alert->set_refractory_period_secs(100);
alert->set_trigger_if_sum_gt(100);
return config;
@@ -143,10 +146,10 @@ StatsdConfig buildAlertWithUnknownMetric() {
StatsdConfig buildMissingMatchers() {
StatsdConfig config;
- config.set_name("12345");
+ config.set_id(12345);
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_IS_ON");
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -156,29 +159,29 @@ StatsdConfig buildMissingMatchers() {
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_ON_OR_OFF");
+ eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
- combination->add_matcher("SCREEN_IS_ON");
+ combination->add_matcher(StringToId("SCREEN_IS_ON"));
// undefined matcher
- combination->add_matcher("ABC");
+ combination->add_matcher(StringToId("ABC"));
return config;
}
StatsdConfig buildMissingPredicate() {
StatsdConfig config;
- config.set_name("12345");
+ config.set_id(12345);
CountMetric* metric = config.add_count_metric();
- metric->set_name("3");
- metric->set_what("SCREEN_EVENT");
+ metric->set_id(3);
+ metric->set_what(StringToId("SCREEN_EVENT"));
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
- metric->set_condition("SOME_CONDITION");
+ metric->set_condition(StringToId("SOME_CONDITION"));
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_EVENT");
+ eventMatcher->set_id(StringToId("SCREEN_EVENT"));
SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2);
@@ -188,38 +191,38 @@ StatsdConfig buildMissingPredicate() {
StatsdConfig buildDimensionMetricsWithMultiTags() {
StatsdConfig config;
- config.set_name("12345");
+ config.set_id(12345);
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("BATTERY_VERY_LOW");
+ eventMatcher->set_id(StringToId("BATTERY_VERY_LOW"));
SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("BATTERY_VERY_VERY_LOW");
+ eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW"));
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(3);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("BATTERY_LOW");
+ eventMatcher->set_id(StringToId("BATTERY_LOW"));
AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
combination->set_operation(LogicalOperation::OR);
- combination->add_matcher("BATTERY_VERY_LOW");
- combination->add_matcher("BATTERY_VERY_VERY_LOW");
+ combination->add_matcher(StringToId("BATTERY_VERY_LOW"));
+ combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW"));
// Count process state changes, slice by uid, while SCREEN_IS_OFF
CountMetric* metric = config.add_count_metric();
- metric->set_name("3");
- metric->set_what("BATTERY_LOW");
+ metric->set_id(3);
+ metric->set_what(StringToId("BATTERY_LOW"));
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
// This case is interesting. We want to dimension across two atoms.
metric->mutable_dimensions()->add_child()->set_field(1);
auto alert = config.add_alert();
- alert->set_name("3");
- alert->set_metric_name("3");
- alert->set_number_of_buckets(10);
+ alert->set_id(103);
+ alert->set_metric_id(3);
+ alert->set_num_buckets(10);
alert->set_refractory_period_secs(100);
alert->set_trigger_if_sum_gt(100);
return config;
@@ -227,10 +230,10 @@ StatsdConfig buildDimensionMetricsWithMultiTags() {
StatsdConfig buildCirclePredicates() {
StatsdConfig config;
- config.set_name("12345");
+ config.set_id(12345);
AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_IS_ON");
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -240,7 +243,7 @@ StatsdConfig buildCirclePredicates() {
2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
eventMatcher = config.add_atom_matcher();
- eventMatcher->set_name("SCREEN_IS_OFF");
+ eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -250,18 +253,18 @@ StatsdConfig buildCirclePredicates() {
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
auto condition = config.add_predicate();
- condition->set_name("SCREEN_IS_ON");
+ condition->set_id(StringToId("SCREEN_IS_ON"));
SimplePredicate* simplePredicate = condition->mutable_simple_predicate();
- simplePredicate->set_start("SCREEN_IS_ON");
- simplePredicate->set_stop("SCREEN_IS_OFF");
+ simplePredicate->set_start(StringToId("SCREEN_IS_ON"));
+ simplePredicate->set_stop(StringToId("SCREEN_IS_OFF"));
condition = config.add_predicate();
- condition->set_name("SCREEN_IS_EITHER_ON_OFF");
+ condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF"));
Predicate_Combination* combination = condition->mutable_combination();
combination->set_operation(LogicalOperation::OR);
- combination->add_predicate("SCREEN_IS_ON");
- combination->add_predicate("SCREEN_IS_EITHER_ON_OFF");
+ combination->add_predicate(StringToId("SCREEN_IS_ON"));
+ combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF"));
return config;
}
@@ -277,12 +280,15 @@ TEST(MetricsManagerTest, TestGoodConfig) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ std::set<int64_t> noReportMetricIds;
EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ noReportMetricIds));
EXPECT_EQ(1u, allMetricProducers.size());
EXPECT_EQ(1u, allAnomalyTrackers.size());
+ EXPECT_EQ(1u, noReportMetricIds.size());
}
TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
@@ -296,10 +302,12 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -313,10 +321,12 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -330,9 +340,11 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -346,9 +358,11 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -362,10 +376,12 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -379,10 +395,12 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ noReportMetricIds));
}
#else
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index a27bed552f9e..5d053e25003d 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -41,7 +41,7 @@ using android::util::ProtoOutputStream;
*/
class MockMetricsManager : public MetricsManager {
public:
- MockMetricsManager() : MetricsManager(ConfigKey(1, "key"), StatsdConfig(), 1000, new UidMap()) {
+ MockMetricsManager() : MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, new UidMap()) {
}
MOCK_METHOD0(byteSize, size_t());
@@ -56,7 +56,7 @@ TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
MockMetricsManager mockMetricsManager;
- ConfigKey key(100, "key");
+ ConfigKey key(100, 12345);
// Expect only the first flush to trigger a check for byte size since the last two are
// rate-limited.
EXPECT_CALL(mockMetricsManager, byteSize()).Times(1);
@@ -74,7 +74,7 @@ TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
MockMetricsManager mockMetricsManager;
- ConfigKey key(100, "key");
+ ConfigKey key(100, 12345);
EXPECT_CALL(mockMetricsManager, byteSize())
.Times(2)
.WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * .95)));
@@ -98,7 +98,7 @@ TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
MockMetricsManager mockMetricsManager;
- ConfigKey key(100, "key");
+ ConfigKey key(100, 12345);
EXPECT_CALL(mockMetricsManager, byteSize())
.Times(1)
.WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 8a394f75a0d0..945af2746eae 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -18,6 +18,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "statsd_test_util.h"
#include <gtest/gtest.h>
@@ -156,8 +157,8 @@ TEST(UidMapTest, TestUpdateApp) {
TEST(UidMapTest, TestClearingOutput) {
UidMap m;
- ConfigKey config1(1, "config1");
- ConfigKey config2(1, "config2");
+ ConfigKey config1(1, StringToId("config1"));
+ ConfigKey config2(1, StringToId("config2"));
m.OnConfigUpdated(config1);
@@ -211,7 +212,7 @@ TEST(UidMapTest, TestClearingOutput) {
TEST(UidMapTest, TestMemoryComputed) {
UidMap m;
- ConfigKey config1(1, "config1");
+ ConfigKey config1(1, StringToId("config1"));
m.OnConfigUpdated(config1);
size_t startBytes = m.mBytesUsed;
@@ -241,7 +242,7 @@ TEST(UidMapTest, TestMemoryGuardrail) {
UidMap m;
string buf;
- ConfigKey config1(1, "config1");
+ ConfigKey config1(1, StringToId("config1"));
m.OnConfigUpdated(config1);
size_t startBytes = m.mBytesUsed;
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index da872add6c0d..5842bc889f93 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -31,7 +31,7 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
HashableDimensionKey getMockDimensionKey(int key, string value) {
DimensionsValue dimensionsValue;
@@ -57,7 +57,7 @@ std::shared_ptr<DimToValMap> MockBucket(
TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
const int64_t bucketSizeNs = 30 * NS_PER_SEC;
Alert alert;
- alert.set_number_of_buckets(3);
+ alert.set_num_buckets(3);
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
@@ -177,7 +177,7 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
TEST(AnomalyTrackerTest, TestSparseBuckets) {
const int64_t bucketSizeNs = 30 * NS_PER_SEC;
Alert alert;
- alert.set_number_of_buckets(3);
+ alert.set_num_buckets(3);
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 705804fef560..819f2bebf327 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -11,7 +11,9 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+
#include "src/condition/SimpleConditionTracker.h"
+#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -29,7 +31,7 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
const int ATTRIBUTION_NODE_FIELD_ID = 1;
const int ATTRIBUTION_UID_FIELD_ID = 1;
@@ -38,9 +40,9 @@ const int TAG_ID = 1;
SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
bool outputSlicedUid, Position position) {
SimplePredicate simplePredicate;
- simplePredicate.set_start("WAKE_LOCK_ACQUIRE");
- simplePredicate.set_stop("WAKE_LOCK_RELEASE");
- simplePredicate.set_stop_all("RELEASE_ALL");
+ simplePredicate.set_start(StringToId("WAKE_LOCK_ACQUIRE"));
+ simplePredicate.set_stop(StringToId("WAKE_LOCK_RELEASE"));
+ simplePredicate.set_stop_all(StringToId("RELEASE_ALL"));
if (outputSlicedUid) {
simplePredicate.mutable_dimensions()->set_field(TAG_ID);
simplePredicate.mutable_dimensions()->add_child()->set_field(ATTRIBUTION_NODE_FIELD_ID);
@@ -73,10 +75,10 @@ void makeWakeLockEvent(
event->init();
}
-std::map<string, std::vector<HashableDimensionKey>> getWakeLockQueryKey(
+std::map<int64_t, std::vector<HashableDimensionKey>> getWakeLockQueryKey(
const Position position,
const std::vector<int> &uids, const string& conditionName) {
- std::map<string, std::vector<HashableDimensionKey>> outputKeyMap;
+ std::map<int64_t, std::vector<HashableDimensionKey>> outputKeyMap;
std::vector<int> uid_indexes;
switch(position) {
case Position::FIRST:
@@ -96,28 +98,29 @@ std::map<string, std::vector<HashableDimensionKey>> getWakeLockQueryKey(
for (const int idx : uid_indexes) {
DimensionsValue dimensionsValue;
dimensionsValue.set_field(TAG_ID);
- dimensionsValue.mutable_value_tuple()->add_dimensions_value()->set_field(ATTRIBUTION_NODE_FIELD_ID);
+ dimensionsValue.mutable_value_tuple()->add_dimensions_value()->set_field(
+ ATTRIBUTION_NODE_FIELD_ID);
dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)
->mutable_value_tuple()->add_dimensions_value()->set_field(ATTRIBUTION_NODE_FIELD_ID);
dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)
->mutable_value_tuple()->mutable_dimensions_value(0)->set_value_int(uids[idx]);
- outputKeyMap[conditionName].push_back(HashableDimensionKey(dimensionsValue));
+ outputKeyMap[StringToId(conditionName)].push_back(HashableDimensionKey(dimensionsValue));
}
return outputKeyMap;
}
TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
SimplePredicate simplePredicate;
- simplePredicate.set_start("SCREEN_TURNED_ON");
- simplePredicate.set_stop("SCREEN_TURNED_OFF");
+ simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
+ simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
simplePredicate.set_count_nesting(false);
simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
- unordered_map<string, int> trackerNameIndexMap;
- trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
- trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON", 0 /*tracker index*/,
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/,
simplePredicate, trackerNameIndexMap);
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -191,15 +194,15 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
SimplePredicate simplePredicate;
- simplePredicate.set_start("SCREEN_TURNED_ON");
- simplePredicate.set_stop("SCREEN_TURNED_OFF");
+ simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
+ simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
simplePredicate.set_count_nesting(true);
- unordered_map<string, int> trackerNameIndexMap;
- trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
- trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON",
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -267,12 +270,12 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
position);
string conditionName = "WL_HELD_BY_UID2";
- unordered_map<string, int> trackerNameIndexMap;
- trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
- trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
- trackerNameIndexMap["RELEASE_ALL"] = 2;
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+ trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
std::vector<int> uids = {111, 222, 333};
@@ -371,12 +374,12 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
Position::ANY /* position */);
string conditionName = "WL_HELD";
- unordered_map<string, int> trackerNameIndexMap;
- trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
- trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
- trackerNameIndexMap["RELEASE_ALL"] = 2;
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+ trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -461,12 +464,12 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
position);
string conditionName = "WL_HELD_BY_UID3";
- unordered_map<string, int> trackerNameIndexMap;
- trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
- trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
- trackerNameIndexMap["RELEASE_ALL"] = 2;
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+ trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index c747016161d3..b56b8176cceb 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -55,16 +55,16 @@ StatsdConfig CreateStatsdConfig() {
*config.add_predicate() = isInBackgroundPredicate;
auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_name("combinationPredicate");
+ combinationPredicate->set_id(StringToId("combinationPredicate"));
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
addPredicateToPredicateCombination(isInBackgroundPredicate, combinationPredicate);
auto countMetric = config.add_count_metric();
- countMetric->set_name("AppCrashes");
- countMetric->set_what(appCrashMatcher.name());
- countMetric->set_condition(combinationPredicate->name());
+ countMetric->set_id(StringToId("AppCrashes"));
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_condition(combinationPredicate->id());
// The metric is dimensioning by uid only.
*countMetric->mutable_dimensions() =
CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
@@ -72,7 +72,7 @@ StatsdConfig CreateStatsdConfig() {
// Links between crash atom and condition of app is in syncing.
auto links = countMetric->add_links();
- links->set_condition(isSyncingPredicate.name());
+ links->set_condition(isSyncingPredicate.id());
auto dimensionWhat = links->mutable_dimensions_in_what();
dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
dimensionWhat->add_child()->set_field(1); // uid field.
@@ -82,7 +82,7 @@ StatsdConfig CreateStatsdConfig() {
// Links between crash atom and condition of app is in background.
links = countMetric->add_links();
- links->set_condition(isInBackgroundPredicate.name());
+ links->set_condition(isInBackgroundPredicate.id());
dimensionWhat = links->mutable_dimensions_in_what();
dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
dimensionWhat->add_child()->set_field(1); // uid field.
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 8d7b2d511eaa..ecdb002c1863 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -43,9 +43,9 @@ StatsdConfig CreateStatsdConfig(DurationMetric::AggregationType aggregationType)
*config.add_predicate() = holdingWakelockPredicate;
auto durationMetric = config.add_duration_metric();
- durationMetric->set_name("WakelockDuration");
- durationMetric->set_what(holdingWakelockPredicate.name());
- durationMetric->set_condition(screenIsOffPredicate.name());
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(screenIsOffPredicate.id());
durationMetric->set_aggregation_type(aggregationType);
// The metric is dimensioning by first attribution node and only by uid.
*durationMetric->mutable_dimensions() =
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 765804475eef..a1343002405b 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -14,6 +14,7 @@
#include "src/guardrail/StatsdStats.h"
#include "statslog.h"
+#include "tests/statsd_test_util.h"
#include <gtest/gtest.h>
#include <vector>
@@ -28,8 +29,7 @@ using std::vector;
TEST(StatsdStatsTest, TestValidConfigAdd) {
StatsdStats stats;
- string name = "StatsdTest";
- ConfigKey key(0, name);
+ ConfigKey key(0, 12345);
const int metricsCount = 10;
const int conditionsCount = 20;
const int matchersCount = 30;
@@ -45,7 +45,7 @@ TEST(StatsdStatsTest, TestValidConfigAdd) {
EXPECT_EQ(1, report.config_stats_size());
const auto& configReport = report.config_stats(0);
EXPECT_EQ(0, configReport.uid());
- EXPECT_EQ(name, configReport.name());
+ EXPECT_EQ(12345, configReport.id());
EXPECT_EQ(metricsCount, configReport.metric_count());
EXPECT_EQ(conditionsCount, configReport.condition_count());
EXPECT_EQ(matchersCount, configReport.matcher_count());
@@ -56,8 +56,7 @@ TEST(StatsdStatsTest, TestValidConfigAdd) {
TEST(StatsdStatsTest, TestInvalidConfigAdd) {
StatsdStats stats;
- string name = "StatsdTest";
- ConfigKey key(0, name);
+ ConfigKey key(0, 12345);
const int metricsCount = 10;
const int conditionsCount = 20;
const int matchersCount = 30;
@@ -78,8 +77,7 @@ TEST(StatsdStatsTest, TestInvalidConfigAdd) {
TEST(StatsdStatsTest, TestConfigRemove) {
StatsdStats stats;
- string name = "StatsdTest";
- ConfigKey key(0, name);
+ ConfigKey key(0, 12345);
const int metricsCount = 10;
const int conditionsCount = 20;
const int matchersCount = 30;
@@ -105,22 +103,22 @@ TEST(StatsdStatsTest, TestConfigRemove) {
TEST(StatsdStatsTest, TestSubStats) {
StatsdStats stats;
- ConfigKey key(0, "test");
+ ConfigKey key(0, 12345);
stats.noteConfigReceived(key, 2, 3, 4, 5, true);
- stats.noteMatcherMatched(key, "matcher1");
- stats.noteMatcherMatched(key, "matcher1");
- stats.noteMatcherMatched(key, "matcher2");
+ stats.noteMatcherMatched(key, StringToId("matcher1"));
+ stats.noteMatcherMatched(key, StringToId("matcher1"));
+ stats.noteMatcherMatched(key, StringToId("matcher2"));
- stats.noteConditionDimensionSize(key, "condition1", 250);
- stats.noteConditionDimensionSize(key, "condition1", 240);
+ stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
+ stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
- stats.noteMetricDimensionSize(key, "metric1", 201);
- stats.noteMetricDimensionSize(key, "metric1", 202);
+ stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
+ stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
- stats.noteAnomalyDeclared(key, "alert1");
- stats.noteAnomalyDeclared(key, "alert1");
- stats.noteAnomalyDeclared(key, "alert2");
+ stats.noteAnomalyDeclared(key, StringToId("alert1"));
+ stats.noteAnomalyDeclared(key, StringToId("alert1"));
+ stats.noteAnomalyDeclared(key, StringToId("alert2"));
// broadcast-> 2
stats.noteBroadcastSent(key);
@@ -147,39 +145,39 @@ TEST(StatsdStatsTest, TestSubStats) {
EXPECT_EQ(2, configReport.matcher_stats_size());
// matcher1 is the first in the list
- if (!configReport.matcher_stats(0).name().compare("matcher1")) {
+ if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
- EXPECT_EQ("matcher2", configReport.matcher_stats(1).name());
+ EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
} else {
// matcher1 is the second in the list.
EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
- EXPECT_EQ("matcher2", configReport.matcher_stats(0).name());
+ EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
- EXPECT_EQ("matcher1", configReport.matcher_stats(1).name());
+ EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
}
EXPECT_EQ(2, configReport.alert_stats_size());
- bool alert1first = !configReport.alert_stats(0).name().compare("alert1");
- EXPECT_EQ("alert1", configReport.alert_stats(alert1first ? 0 : 1).name());
+ bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
+ EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
- EXPECT_EQ("alert2", configReport.alert_stats(alert1first ? 1 : 0).name());
+ EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
EXPECT_EQ(1, configReport.condition_stats_size());
- EXPECT_EQ("condition1", configReport.condition_stats(0).name());
+ EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
EXPECT_EQ(1, configReport.metric_stats_size());
- EXPECT_EQ("metric1", configReport.metric_stats(0).name());
+ EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
// after resetting the stats, some new events come
- stats.noteMatcherMatched(key, "matcher99");
- stats.noteConditionDimensionSize(key, "condition99", 300);
- stats.noteMetricDimensionSize(key, "metric99", 270);
- stats.noteAnomalyDeclared(key, "alert99");
+ stats.noteMatcherMatched(key, StringToId("matcher99"));
+ stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
+ stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
+ stats.noteAnomalyDeclared(key, StringToId("alert99"));
// now the config stats should only contain the stats about the new event.
stats.dumpStats(&output, false);
@@ -188,19 +186,19 @@ TEST(StatsdStatsTest, TestSubStats) {
EXPECT_EQ(1, report.config_stats_size());
const auto& configReport2 = report.config_stats(0);
EXPECT_EQ(1, configReport2.matcher_stats_size());
- EXPECT_EQ("matcher99", configReport2.matcher_stats(0).name());
+ EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
EXPECT_EQ(1, configReport2.condition_stats_size());
- EXPECT_EQ("condition99", configReport2.condition_stats(0).name());
+ EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
EXPECT_EQ(1, configReport2.metric_stats_size());
- EXPECT_EQ("metric99", configReport2.metric_stats(0).name());
+ EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
EXPECT_EQ(1, configReport2.alert_stats_size());
- EXPECT_EQ("alert99", configReport2.alert_stats(0).name());
+ EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
}
@@ -260,7 +258,7 @@ TEST(StatsdStatsTest, TestTimestampThreshold) {
for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
timestamps.push_back(i);
}
- ConfigKey key(0, "test");
+ ConfigKey key(0, 12345);
stats.noteConfigReceived(key, 2, 3, 4, 5, true);
for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 6e114a628fef..4cb242aa3bcc 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -15,6 +15,7 @@
#include "src/metrics/CountMetricProducer.h"
#include "src/dimension.h"
#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -33,7 +34,7 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
int64_t bucketStartTimeNs = 10000000000;
@@ -43,7 +44,7 @@ TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
int tagId = 1;
CountMetric metric;
- metric.set_name("1");
+ metric.set_id(1);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
LogEvent event1(tagId, bucketStartTimeNs + 1);
@@ -100,9 +101,9 @@ TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
CountMetric metric;
- metric.set_name("1");
+ metric.set_id(1);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
- metric.set_condition("SCREEN_ON");
+ metric.set_condition(StringToId("SCREEN_ON"));
LogEvent event1(1, bucketStartTimeNs + 1);
LogEvent event2(1, bucketStartTimeNs + 10);
@@ -142,11 +143,11 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
int conditionTagId = 2;
CountMetric metric;
- metric.set_name("1");
+ metric.set_id(1);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
- metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+ metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
MetricConditionLink* link = metric.add_links();
- link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
*link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
*link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
@@ -154,13 +155,15 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
event1.write("111"); // uid
event1.init();
ConditionKey key1;
- key1["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "111")};
+ key1[StringToId("APP_IN_BACKGROUND_PER_UID")] =
+ {getMockedDimensionKey(conditionTagId, 2, "111")};
LogEvent event2(tagId, bucketStartTimeNs + 10);
event2.write("222"); // uid
event2.init();
ConditionKey key2;
- key2["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "222")};
+ key2[StringToId("APP_IN_BACKGROUND_PER_UID")] =
+ {getMockedDimensionKey(conditionTagId, 2, "222")};
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
@@ -189,10 +192,10 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
TEST(CountMetricProducerTest, TestAnomalyDetection) {
Alert alert;
- alert.set_name("alert");
- alert.set_metric_name("1");
+ alert.set_id(11);
+ alert.set_metric_id(1);
alert.set_trigger_if_sum_gt(2);
- alert.set_number_of_buckets(2);
+ alert.set_num_buckets(2);
alert.set_refractory_period_secs(1);
int64_t bucketStartTimeNs = 10000000000;
@@ -201,7 +204,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetection) {
int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
CountMetric metric;
- metric.set_name("1");
+ metric.set_id(1);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 8ee94c75356f..a4213dec7c44 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -36,7 +36,7 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
TEST(DurationMetricTrackerTest, TestNoCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -44,7 +44,7 @@ TEST(DurationMetricTrackerTest, TestNoCondition) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
DurationMetric metric;
- metric.set_name("1");
+ metric.set_id(1);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
@@ -79,7 +79,7 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
DurationMetric metric;
- metric.set_name("1");
+ metric.set_id(1);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 0ba1c2f522d9..7171de939c62 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -15,6 +15,7 @@
#include "src/metrics/EventMetricProducer.h"
#include "src/dimension.h"
#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -33,7 +34,7 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
TEST(EventMetricProducerTest, TestNoCondition) {
uint64_t bucketStartTimeNs = 10000000000;
@@ -41,7 +42,7 @@ TEST(EventMetricProducerTest, TestNoCondition) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
EventMetric metric;
- metric.set_name("1");
+ metric.set_id(1);
LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
@@ -64,8 +65,8 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
EventMetric metric;
- metric.set_name("1");
- metric.set_condition("SCREEN_ON");
+ metric.set_id(1);
+ metric.set_condition(StringToId("SCREEN_ON"));
LogEvent event1(1, bucketStartTimeNs + 1);
LogEvent event2(1, bucketStartTimeNs + 10);
@@ -93,10 +94,10 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
int conditionTagId = 2;
EventMetric metric;
- metric.set_name("1");
- metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+ metric.set_id(1);
+ metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
MetricConditionLink* link = metric.add_links();
- link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
*link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
*link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
@@ -104,13 +105,13 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
EXPECT_TRUE(event1.write("111"));
event1.init();
ConditionKey key1;
- key1["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "111")};
+ key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "111")};
LogEvent event2(tagId, bucketStartTimeNs + 10);
EXPECT_TRUE(event2.write("222"));
event2.init();
ConditionKey key2;
- key2["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "222")};
+ key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 359851fbb217..749cf26e4630 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -15,6 +15,7 @@
#include "src/metrics/GaugeMetricProducer.h"
#include "logd/LogEvent.h"
#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -34,9 +35,9 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
-const string metricName = "test_metric";
+const int64_t metricId = 123;
const int64_t bucketStartTimeNs = 10000000000;
const int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
@@ -45,7 +46,7 @@ const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
TEST(GaugeMetricProducerTest, TestNoCondition) {
GaugeMetric metric;
- metric.set_name(metricName);
+ metric.set_id(metricId);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
metric.mutable_gauge_fields_filter()->set_include_all(false);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
@@ -119,12 +120,12 @@ TEST(GaugeMetricProducerTest, TestNoCondition) {
TEST(GaugeMetricProducerTest, TestWithCondition) {
GaugeMetric metric;
- metric.set_name(metricName);
+ metric.set_id(metricId);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(2);
- metric.set_condition("SCREEN_ON");
+ metric.set_condition(StringToId("SCREEN_ON"));
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -186,7 +187,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
GaugeMetric metric;
- metric.set_name(metricName);
+ metric.set_id(metricId);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
@@ -195,10 +196,10 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
tagId, tagId, bucketStartTimeNs, pullerManager);
Alert alert;
- alert.set_name("alert");
- alert.set_metric_name(metricName);
+ alert.set_id(101);
+ alert.set_metric_id(metricId);
alert.set_trigger_if_sum_gt(25);
- alert.set_number_of_buckets(2);
+ alert.set_num_buckets(2);
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
int tagId = 1;
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 7843ca085d5b..704a46691328 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -13,8 +13,9 @@
// limitations under the License.
#include "src/metrics/duration_helper/MaxDurationTracker.h"
-#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
+#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -36,7 +37,7 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
const int TagId = 1;
@@ -50,12 +51,13 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey conditionKey1;
- conditionKey1["condition"] = conditionKey;
+ conditionKey1[StringToId("condition")] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ int64_t metricId = 1;
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
bucketSizeNs, {});
tracker.noteStart(key1, true, bucketStartTimeNs, conditionKey1);
@@ -79,12 +81,13 @@ TEST(MaxDurationTrackerTest, TestStopAll) {
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey conditionKey1;
- conditionKey1["condition"] = conditionKey;
+ conditionKey1[StringToId("condition")] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ int64_t metricId = 1;
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
bucketSizeNs, {});
tracker.noteStart(key1, true, bucketStartTimeNs + 1, conditionKey1);
@@ -110,12 +113,13 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey conditionKey1;
- conditionKey1["condition"] = conditionKey;
+ conditionKey1[StringToId("condition")] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ int64_t metricId = 1;
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
bucketSizeNs, {});
// The event starts.
@@ -141,12 +145,13 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey conditionKey1;
- conditionKey1["condition"] = conditionKey;
+ conditionKey1[StringToId("condition")] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+ int64_t metricId = 1;
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, true, bucketStartTimeNs,
bucketSizeNs, {});
// 2 starts
@@ -177,7 +182,7 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
ConditionKey conditionKey1;
HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 2, "maps");
- conditionKey1["APP_BACKGROUND"] = conditionKey;
+ conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
EXPECT_CALL(*wizard, query(_, conditionKey1)) // #4
.WillOnce(Return(ConditionState::kFalse));
@@ -189,7 +194,8 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
int64_t durationTimeNs = 2 * 1000;
- MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false, bucketStartTimeNs,
+ int64_t metricId = 1;
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false, bucketStartTimeNs,
bucketSizeNs, {});
EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
@@ -206,23 +212,24 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
}
TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
+ int64_t metricId = 1;
Alert alert;
- alert.set_name("alert");
- alert.set_metric_name("metric");
+ alert.set_id(101);
+ alert.set_metric_id(metricId);
alert.set_trigger_if_sum_gt(32 * NS_PER_SEC);
- alert.set_number_of_buckets(2);
+ alert.set_num_buckets(2);
alert.set_refractory_period_secs(1);
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey conditionKey1;
- conditionKey1["APP_BACKGROUND"] = conditionKey;
+ conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
- MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, true, bucketStartTimeNs,
bucketSizeNs, {anomalyTracker});
tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 550b059e4d69..36cdaae01b4f 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -13,8 +13,9 @@
// limitations under the License.
#include "src/metrics/duration_helper/OringDurationTracker.h"
-#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
+#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -34,8 +35,9 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
const int TagId = 1;
+const int64_t metricId = 123;
const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "event");
const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
@@ -46,7 +48,7 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -55,7 +57,7 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -75,7 +77,7 @@ TEST(OringDurationTrackerTest, TestDurationNested) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -83,7 +85,7 @@ TEST(OringDurationTrackerTest, TestDurationNested) {
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -102,7 +104,7 @@ TEST(OringDurationTrackerTest, TestStopAll) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -110,7 +112,7 @@ TEST(OringDurationTrackerTest, TestStopAll) {
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -128,7 +130,7 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -137,7 +139,7 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -163,7 +165,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
@@ -175,7 +177,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -194,7 +196,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
EXPECT_CALL(*wizard, query(_, key1))
.Times(2)
@@ -208,7 +210,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -229,7 +231,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
@@ -240,7 +242,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -260,22 +262,22 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
Alert alert;
- alert.set_name("alert");
- alert.set_metric_name("1");
+ alert.set_id(101);
+ alert.set_metric_id(1);
alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
- alert.set_number_of_buckets(2);
+ alert.set_num_buckets(2);
alert.set_refractory_period_secs(1);
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {anomalyTracker});
// Nothing in the past bucket.
@@ -322,22 +324,22 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
TEST(OringDurationTrackerTest, TestAnomalyDetection) {
Alert alert;
- alert.set_name("alert");
- alert.set_metric_name("1");
+ alert.set_id(101);
+ alert.set_metric_id(1);
alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
- alert.set_number_of_buckets(2);
+ alert.set_num_buckets(2);
alert.set_refractory_period_secs(1);
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = kConditionKey1;
+ key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
- OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true /*nesting*/,
bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 12bc834be540..15acca4bd2a1 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -14,6 +14,7 @@
#include "src/metrics/ValueMetricProducer.h"
#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -34,9 +35,9 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
-const string metricName = "test_metric";
+const int64_t metricId = 123;
const int64_t bucketStartTimeNs = 10000000000;
const int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
@@ -48,9 +49,10 @@ const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
*/
TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
ValueMetric metric;
- metric.set_name(metricName);
+ metric.set_id(metricId);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
- metric.set_value_field(2);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
// TODO: pending refactor of StatsPullerManager
@@ -124,10 +126,11 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
*/
TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
ValueMetric metric;
- metric.set_name(metricName);
+ metric.set_id(metricId);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
- metric.set_value_field(2);
- metric.set_condition("SCREEN_ON");
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_condition(StringToId("SCREEN_ON"));
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
shared_ptr<MockStatsPullerManager> pullerManager =
@@ -200,9 +203,10 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
ValueMetric metric;
- metric.set_name(metricName);
+ metric.set_id(metricId);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
- metric.set_value_field(2);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
shared_ptr<MockStatsPullerManager> pullerManager =
@@ -240,16 +244,17 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
Alert alert;
- alert.set_name("alert");
- alert.set_metric_name(metricName);
+ alert.set_id(101);
+ alert.set_metric_id(metricId);
alert.set_trigger_if_sum_gt(130);
- alert.set_number_of_buckets(2);
+ alert.set_num_buckets(2);
alert.set_refractory_period_secs(3);
ValueMetric metric;
- metric.set_name(metricName);
+ metric.set_id(metricId);
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
- metric.set_value_field(2);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 39e366fae3f8..939dc1f7c66c 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -22,7 +22,7 @@ namespace statsd {
AtomMatcher CreateWakelockStateChangedAtomMatcher(const string& name,
WakelockStateChanged::State state) {
AtomMatcher atom_matcher;
- atom_matcher.set_name(name);
+ atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::WAKELOCK_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -42,7 +42,7 @@ AtomMatcher CreateReleaseWakelockAtomMatcher() {
AtomMatcher CreateScreenStateChangedAtomMatcher(
const string& name, ScreenStateChanged::State state) {
AtomMatcher atom_matcher;
- atom_matcher.set_name(name);
+ atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::SCREEN_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -62,7 +62,7 @@ AtomMatcher CreateScreenTurnedOffAtomMatcher() {
AtomMatcher CreateSyncStateChangedAtomMatcher(
const string& name, SyncStateChanged::State state) {
AtomMatcher atom_matcher;
- atom_matcher.set_name(name);
+ atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::SYNC_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -82,7 +82,7 @@ AtomMatcher CreateSyncEndAtomMatcher() {
AtomMatcher CreateActivityForegroundStateChangedAtomMatcher(
const string& name, ActivityForegroundStateChanged::Activity activity) {
AtomMatcher atom_matcher;
- atom_matcher.set_name(name);
+ atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -104,7 +104,7 @@ AtomMatcher CreateMoveToForegroundAtomMatcher() {
AtomMatcher CreateProcessLifeCycleStateChangedAtomMatcher(
const string& name, ProcessLifeCycleStateChanged::Event event) {
AtomMatcher atom_matcher;
- atom_matcher.set_name(name);
+ atom_matcher.set_id(StringToId(name));
auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
simple_atom_matcher->set_atom_id(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -121,47 +121,47 @@ AtomMatcher CreateProcessCrashAtomMatcher() {
Predicate CreateScreenIsOnPredicate() {
Predicate predicate;
- predicate.set_name("ScreenIsOn");
- predicate.mutable_simple_predicate()->set_start("ScreenTurnedOn");
- predicate.mutable_simple_predicate()->set_stop("ScreenTurnedOff");
+ predicate.set_id(StringToId("ScreenIsOn"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOn"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOff"));
return predicate;
}
Predicate CreateScreenIsOffPredicate() {
Predicate predicate;
- predicate.set_name("ScreenIsOff");
- predicate.mutable_simple_predicate()->set_start("ScreenTurnedOff");
- predicate.mutable_simple_predicate()->set_stop("ScreenTurnedOn");
+ predicate.set_id(StringToId("ScreenIsOff"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOff"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOn"));
return predicate;
}
Predicate CreateHoldingWakelockPredicate() {
Predicate predicate;
- predicate.set_name("HoldingWakelock");
- predicate.mutable_simple_predicate()->set_start("AcquireWakelock");
- predicate.mutable_simple_predicate()->set_stop("ReleaseWakelock");
+ predicate.set_id(StringToId("HoldingWakelock"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("AcquireWakelock"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ReleaseWakelock"));
return predicate;
}
Predicate CreateIsSyncingPredicate() {
Predicate predicate;
- predicate.set_name("IsSyncing");
- predicate.mutable_simple_predicate()->set_start("SyncStart");
- predicate.mutable_simple_predicate()->set_stop("SyncEnd");
+ predicate.set_id(StringToId("IsSyncing"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("SyncStart"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("SyncEnd"));
return predicate;
}
Predicate CreateIsInBackgroundPredicate() {
Predicate predicate;
- predicate.set_name("IsInBackground");
- predicate.mutable_simple_predicate()->set_start("MoveToBackground");
- predicate.mutable_simple_predicate()->set_stop("MoveToForeground");
+ predicate.set_id(StringToId("IsInBackground"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("MoveToBackground"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("MoveToForeground"));
return predicate;
}
void addPredicateToPredicateCombination(const Predicate& predicate,
Predicate* combinationPredicate) {
- combinationPredicate->mutable_combination()->add_predicate(predicate.name());
+ combinationPredicate->mutable_combination()->add_predicate(predicate.id());
}
FieldMatcher CreateAttributionUidDimensions(const int atomId,
@@ -316,6 +316,9 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events) {
});
}
+int64_t StringToId(const string& str) {
+ return static_cast<int64_t>(std::hash<std::string>()(str));
+}
} // namespace statsd
} // namespace os
} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 282e1b2c70a0..5e19da032e07 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -121,6 +121,8 @@ sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const Stat
// Util function to sort the log events by timestamp.
void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);
+int64_t StringToId(const string& str);
+
} // namespace statsd
} // namespace os
} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/tools/dogfood/Android.mk b/cmds/statsd/tools/dogfood/Android.mk
index 7bd15d707bbc..a4c080063284 100644
--- a/cmds/statsd/tools/dogfood/Android.mk
+++ b/cmds/statsd/tools/dogfood/Android.mk
@@ -20,7 +20,8 @@ LOCAL_PACKAGE_NAME := StatsdDogfood
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += ../../src/stats_log.proto \
- ../../src/atoms.proto
+ ../../src/atoms.proto \
+ ../../src/statsd_config.proto
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config b/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
index 03299929f84b..c1c391483855 100644
--- a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
+++ b/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
index 9294681f5baa..93dba71716a5 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
@@ -26,7 +26,7 @@ public class DisplayProtoUtils {
sb.append("ConfigKey: ");
if (reports.hasConfigKey()) {
com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
- sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getName())
+ sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getId())
.append("\n");
}
@@ -34,7 +34,7 @@ public class DisplayProtoUtils {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
sb.append("\n\n");
- sb.append("metric id: ").append(log.getMetricName()).append("\n");
+ sb.append("metric id: ").append(log.getMetricId()).append("\n");
sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
index 137fd4d01fda..4f9032ff01b4 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
@@ -34,6 +34,7 @@ import static com.android.statsd.dogfood.DisplayProtoUtils.displayLogReport;
public class MainActivity extends Activity {
private final static String TAG = "StatsdDogfood";
+ private final static long CONFIG_ID = 987654321;
final int[] mUids = {11111111, 2222222};
StatsManager mStatsManager;
@@ -163,7 +164,7 @@ public class MainActivity extends Activity {
return;
}
if (mStatsManager != null) {
- byte[] data = mStatsManager.getData("fake");
+ byte[] data = mStatsManager.getData(CONFIG_ID);
if (data != null) {
displayData(data);
} else {
@@ -186,7 +187,7 @@ public class MainActivity extends Activity {
byte[] config = new byte[inputStream.available()];
inputStream.read(config);
if (mStatsManager != null) {
- if (mStatsManager.addConfiguration("fake",
+ if (mStatsManager.addConfiguration(CONFIG_ID,
config, getPackageName(), MainActivity.this.getClass().getName())) {
Toast.makeText(
MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
index f516477abf9f..4bd284448446 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
@@ -41,7 +41,7 @@ import java.util.List;
* Creates StatsdConfig protos for loadtesting.
*/
public class ConfigFactory {
- public static final String CONFIG_NAME = "LOADTEST";
+ public static final long CONFIG_ID = 123456789;
private static final String TAG = "loadtest.ConfigFactory";
@@ -86,7 +86,7 @@ public class ConfigFactory {
boolean includeDuration, boolean includeEvent, boolean includeValue,
boolean includeGauge) {
StatsdConfig.Builder config = StatsdConfig.newBuilder()
- .setName(CONFIG_NAME);
+ .setId(CONFIG_ID);
if (placebo) {
replication = 0; // Config will be empty, aside from a name.
}
@@ -160,7 +160,7 @@ public class ConfigFactory {
*/
private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
EventMetric.Builder metric = template.toBuilder()
- .setName(template.getName() + suffix)
+ .setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
@@ -186,7 +186,7 @@ public class ConfigFactory {
private void addCountMetric(CountMetric template, int suffix, long bucketMillis,
StatsdConfig.Builder config) {
CountMetric.Builder metric = template.toBuilder()
- .setName(template.getName() + suffix)
+ .setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
@@ -207,7 +207,7 @@ public class ConfigFactory {
private void addDurationMetric(DurationMetric template, int suffix, long bucketMillis,
StatsdConfig.Builder config) {
DurationMetric.Builder metric = template.toBuilder()
- .setName(template.getName() + suffix)
+ .setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
@@ -228,7 +228,7 @@ public class ConfigFactory {
private void addGaugeMetric(GaugeMetric template, int suffix, long bucketMillis,
StatsdConfig.Builder config) {
GaugeMetric.Builder metric = template.toBuilder()
- .setName(template.getName() + suffix)
+ .setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
@@ -249,7 +249,7 @@ public class ConfigFactory {
private void addValueMetric(ValueMetric template, int suffix, long bucketMillis,
StatsdConfig.Builder config) {
ValueMetric.Builder metric = template.toBuilder()
- .setName(template.getName() + suffix)
+ .setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
@@ -269,11 +269,11 @@ public class ConfigFactory {
*/
private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
Predicate.Builder predicate = template.toBuilder()
- .setName(template.getName() + suffix);
+ .setId(template.getId() + suffix);
if (template.hasCombination()) {
Predicate.Combination.Builder cb = template.getCombination().toBuilder()
.clearPredicate();
- for (String child : template.getCombination().getPredicateList()) {
+ for (long child : template.getCombination().getPredicateList()) {
cb.addPredicate(child + suffix);
}
predicate.setCombination(cb.build());
@@ -296,11 +296,11 @@ public class ConfigFactory {
*/
private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
AtomMatcher.Builder matcher = template.toBuilder()
- .setName(template.getName() + suffix);
+ .setId(template.getId() + suffix);
if (template.hasCombination()) {
AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
.clearMatcher();
- for (String child : template.getCombination().getMatcherList()) {
+ for (long child : template.getCombination().getMatcherList()) {
cb.addMatcher(child + suffix);
}
matcher.setCombination(cb);
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
index ba43d57db8af..19087d86c4a6 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
@@ -26,7 +26,7 @@ public class DisplayProtoUtils {
sb.append("ConfigKey: ");
if (reports.hasConfigKey()) {
com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
- sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getName())
+ sb.append("\tuid: ").append(key.getUid()).append(" id: ").append(key.getId())
.append("\n");
}
@@ -34,7 +34,7 @@ public class DisplayProtoUtils {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
sb.append("\n\n");
- sb.append("metric id: ").append(log.getMetricName()).append("\n");
+ sb.append("metric id: ").append(log.getMetricId()).append("\n");
sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
index 83f4b7bed558..86da16c82e9b 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -294,7 +294,7 @@ public class LoadtestActivity extends Activity {
return null;
}
if (mStatsManager != null) {
- byte[] data = mStatsManager.getData(ConfigFactory.CONFIG_NAME);
+ byte[] data = mStatsManager.getData(ConfigFactory.CONFIG_ID);
if (data != null) {
ConfigMetricsReportList reports = null;
try {
@@ -453,7 +453,7 @@ public class LoadtestActivity extends Activity {
// TODO: Clear all configs instead of specific ones.
if (mStatsManager != null) {
if (mStarted) {
- if (!mStatsManager.removeConfiguration(ConfigFactory.CONFIG_NAME)) {
+ if (!mStatsManager.removeConfiguration(ConfigFactory.CONFIG_ID)) {
Log.d(TAG, "Removed loadtest statsd configs.");
} else {
Log.d(TAG, "Failed to remove loadtest configs.");
@@ -464,7 +464,7 @@ public class LoadtestActivity extends Activity {
private boolean setConfig(byte[] config) {
if (mStatsManager != null) {
- if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_NAME,
+ if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_ID,
config, getPackageName(), LoadtestActivity.this.getClass().getName())) {
Log.d(TAG, "Config pushed to statsd");
return true;
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
index 4b614aa19492..d122654ec8a1 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
@@ -59,18 +59,8 @@ public class ValidationRecorder extends PerfDataRecorder {
Log.d(TAG, "GOT DATA");
for (ConfigMetricsReport report : reports) {
for (StatsLogReport logReport : report.getMetricsList()) {
- if (!logReport.hasMetricName()) {
+ if (!logReport.hasMetricId()) {
Log.e(TAG, "Metric missing name.");
- continue;
- }
- String metricName = logReport.getMetricName();
- if (metricName.startsWith("EVENT_BATTERY_LEVEL_CHANGES_WHILE_SCREEN_IS_ON_")) {
- validateEventBatteryLevelChangesWhileScreenIsOn(logReport);
- continue;
- }
- if (metricName.startsWith("EVENT_BATTERY_LEVEL_CHANGES_")) {
- validateEventBatteryLevelChanges(logReport);
- continue;
}
}
}
@@ -78,7 +68,7 @@ public class ValidationRecorder extends PerfDataRecorder {
}
private void validateEventBatteryLevelChanges(StatsLogReport logReport) {
- Log.d(TAG, "Validating " + logReport.getMetricName());
+ Log.d(TAG, "Validating " + logReport.getMetricId());
if (logReport.hasEventMetrics()) {
Log.d(TAG, "Num events captured: " + logReport.getEventMetrics().getDataCount());
for (EventMetricData data : logReport.getEventMetrics().getDataList()) {
@@ -90,6 +80,6 @@ public class ValidationRecorder extends PerfDataRecorder {
}
private void validateEventBatteryLevelChangesWhileScreenIsOn(StatsLogReport logReport) {
- Log.d(TAG, "Validating " + logReport.getMetricName());
+ Log.d(TAG, "Validating " + logReport.getMetricId());
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1adae7a84fcc..847f91bdc59a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -60,6 +60,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.WorkSource;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -3911,10 +3912,10 @@ public class ActivityManager {
/**
* @hide
*/
- public static void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
- String tag) {
+ public static void noteWakeupAlarm(PendingIntent ps, WorkSource workSource, int sourceUid,
+ String sourcePkg, String tag) {
try {
- getService().noteWakeupAlarm((ps != null) ? ps.getTarget() : null,
+ getService().noteWakeupAlarm((ps != null) ? ps.getTarget() : null, workSource,
sourceUid, sourcePkg, tag);
} catch (RemoteException ex) {
}
@@ -3923,19 +3924,24 @@ public class ActivityManager {
/**
* @hide
*/
- public static void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
+ public static void noteAlarmStart(PendingIntent ps, WorkSource workSource, int sourceUid,
+ String tag) {
try {
- getService().noteAlarmStart((ps != null) ? ps.getTarget() : null, sourceUid, tag);
+ getService().noteAlarmStart((ps != null) ? ps.getTarget() : null, workSource,
+ sourceUid, tag);
} catch (RemoteException ex) {
}
}
+
/**
* @hide
*/
- public static void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
+ public static void noteAlarmFinish(PendingIntent ps, WorkSource workSource, int sourceUid,
+ String tag) {
try {
- getService().noteAlarmFinish((ps != null) ? ps.getTarget() : null, sourceUid, tag);
+ getService().noteAlarmFinish((ps != null) ? ps.getTarget() : null, workSource,
+ sourceUid, tag);
} catch (RemoteException ex) {
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index c09403c29943..4c558f374f91 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -75,20 +75,20 @@ public abstract class ActivityManagerNative {
*/
static public void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
String tag) {
- ActivityManager.noteWakeupAlarm(ps, sourceUid, sourcePkg, tag);
+ ActivityManager.noteWakeupAlarm(ps, null, sourceUid, sourcePkg, tag);
}
/**
* @deprecated use ActivityManager.noteAlarmStart instead.
*/
static public void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
- ActivityManager.noteAlarmStart(ps, sourceUid, tag);
+ ActivityManager.noteAlarmStart(ps, null, sourceUid, tag);
}
/**
* @deprecated use ActivityManager.noteAlarmFinish instead.
*/
static public void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
- ActivityManager.noteAlarmFinish(ps, sourceUid, tag);
+ ActivityManager.noteAlarmFinish(ps, null, sourceUid, tag);
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index aaa6bf0333a2..de346f315016 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1768,9 +1768,7 @@ public final class ActivityThread extends ClientTransactionHandler {
(String[]) ((SomeArgs) msg.obj).arg2);
break;
case EXECUTE_TRANSACTION:
- final ClientTransaction transaction = (ClientTransaction) msg.obj;
- mTransactionExecutor.execute(transaction);
- transaction.recycle();
+ mTransactionExecutor.execute(((ClientTransaction) msg.obj));
break;
}
Object obj = msg.obj;
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1278f75abce0..a9e633ff392d 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -63,6 +63,7 @@ import android.os.IProgressListener;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.StrictMode;
+import android.os.WorkSource;
import android.service.voice.IVoiceInteractionSession;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
@@ -198,7 +199,7 @@ interface IActivityManager {
void enterSafeMode();
boolean startNextMatchingActivity(in IBinder callingActivity,
in Intent intent, in Bundle options);
- void noteWakeupAlarm(in IIntentSender sender, int sourceUid,
+ void noteWakeupAlarm(in IIntentSender sender, in WorkSource workSource, int sourceUid,
in String sourcePkg, in String tag);
void removeContentProvider(in IBinder connection, boolean stable);
void setRequestedOrientation(in IBinder token, int requestedOrientation);
@@ -468,8 +469,8 @@ interface IActivityManager {
void dumpHeapFinished(in String path);
void setVoiceKeepAwake(in IVoiceInteractionSession session, boolean keepAwake);
void updateLockTaskPackages(int userId, in String[] packages);
- void noteAlarmStart(in IIntentSender sender, int sourceUid, in String tag);
- void noteAlarmFinish(in IIntentSender sender, int sourceUid, in String tag);
+ void noteAlarmStart(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String tag);
+ void noteAlarmFinish(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String tag);
int getPackageProcessState(in String packageName, in String callingPackage);
oneway void showLockTaskEscapeMessage(in IBinder token);
void updateDeviceOwner(in String packageName);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7e80ac7b8d94..0b747416bbbf 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1668,6 +1668,46 @@ public class DevicePolicyManager {
public static final String ACTION_DEVICE_ADMIN_SERVICE
= "android.app.action.DEVICE_ADMIN_SERVICE";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"ID_TYPE_"}, value = {
+ ID_TYPE_BASE_INFO,
+ ID_TYPE_SERIAL,
+ ID_TYPE_IMEI,
+ ID_TYPE_MEID
+ })
+ public @interface AttestationIdType {}
+
+ /**
+ * Specifies that the device should attest its manufacturer details. For use with
+ * {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_BASE_INFO = 1;
+
+ /**
+ * Specifies that the device should attest its serial number. For use with
+ * {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_SERIAL = 2;
+
+ /**
+ * Specifies that the device should attest its IMEI. For use with {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_IMEI = 4;
+
+ /**
+ * Specifies that the device should attest its MEID. For use with {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_MEID = 8;
+
/**
* Return true if the given administrator component is currently active (enabled) in the system.
*
@@ -4106,22 +4146,46 @@ public class DevicePolicyManager {
* @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
* @param keySpec Specification of the key to generate, see
* {@link java.security.KeyPairGenerator}.
+ * @param idAttestationFlags A bitmask of all the identifiers that should be included in the
+ * attestation record ({@code ID_TYPE_BASE_INFO}, {@code ID_TYPE_SERIAL},
+ * {@code ID_TYPE_IMEI} and {@code ID_TYPE_MEID}), or {@code 0} if no device
+ * identification is required in the attestation record.
+ * Device owner, profile owner and their delegated certificate installer can use
+ * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information
+ * including manufacturer, model, brand, device and product in the attestation record.
+ * Only device owner and their delegated certificate installer can use
+ * {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID} to request
+ * unique device identifiers to be attested.
+ * <p>
+ * If any of {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID}
+ * is set, it is implicitly assumed that {@link #ID_TYPE_BASE_INFO} is also set.
+ * <p>
+ * If any flag is specified, then an attestation challenge must be included in the
+ * {@code keySpec}.
* @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner.
- * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, or if the
+ * owner. If Device ID attestation is requested (using {@link #ID_TYPE_SERIAL},
+ * {@link #ID_TYPE_IMEI} or {@link #ID_TYPE_MEID}), the caller must be the Device Owner
+ * or the Certificate Installer delegate.
+ * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, if the
* algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec}
- * or {@code ECGenParameterSpec}.
+ * or {@code ECGenParameterSpec}, or if Device ID attestation was requested but the
+ * {@code keySpec} does not contain an attestation challenge.
+ * @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])
*/
public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin,
- @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec) {
+ @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec,
+ @AttestationIdType int idAttestationFlags) {
throwIfParentInstance("generateKeyPair");
try {
final ParcelableKeyGenParameterSpec parcelableSpec =
new ParcelableKeyGenParameterSpec(keySpec);
KeymasterCertificateChain attestationChain = new KeymasterCertificateChain();
+
+ // Translate ID attestation flags to values used by AttestationUtils
final boolean success = mService.generateKeyPair(
- admin, mContext.getPackageName(), algorithm, parcelableSpec, attestationChain);
+ admin, mContext.getPackageName(), algorithm, parcelableSpec,
+ idAttestationFlags, attestationChain);
if (!success) {
Log.e(TAG, "Error generating key via DevicePolicyManagerService.");
return null;
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7cf19eeb881d..5916a629f2e6 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -173,7 +173,7 @@ interface IDevicePolicyManager {
boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm,
in ParcelableKeyGenParameterSpec keySpec,
- out KeymasterCertificateChain attestationChain);
+ in int idAttestationFlags, out KeymasterCertificateChain attestationChain);
boolean setKeyPairCertificate(in ComponentName who, in String callerPackage, in String alias,
in byte[] certBuffer, in byte[] certChainBuffer, boolean isUserSelectable);
void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 7b549cd59666..87f227129586 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -32,6 +32,8 @@ import android.view.WindowManagerGlobal;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import com.android.internal.util.Preconditions;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -624,6 +626,7 @@ public class AssistStructure implements Parcelable {
int mMinEms = -1;
int mMaxEms = -1;
int mMaxLength = -1;
+ @Nullable String mTextIdEntry;
// POJO used to override some autofill-related values when the node is parcelized.
// Not written to parcel.
@@ -701,7 +704,7 @@ public class AssistStructure implements Parcelable {
final int flags = mFlags;
if ((flags&FLAGS_HAS_ID) != 0) {
mId = in.readInt();
- if (mId != 0) {
+ if (mId != View.NO_ID) {
mIdEntry = preader.readString();
if (mIdEntry != null) {
mIdType = preader.readString();
@@ -724,6 +727,7 @@ public class AssistStructure implements Parcelable {
mMinEms = in.readInt();
mMaxEms = in.readInt();
mMaxLength = in.readInt();
+ mTextIdEntry = preader.readString();
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
mX = in.readInt();
@@ -857,7 +861,7 @@ public class AssistStructure implements Parcelable {
out.writeInt(writtenFlags);
if ((flags&FLAGS_HAS_ID) != 0) {
out.writeInt(mId);
- if (mId != 0) {
+ if (mId != View.NO_ID) {
pwriter.writeString(mIdEntry);
if (mIdEntry != null) {
pwriter.writeString(mIdType);
@@ -890,6 +894,7 @@ public class AssistStructure implements Parcelable {
out.writeInt(mMinEms);
out.writeInt(mMaxEms);
out.writeInt(mMaxLength);
+ pwriter.writeString(mTextIdEntry);
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
out.writeInt(mX);
@@ -1430,6 +1435,17 @@ public class AssistStructure implements Parcelable {
}
/**
+ * Gets the identifier used to set the text associated with this view.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
+ * not for assist purposes.
+ */
+ @Nullable
+ public String getTextIdEntry() {
+ return mTextIdEntry;
+ }
+
+ /**
* Return additional hint text associated with the node; this is typically used with
* a node that takes user input, describing to the user what the input means.
*/
@@ -1684,6 +1700,11 @@ public class AssistStructure implements Parcelable {
}
@Override
+ public void setTextIdEntry(@NonNull String entryName) {
+ mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
+ }
+
+ @Override
public void setHint(CharSequence hint) {
getNodeText().mHint = hint != null ? hint.toString() : null;
}
@@ -2082,6 +2103,7 @@ public class AssistStructure implements Parcelable {
Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
+ ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
Log.i(TAG, prefix + " Input type: " + node.getInputType());
+ Log.i(TAG, prefix + " Resource id: " + node.getTextIdEntry());
}
String webDomain = node.getWebDomain();
if (webDomain != null) {
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index 3c96f06945c5..764ceede5d20 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -54,11 +54,6 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
/** Target client activity. Might be null if the entire transaction is targeting an app. */
private IBinder mActivityToken;
- /** Get the target client of the transaction. */
- public IApplicationThread getClient() {
- return mClient;
- }
-
/**
* Add a message to the end of the sequence of callbacks.
* @param activityCallback A single message that can contain a lifecycle request/callback.
diff --git a/core/java/android/app/servertransaction/ObjectPool.java b/core/java/android/app/servertransaction/ObjectPool.java
index 2fec30a0dde7..98121253f486 100644
--- a/core/java/android/app/servertransaction/ObjectPool.java
+++ b/core/java/android/app/servertransaction/ObjectPool.java
@@ -16,8 +16,8 @@
package android.app.servertransaction;
-import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Map;
/**
@@ -27,7 +27,7 @@ import java.util.Map;
class ObjectPool {
private static final Object sPoolSync = new Object();
- private static final Map<Class, ArrayList<? extends ObjectPoolItem>> sPoolMap =
+ private static final Map<Class, LinkedList<? extends ObjectPoolItem>> sPoolMap =
new HashMap<>();
private static final int MAX_POOL_SIZE = 50;
@@ -40,9 +40,9 @@ class ObjectPool {
public static <T extends ObjectPoolItem> T obtain(Class<T> itemClass) {
synchronized (sPoolSync) {
@SuppressWarnings("unchecked")
- final ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(itemClass);
+ LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(itemClass);
if (itemPool != null && !itemPool.isEmpty()) {
- return itemPool.remove(itemPool.size() - 1);
+ return itemPool.poll();
}
return null;
}
@@ -56,20 +56,16 @@ class ObjectPool {
public static <T extends ObjectPoolItem> void recycle(T item) {
synchronized (sPoolSync) {
@SuppressWarnings("unchecked")
- ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(item.getClass());
+ LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(item.getClass());
if (itemPool == null) {
- itemPool = new ArrayList<>();
+ itemPool = new LinkedList<>();
sPoolMap.put(item.getClass(), itemPool);
}
- // Check if the item is already in the pool
- final int size = itemPool.size();
- for (int i = 0; i < size; i++) {
- if (itemPool.get(i) == item) {
- throw new IllegalStateException("Trying to recycle already recycled item");
- }
+ if (itemPool.contains(item)) {
+ throw new IllegalStateException("Trying to recycle already recycled item");
}
- if (size < MAX_POOL_SIZE) {
+ if (itemPool.size() < MAX_POOL_SIZE) {
itemPool.add(item);
}
}
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index 5c7f67411a83..b8fb2e34d083 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -184,6 +184,10 @@ public final class Slice implements Parcelable {
* Subtype to tag an item representing priority.
*/
public static final String SUBTYPE_PRIORITY = "priority";
+ /**
+ * Subtype to tag an item to use as a content description.
+ */
+ public static final String SUBTYPE_CONTENT_DESCRIPTION = "content_description";
private final SliceItem[] mItems;
private final @SliceHint String[] mHints;
diff --git a/core/java/android/content/pm/PackageList.java b/core/java/android/content/pm/PackageList.java
new file mode 100644
index 000000000000..cfd99abc6283
--- /dev/null
+++ b/core/java/android/content/pm/PackageList.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManagerInternal.PackageListObserver;
+
+import com.android.server.LocalServices;
+
+import java.util.List;
+
+/**
+ * All of the package name installed on the system.
+ * <p>A self observable list that automatically removes the listener when it goes out of scope.
+ *
+ * @hide Only for use within the system server.
+ */
+public class PackageList implements PackageListObserver, AutoCloseable {
+ private final PackageListObserver mWrappedObserver;
+ private final List<String> mPackageNames;
+
+ /**
+ * Create a new object.
+ * <p>Ownership of the given {@link List} transfers to this object and should not
+ * be modified by the caller.
+ */
+ public PackageList(@NonNull List<String> packageNames, @Nullable PackageListObserver observer) {
+ mPackageNames = packageNames;
+ mWrappedObserver = observer;
+ }
+
+ @Override
+ public void onPackageAdded(String packageName) {
+ if (mWrappedObserver != null) {
+ mWrappedObserver.onPackageAdded(packageName);
+ }
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName) {
+ if (mWrappedObserver != null) {
+ mWrappedObserver.onPackageRemoved(packageName);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ LocalServices.getService(PackageManagerInternal.class).removePackageListObserver(this);
+ }
+
+ /**
+ * Returns the names of packages installed on the system.
+ * <p>The list is a copy-in-time and the actual set of installed packages may differ. Real
+ * time updates to the package list are sent via the {@link PackageListObserver} callback.
+ */
+ public @NonNull List<String> getPackageNames() {
+ return mPackageNames;
+ }
+}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 713cd109ef87..2c45b8d8b30e 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -53,6 +53,14 @@ public abstract class PackageManagerInternal {
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}
+ /** Observer called whenever the list of packages changes */
+ public interface PackageListObserver {
+ /** A package was added to the system. */
+ void onPackageAdded(@NonNull String packageName);
+ /** A package was removed from the system. */
+ void onPackageRemoved(@NonNull String packageName);
+ }
+
/**
* Provider for package names.
*/
@@ -111,6 +119,12 @@ public abstract class PackageManagerInternal {
public abstract void setSimCallManagerPackagesProvider(PackagesProvider provider);
/**
+ * Sets the Use Open Wifi packages provider.
+ * @param provider The packages provider.
+ */
+ public abstract void setUseOpenWifiAppPackagesProvider(PackagesProvider provider);
+
+ /**
* Sets the sync adapter packages provider.
* @param provider The provider.
*/
@@ -139,6 +153,14 @@ public abstract class PackageManagerInternal {
int userId);
/**
+ * Requests granting of the default permissions to the current default Use Open Wifi app.
+ * @param packageName The default use open wifi package name.
+ * @param userId The user for which to grant the permissions.
+ */
+ public abstract void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName,
+ int userId);
+
+ /**
* Sets a list of apps to keep in PM's internal data structures and as APKs even if no user has
* currently installed it. The apps are not preloaded.
* @param packageList List of package names to keep cached.
@@ -435,6 +457,35 @@ public abstract class PackageManagerInternal {
public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName);
/**
+ * Returns a list without a change observer.
+ *
+ * {@see #getPackageList(PackageListObserver)}
+ */
+ public @NonNull PackageList getPackageList() {
+ return getPackageList(null);
+ }
+
+ /**
+ * Returns the list of packages installed at the time of the method call.
+ * <p>The given observer is notified when the list of installed packages
+ * changes [eg. a package was installed or uninstalled]. It will not be
+ * notified if a package is updated.
+ * <p>The package list will not be updated automatically as packages are
+ * installed / uninstalled. Any changes must be handled within the observer.
+ */
+ public abstract @NonNull PackageList getPackageList(@Nullable PackageListObserver observer);
+
+ /**
+ * Removes the observer.
+ * <p>Generally not needed. {@link #getPackageList(PackageListObserver)} will automatically
+ * remove the observer.
+ * <p>Does nothing if the observer isn't currently registered.
+ * <p>Observers are notified asynchronously and it's possible for an observer to be
+ * invoked after its been removed.
+ */
+ public abstract void removePackageListObserver(@NonNull PackageListObserver observer);
+
+ /**
* Returns a package object for the disabled system package name.
*/
public abstract @Nullable PackageParser.Package getDisabledPackage(@NonNull String packageName);
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index 3003607e5f72..0a08353cbe4c 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -28,7 +28,7 @@ import android.os.Parcelable;
*/
public final class BrightnessChangeEvent implements Parcelable {
/** Brightness in nits */
- public int brightness;
+ public float brightness;
/** Timestamp of the change {@see System.currentTimeMillis()} */
public long timeStamp;
@@ -58,7 +58,7 @@ public final class BrightnessChangeEvent implements Parcelable {
public int colorTemperature;
/** Brightness level before slider adjustment */
- public int lastBrightness;
+ public float lastBrightness;
public BrightnessChangeEvent() {
}
@@ -78,7 +78,7 @@ public final class BrightnessChangeEvent implements Parcelable {
}
private BrightnessChangeEvent(Parcel source) {
- brightness = source.readInt();
+ brightness = source.readFloat();
timeStamp = source.readLong();
packageName = source.readString();
userId = source.readInt();
@@ -87,7 +87,7 @@ public final class BrightnessChangeEvent implements Parcelable {
batteryLevel = source.readFloat();
nightMode = source.readBoolean();
colorTemperature = source.readInt();
- lastBrightness = source.readInt();
+ lastBrightness = source.readFloat();
}
public static final Creator<BrightnessChangeEvent> CREATOR =
@@ -107,7 +107,7 @@ public final class BrightnessChangeEvent implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(brightness);
+ dest.writeFloat(brightness);
dest.writeLong(timeStamp);
dest.writeString(packageName);
dest.writeInt(userId);
@@ -116,6 +116,6 @@ public final class BrightnessChangeEvent implements Parcelable {
dest.writeFloat(batteryLevel);
dest.writeBoolean(nightMode);
dest.writeInt(colorTemperature);
- dest.writeInt(lastBrightness);
+ dest.writeFloat(lastBrightness);
}
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7de667dcaa2b..97e9b9c2e2f4 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -628,13 +628,6 @@ public final class DisplayManager {
}
/**
- * @hide STOPSHIP - remove when adaptive brightness accepts curves.
- */
- public void setBrightness(int brightness) {
- mGlobal.setBrightness(brightness);
- }
-
- /**
* Sets the global display brightness configuration.
*
* @hide
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index bf4cc1d826a9..cbb5a7de7db8 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -476,18 +476,6 @@ public final class DisplayManagerGlobal {
}
/**
- * Set brightness but don't add a BrightnessChangeEvent
- * STOPSHIP remove when adaptive brightness accepts curves.
- */
- public void setBrightness(int brightness) {
- try {
- mDm.setBrightness(brightness);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /**
* Sets the global brightness configuration for a given user.
*
* @hide
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index cd551bd42e0f..3f6dd2e757ed 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -222,6 +222,11 @@ public abstract class DisplayManagerInternal {
// set by the user as opposed to being programmatically controlled by apps.
public boolean brightnessSetByUser;
+ // Set to true if screenBrightness or screenAutoBrightnessAdjustment are being set
+ // temporarily. This is typically set while the user has their finger on the brightness
+ // control, before they've selected the final brightness value.
+ public boolean brightnessIsTemporary;
+
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
@@ -280,6 +285,7 @@ public abstract class DisplayManagerInternal {
screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
screenLowPowerBrightnessFactor = other.screenLowPowerBrightnessFactor;
brightnessSetByUser = other.brightnessSetByUser;
+ brightnessIsTemporary = other.brightnessIsTemporary;
useAutoBrightness = other.useAutoBrightness;
blockScreenOn = other.blockScreenOn;
lowPowerMode = other.lowPowerMode;
@@ -303,6 +309,7 @@ public abstract class DisplayManagerInternal {
&& screenLowPowerBrightnessFactor
== other.screenLowPowerBrightnessFactor
&& brightnessSetByUser == other.brightnessSetByUser
+ && brightnessIsTemporary == other.brightnessIsTemporary
&& useAutoBrightness == other.useAutoBrightness
&& blockScreenOn == other.blockScreenOn
&& lowPowerMode == other.lowPowerMode
@@ -324,6 +331,7 @@ public abstract class DisplayManagerInternal {
+ ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+ ", screenLowPowerBrightnessFactor=" + screenLowPowerBrightnessFactor
+ ", brightnessSetByUser=" + brightnessSetByUser
+ + ", brightnessIsTemporary=" + brightnessIsTemporary
+ ", useAutoBrightness=" + useAutoBrightness
+ ", blockScreenOn=" + blockScreenOn
+ ", lowPowerMode=" + lowPowerMode
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 8afae6ec9010..61c42e1ab491 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -87,10 +87,6 @@ interface IDisplayManager {
// Requires BRIGHTNESS_SLIDER_USAGE permission.
ParceledListSlice getBrightnessEvents(String callingPackage);
- // STOPSHIP remove when adaptive brightness code is updated to accept curves.
- // Requires BRIGHTNESS_SLIDER_USAGE permission.
- void setBrightness(int brightness);
-
// Sets the global brightness configuration for a given user. Requires
// CONFIGURE_DISPLAY_BRIGHTNESS, and INTERACT_ACROSS_USER if the user being configured is not
// the same as the calling user.
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 52527ed67ae4..0a21083a0262 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -15,9 +15,13 @@
*/
package android.hardware.location;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.os.RemoteException;
+import com.android.internal.util.Preconditions;
+
import dalvik.system.CloseGuard;
import java.io.Closeable;
@@ -31,16 +35,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* @hide
*/
+@SystemApi
public class ContextHubClient implements Closeable {
/*
* The proxy to the client interface at the service.
*/
- private final IContextHubClient mClientProxy;
-
- /*
- * The callback interface associated with this client.
- */
- private final IContextHubClientCallback mCallbackInterface;
+ private IContextHubClient mClientProxy = null;
/*
* The Context Hub that this client is attached to.
@@ -51,20 +51,33 @@ public class ContextHubClient implements Closeable {
private final AtomicBoolean mIsClosed = new AtomicBoolean(false);
- /* package */ ContextHubClient(
- IContextHubClient clientProxy, IContextHubClientCallback callback,
- ContextHubInfo hubInfo) {
- mClientProxy = clientProxy;
- mCallbackInterface = callback;
+ /* package */ ContextHubClient(ContextHubInfo hubInfo) {
mAttachedHub = hubInfo;
mCloseGuard.open("close");
}
/**
+ * Sets the proxy interface of the client at the service. This method should always be called
+ * by the ContextHubManager after the client is registered at the service, and should only be
+ * called once.
+ *
+ * @param clientProxy the proxy of the client at the service
+ */
+ /* package */ void setClientProxy(IContextHubClient clientProxy) {
+ Preconditions.checkNotNull(clientProxy, "IContextHubClient cannot be null");
+ if (mClientProxy != null) {
+ throw new IllegalStateException("Cannot change client proxy multiple times");
+ }
+
+ mClientProxy = clientProxy;
+ }
+
+ /**
* Returns the hub that this client is attached to.
*
* @return the ContextHubInfo of the attached hub
*/
+ @NonNull
public ContextHubInfo getAttachedHub() {
return mAttachedHub;
}
@@ -96,12 +109,16 @@ public class ContextHubClient implements Closeable {
*
* @return the result of sending the message defined as in ContextHubTransaction.Result
*
+ * @throws NullPointerException if NanoAppMessage is null
+ *
* @see NanoAppMessage
* @see ContextHubTransaction.Result
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@ContextHubTransaction.Result
- public int sendMessageToNanoApp(NanoAppMessage message) {
+ public int sendMessageToNanoApp(@NonNull NanoAppMessage message) {
+ Preconditions.checkNotNull(message, "NanoAppMessage cannot be null");
+
try {
return mClientProxy.sendMessageToNanoApp(message);
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/location/ContextHubClientCallback.java b/core/java/android/hardware/location/ContextHubClientCallback.java
index ab19d547025d..cc2fe65dcb7e 100644
--- a/core/java/android/hardware/location/ContextHubClientCallback.java
+++ b/core/java/android/hardware/location/ContextHubClientCallback.java
@@ -15,15 +15,20 @@
*/
package android.hardware.location;
+import android.annotation.SystemApi;
+
+import java.util.concurrent.Executor;
+
/**
* A class for {@link android.hardware.location.ContextHubClient ContextHubClient} to
* receive messages and life-cycle events from nanoapps in the Context Hub at which the client is
* attached to.
*
- * This callback is registered through the
- * {@link android.hardware.location.ContextHubManager#createClient() creation} of
- * {@link android.hardware.location.ContextHubClient ContextHubClient}. Callbacks are
- * invoked in the following ways:
+ * This callback is registered through the {@link
+ * android.hardware.location.ContextHubManager#createClient(
+ * ContextHubInfo, ContextHubClientCallback, Executor) creation} of
+ * {@link android.hardware.location.ContextHubClient ContextHubClient}. Callbacks are invoked in
+ * the following ways:
* 1) Messages from nanoapps delivered through onMessageFromNanoApp may either be broadcasted
* or targeted to a specific client.
* 2) Nanoapp or Context Hub events (the remaining callbacks) are broadcasted to all clients, and
@@ -31,6 +36,7 @@ package android.hardware.location;
*
* @hide
*/
+@SystemApi
public class ContextHubClientCallback {
/**
* Callback invoked when receiving a message from a nanoapp.
@@ -38,48 +44,56 @@ public class ContextHubClientCallback {
* The message contents of this callback may either be broadcasted or targeted to the
* client receiving the invocation.
*
+ * @param client the client that is associated with this callback
* @param message the message sent by the nanoapp
*/
- public void onMessageFromNanoApp(NanoAppMessage message) {}
+ public void onMessageFromNanoApp(ContextHubClient client, NanoAppMessage message) {}
/**
* Callback invoked when the attached Context Hub has reset.
+ *
+ * @param client the client that is associated with this callback
*/
- public void onHubReset() {}
+ public void onHubReset(ContextHubClient client) {}
/**
* Callback invoked when a nanoapp aborts at the attached Context Hub.
*
+ * @param client the client that is associated with this callback
* @param nanoAppId the ID of the nanoapp that had aborted
* @param abortCode the reason for nanoapp's abort, specific to each nanoapp
*/
- public void onNanoAppAborted(long nanoAppId, int abortCode) {}
+ public void onNanoAppAborted(ContextHubClient client, long nanoAppId, int abortCode) {}
/**
* Callback invoked when a nanoapp is loaded at the attached Context Hub.
*
+ * @param client the client that is associated with this callback
* @param nanoAppId the ID of the nanoapp that had been loaded
*/
- public void onNanoAppLoaded(long nanoAppId) {}
+ public void onNanoAppLoaded(ContextHubClient client, long nanoAppId) {}
/**
* Callback invoked when a nanoapp is unloaded from the attached Context Hub.
*
+ * @param client the client that is associated with this callback
* @param nanoAppId the ID of the nanoapp that had been unloaded
*/
- public void onNanoAppUnloaded(long nanoAppId) {}
+ public void onNanoAppUnloaded(ContextHubClient client, long nanoAppId) {}
/**
* Callback invoked when a nanoapp is enabled at the attached Context Hub.
*
+ * @param client the client that is associated with this callback
* @param nanoAppId the ID of the nanoapp that had been enabled
*/
- public void onNanoAppEnabled(long nanoAppId) {}
+ public void onNanoAppEnabled(ContextHubClient client, long nanoAppId) {}
/**
* Callback invoked when a nanoapp is disabled at the attached Context Hub.
*
+ * @param client the client that is associated with this callback
* @param nanoAppId the ID of the nanoapp that had been disabled
*/
- public void onNanoAppDisabled(long nanoAppId) {}
+ public void onNanoAppDisabled(ContextHubClient client, long nanoAppId) {}
}
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index c2b280016f68..36123e3d4229 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -221,9 +221,6 @@ public class ContextHubInfo implements Parcelable {
/**
* @return the CHRE platform ID as defined in chre/version.h
- *
- * TODO(b/67734082): Expose as public API
- * @hide
*/
public long getChrePlatformId() {
return mChrePlatformId;
@@ -231,9 +228,6 @@ public class ContextHubInfo implements Parcelable {
/**
* @return the CHRE API's major version as defined in chre/version.h
- *
- * TODO(b/67734082): Expose as public API
- * @hide
*/
public byte getChreApiMajorVersion() {
return mChreApiMajorVersion;
@@ -241,9 +235,6 @@ public class ContextHubInfo implements Parcelable {
/**
* @return the CHRE API's minor version as defined in chre/version.h
- *
- * TODO(b/67734082): Expose as public API
- * @hide
*/
public byte getChreApiMinorVersion() {
return mChreApiMinorVersion;
@@ -251,9 +242,6 @@ public class ContextHubInfo implements Parcelable {
/**
* @return the CHRE patch version as defined in chre/version.h
- *
- * TODO(b/67734082): Expose as public API
- * @hide
*/
public short getChrePatchVersion() {
return mChrePatchVersion;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 4cea0acd3809..de13c8132a65 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -17,6 +17,7 @@ package android.hardware.location;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -30,6 +31,8 @@ import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.util.List;
import java.util.concurrent.Executor;
@@ -59,7 +62,11 @@ public final class ContextHubManager {
/**
* An interface to receive asynchronous communication from the context hub.
+ *
+ * @deprecated Use the more refined {@link android.hardware.location.ContextHubClientCallback}
+ * instead for notification callbacks.
*/
+ @Deprecated
public abstract static class Callback {
protected Callback() {}
@@ -75,7 +82,7 @@ public final class ContextHubManager {
public abstract void onMessageReceipt(
int hubHandle,
int nanoAppHandle,
- ContextHubMessage message);
+ @NonNull ContextHubMessage message);
}
/**
@@ -98,8 +105,13 @@ public final class ContextHubManager {
/**
* Get a handle to all the context hubs in the system
+ *
* @return array of context hub handles
+ *
+ * @deprecated Use {@link #getContextHubs()} instead. The use of handles are deprecated in the
+ * new APIs.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public int[] getContextHubHandles() {
try {
@@ -116,7 +128,11 @@ public final class ContextHubManager {
* @return ContextHubInfo Information about the requested context hub.
*
* @see ContextHubInfo
+ *
+ * @deprecated Use {@link #getContextHubs()} instead. The use of handles are deprecated in the
+ * new APIs.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public ContextHubInfo getContextHubInfo(int hubHandle) {
try {
@@ -144,9 +160,12 @@ public final class ContextHubManager {
* -1 otherwise
*
* @see NanoApp
+ *
+ * @deprecated Use {@link #loadNanoApp(ContextHubInfo, NanoAppBinary)} instead.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public int loadNanoApp(int hubHandle, NanoApp app) {
+ public int loadNanoApp(int hubHandle, @NonNull NanoApp app) {
try {
return mService.loadNanoApp(hubHandle, app);
} catch (RemoteException e) {
@@ -168,7 +187,10 @@ public final class ContextHubManager {
*
* @return 0 if the command for unloading was sent to the context hub;
* -1 otherwise
+ *
+ * @deprecated Use {@link #unloadNanoApp(ContextHubInfo, long)} instead.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public int unloadNanoApp(int nanoAppHandle) {
try {
@@ -199,13 +221,18 @@ public final class ContextHubManager {
* TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the
* correct information.
*
- * @param nanoAppHandle handle of the nanoAppInstance
- * @return NanoAppInstanceInfo Information about the nano app instance.
+ * @param nanoAppHandle handle of the nanoapp instance
+ * @return NanoAppInstanceInfo the NanoAppInstanceInfo of the nanoapp, or null if the nanoapp
+ * does not exist
*
* @see NanoAppInstanceInfo
+ *
+ * @deprecated Use {@link #queryNanoApps(ContextHubInfo)} instead to explicitly query the hub
+ * for loaded nanoapps.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
+ @Nullable public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
try {
return mService.getNanoAppInstanceInfo(nanoAppHandle);
} catch (RemoteException e) {
@@ -222,9 +249,13 @@ public final class ContextHubManager {
* @see NanoAppFilter
*
* @return int[] Array of handles to any found nano apps
+ *
+ * @deprecated Use {@link #queryNanoApps(ContextHubInfo)} instead to explicitly query the hub
+ * for loaded nanoapps.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+ @NonNull public int[] findNanoAppOnHub(int hubHandle, @NonNull NanoAppFilter filter) {
try {
return mService.findNanoAppOnHub(hubHandle, filter);
} catch (RemoteException e) {
@@ -250,9 +281,16 @@ public final class ContextHubManager {
* @see ContextHubMessage
*
* @return int 0 on success, -1 otherwise
+ *
+ * @deprecated Use {@link android.hardware.location.ContextHubClient#sendMessageToNanoApp(
+ * NanoAppMessage)} instead, after creating a
+ * {@link android.hardware.location.ContextHubClient} with
+ * {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)}
+ * or {@link #createClient(ContextHubInfo, ContextHubClientCallback)}.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) {
+ public int sendMessage(int hubHandle, int nanoAppHandle, @NonNull ContextHubMessage message) {
try {
return mService.sendMessage(hubHandle, nanoAppHandle, message);
} catch (RemoteException e) {
@@ -266,11 +304,9 @@ public final class ContextHubManager {
* @return the list of ContextHubInfo objects
*
* @see ContextHubInfo
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public List<ContextHubInfo> getContextHubs() {
+ @NonNull public List<ContextHubInfo> getContextHubs() {
try {
return mService.getContextHubs();
} catch (RemoteException e) {
@@ -342,13 +378,16 @@ public final class ContextHubManager {
*
* @return the ContextHubTransaction of the request
*
- * @see NanoAppBinary
+ * @throws NullPointerException if hubInfo or NanoAppBinary is null
*
- * @hide
+ * @see NanoAppBinary
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public ContextHubTransaction<Void> loadNanoApp(
- ContextHubInfo hubInfo, NanoAppBinary appBinary) {
+ @NonNull public ContextHubTransaction<Void> loadNanoApp(
+ @NonNull ContextHubInfo hubInfo, @NonNull NanoAppBinary appBinary) {
+ Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+ Preconditions.checkNotNull(appBinary, "NanoAppBinary cannot be null");
+
ContextHubTransaction<Void> transaction =
new ContextHubTransaction<>(ContextHubTransaction.TYPE_LOAD_NANOAPP);
IContextHubTransactionCallback callback = createTransactionCallback(transaction);
@@ -370,10 +409,13 @@ public final class ContextHubManager {
*
* @return the ContextHubTransaction of the request
*
- * @hide
+ * @throws NullPointerException if hubInfo is null
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public ContextHubTransaction<Void> unloadNanoApp(ContextHubInfo hubInfo, long nanoAppId) {
+ @NonNull public ContextHubTransaction<Void> unloadNanoApp(
+ @NonNull ContextHubInfo hubInfo, long nanoAppId) {
+ Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+
ContextHubTransaction<Void> transaction =
new ContextHubTransaction<>(ContextHubTransaction.TYPE_UNLOAD_NANOAPP);
IContextHubTransactionCallback callback = createTransactionCallback(transaction);
@@ -395,10 +437,13 @@ public final class ContextHubManager {
*
* @return the ContextHubTransaction of the request
*
- * @hide
+ * @throws NullPointerException if hubInfo is null
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public ContextHubTransaction<Void> enableNanoApp(ContextHubInfo hubInfo, long nanoAppId) {
+ @NonNull public ContextHubTransaction<Void> enableNanoApp(
+ @NonNull ContextHubInfo hubInfo, long nanoAppId) {
+ Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+
ContextHubTransaction<Void> transaction =
new ContextHubTransaction<>(ContextHubTransaction.TYPE_ENABLE_NANOAPP);
IContextHubTransactionCallback callback = createTransactionCallback(transaction);
@@ -420,10 +465,13 @@ public final class ContextHubManager {
*
* @return the ContextHubTransaction of the request
*
- * @hide
+ * @throws NullPointerException if hubInfo is null
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public ContextHubTransaction<Void> disableNanoApp(ContextHubInfo hubInfo, long nanoAppId) {
+ @NonNull public ContextHubTransaction<Void> disableNanoApp(
+ @NonNull ContextHubInfo hubInfo, long nanoAppId) {
+ Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+
ContextHubTransaction<Void> transaction =
new ContextHubTransaction<>(ContextHubTransaction.TYPE_DISABLE_NANOAPP);
IContextHubTransactionCallback callback = createTransactionCallback(transaction);
@@ -444,10 +492,13 @@ public final class ContextHubManager {
*
* @return the ContextHubTransaction of the request
*
- * @hide
+ * @throws NullPointerException if hubInfo is null
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
- public ContextHubTransaction<List<NanoAppState>> queryNanoApps(ContextHubInfo hubInfo) {
+ @NonNull public ContextHubTransaction<List<NanoAppState>> queryNanoApps(
+ @NonNull ContextHubInfo hubInfo) {
+ Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+
ContextHubTransaction<List<NanoAppState>> transaction =
new ContextHubTransaction<>(ContextHubTransaction.TYPE_QUERY_NANOAPPS);
IContextHubTransactionCallback callback = createQueryCallback(transaction);
@@ -469,9 +520,14 @@ public final class ContextHubManager {
* @see Callback
*
* @return int 0 on success, -1 otherwise
+ *
+ * @deprecated Use {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)}
+ * or {@link #createClient(ContextHubInfo, ContextHubClientCallback)} instead to
+ * register a {@link android.hardware.location.ContextHubClientCallback}.
*/
+ @Deprecated
@SuppressLint("Doclava125")
- public int registerCallback(Callback callback) {
+ public int registerCallback(@NonNull Callback callback) {
return registerCallback(callback, null);
}
@@ -498,7 +554,12 @@ public final class ContextHubManager {
* @see Callback
*
* @return int 0 on success, -1 otherwise
+ *
+ * @deprecated Use {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)}
+ * or {@link #createClient(ContextHubInfo, ContextHubClientCallback)} instead to
+ * register a {@link android.hardware.location.ContextHubClientCallback}.
*/
+ @Deprecated
@SuppressLint("Doclava125")
public int registerCallback(Callback callback, Handler handler) {
synchronized(this) {
@@ -515,47 +576,48 @@ public final class ContextHubManager {
/**
* Creates an interface to the ContextHubClient to send down to the service.
*
+ * @param client the ContextHubClient object associated with this callback
* @param callback the callback to invoke at the client process
* @param executor the executor to invoke callbacks for this client
*
* @return the callback interface
*/
private IContextHubClientCallback createClientCallback(
- ContextHubClientCallback callback, Executor executor) {
+ ContextHubClient client, ContextHubClientCallback callback, Executor executor) {
return new IContextHubClientCallback.Stub() {
@Override
public void onMessageFromNanoApp(NanoAppMessage message) {
- executor.execute(() -> callback.onMessageFromNanoApp(message));
+ executor.execute(() -> callback.onMessageFromNanoApp(client, message));
}
@Override
public void onHubReset() {
- executor.execute(() -> callback.onHubReset());
+ executor.execute(() -> callback.onHubReset(client));
}
@Override
public void onNanoAppAborted(long nanoAppId, int abortCode) {
- executor.execute(() -> callback.onNanoAppAborted(nanoAppId, abortCode));
+ executor.execute(() -> callback.onNanoAppAborted(client, nanoAppId, abortCode));
}
@Override
public void onNanoAppLoaded(long nanoAppId) {
- executor.execute(() -> callback.onNanoAppLoaded(nanoAppId));
+ executor.execute(() -> callback.onNanoAppLoaded(client, nanoAppId));
}
@Override
public void onNanoAppUnloaded(long nanoAppId) {
- executor.execute(() -> callback.onNanoAppUnloaded(nanoAppId));
+ executor.execute(() -> callback.onNanoAppUnloaded(client, nanoAppId));
}
@Override
public void onNanoAppEnabled(long nanoAppId) {
- executor.execute(() -> callback.onNanoAppEnabled(nanoAppId));
+ executor.execute(() -> callback.onNanoAppEnabled(client, nanoAppId));
}
@Override
public void onNanoAppDisabled(long nanoAppId) {
- executor.execute(() -> callback.onNanoAppDisabled(nanoAppId));
+ executor.execute(() -> callback.onNanoAppDisabled(client, nanoAppId));
}
};
}
@@ -574,31 +636,30 @@ public final class ContextHubManager {
*
* @throws IllegalArgumentException if hubInfo does not represent a valid hub
* @throws IllegalStateException if there were too many registered clients at the service
- * @throws NullPointerException if callback or hubInfo is null
+ * @throws NullPointerException if callback, hubInfo, or executor is null
*
- * @hide
* @see ContextHubClientCallback
*/
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback,
@NonNull @CallbackExecutor Executor executor) {
- if (callback == null) {
- throw new NullPointerException("Callback cannot be null");
- }
- if (hubInfo == null) {
- throw new NullPointerException("Hub info cannot be null");
- }
+ Preconditions.checkNotNull(callback, "Callback cannot be null");
+ Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+ Preconditions.checkNotNull(executor, "Executor cannot be null");
- IContextHubClientCallback clientInterface = createClientCallback(callback, executor);
+ ContextHubClient client = new ContextHubClient(hubInfo);
+ IContextHubClientCallback clientInterface = createClientCallback(
+ client, callback, executor);
- IContextHubClient client;
+ IContextHubClient clientProxy;
try {
- client = mService.createClient(clientInterface, hubInfo.getId());
+ clientProxy = mService.createClient(clientInterface, hubInfo.getId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- return new ContextHubClient(client, clientInterface, hubInfo);
+ client.setClientProxy(clientProxy);
+ return client;
}
/**
@@ -612,7 +673,7 @@ public final class ContextHubManager {
* @throws IllegalArgumentException if hubInfo does not represent a valid hub
* @throws IllegalStateException if there were too many registered clients at the service
* @throws NullPointerException if callback or hubInfo is null
- * @hide
+ *
* @see ContextHubClientCallback
*/
@NonNull public ContextHubClient createClient(
@@ -628,9 +689,13 @@ public final class ContextHubManager {
* @param callback method to deregister
*
* @return int 0 on success, -1 otherwise
+ *
+ * @deprecated Use {@link android.hardware.location.ContextHubClient#close()} to unregister
+ * a {@link android.hardware.location.ContextHubClientCallback}.
*/
@SuppressLint("Doclava125")
- public int unregisterCallback(Callback callback) {
+ @Deprecated
+ public int unregisterCallback(@NonNull Callback callback) {
synchronized(this) {
if (callback != mCallback) {
Log.w(TAG, "Cannot recognize callback!");
@@ -679,8 +744,6 @@ public final class ContextHubManager {
synchronized (this) {
mLocalCallback.onMessageReceipt(hubId, nanoAppId, message);
}
- } else {
- Log.d(TAG, "Context hub manager client callback is NULL");
}
}
};
@@ -694,7 +757,7 @@ public final class ContextHubManager {
try {
mService.registerCallback(mClientCallback);
} catch (RemoteException e) {
- Log.w(TAG, "Could not register callback:" + e);
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index a1b743da785b..bc7efef55bcf 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -18,9 +18,12 @@ package android.hardware.location;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Handler;
import android.os.HandlerExecutor;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.CountDownLatch;
@@ -35,17 +38,19 @@ import java.util.concurrent.TimeoutException;
* through the ContextHubManager APIs. The caller can either retrieve the result
* synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
* asynchronously through a user-defined listener
- * ({@link #setOnCompleteListener(Listener, Executor)} )}).
+ * ({@link #setOnCompleteListener(OnCompleteListener, Executor)} )}).
*
* @param <T> the type of the contents in the transaction response
*
* @hide
*/
+@SystemApi
public class ContextHubTransaction<T> {
private static final String TAG = "ContextHubTransaction";
/**
* Constants describing the type of a transaction through the Context Hub Service.
+ * {@hide}
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "TYPE_" }, value = {
@@ -65,6 +70,7 @@ public class ContextHubTransaction<T> {
/**
* Constants describing the result of a transaction or request through the Context Hub Service.
+ * {@hide}
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "RESULT_" }, value = {
@@ -72,7 +78,7 @@ public class ContextHubTransaction<T> {
RESULT_FAILED_UNKNOWN,
RESULT_FAILED_BAD_PARAMS,
RESULT_FAILED_UNINITIALIZED,
- RESULT_FAILED_PENDING,
+ RESULT_FAILED_BUSY,
RESULT_FAILED_AT_HUB,
RESULT_FAILED_TIMEOUT,
RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
@@ -95,7 +101,7 @@ public class ContextHubTransaction<T> {
/**
* Failure mode when there are too many transactions pending.
*/
- public static final int RESULT_FAILED_PENDING = 4;
+ public static final int RESULT_FAILED_BUSY = 4;
/**
* Failure mode when the request went through, but failed asynchronously at the hub.
*/
@@ -151,7 +157,7 @@ public class ContextHubTransaction<T> {
* @param <L> the type of the contents in the transaction response
*/
@FunctionalInterface
- public interface Listener<L> {
+ public interface OnCompleteListener<L> {
/**
* The listener function to invoke when the transaction completes.
*
@@ -181,7 +187,7 @@ public class ContextHubTransaction<T> {
/*
* The listener to be invoked when the transaction completes.
*/
- private ContextHubTransaction.Listener<T> mListener = null;
+ private ContextHubTransaction.OnCompleteListener<T> mListener = null;
/*
* Synchronization latch used to block on response.
@@ -272,8 +278,8 @@ public class ContextHubTransaction<T> {
* A transaction can be invalidated if the process owning the transaction is no longer active
* and the reference to this object is lost.
*
- * This method or {@link #setOnCompleteListener(ContextHubTransaction.Listener)} can only be
- * invoked once, or an IllegalStateException will be thrown.
+ * This method or {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener)} can
+ * only be invoked once, or an IllegalStateException will be thrown.
*
* @param listener the listener to be invoked upon completion
* @param executor the executor to invoke the callback
@@ -282,15 +288,11 @@ public class ContextHubTransaction<T> {
* @throws NullPointerException if the callback or handler is null
*/
public void setOnCompleteListener(
- @NonNull ContextHubTransaction.Listener<T> listener,
+ @NonNull ContextHubTransaction.OnCompleteListener<T> listener,
@NonNull @CallbackExecutor Executor executor) {
synchronized (this) {
- if (listener == null) {
- throw new NullPointerException("Listener cannot be null");
- }
- if (executor == null) {
- throw new NullPointerException("Executor cannot be null");
- }
+ Preconditions.checkNotNull(listener, "OnCompleteListener cannot be null");
+ Preconditions.checkNotNull(executor, "Executor cannot be null");
if (mListener != null) {
throw new IllegalStateException(
"Cannot set ContextHubTransaction listener multiple times");
@@ -308,18 +310,19 @@ public class ContextHubTransaction<T> {
/**
* Sets the listener to be invoked invoked when the transaction completes.
*
- * Equivalent to {@link #setOnCompleteListener(ContextHubTransaction.Listener, Executor)}
- * with the executor using the main thread's Looper.
+ * Equivalent to {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener,
+ * Executor)} with the executor using the main thread's Looper.
*
- * This method or {@link #setOnCompleteListener(ContextHubTransaction.Listener, Executor)}
- * can only be invoked once, or an IllegalStateException will be thrown.
+ * This method or {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener,
+ * Executor)} can only be invoked once, or an IllegalStateException will be thrown.
*
* @param listener the listener to be invoked upon completion
*
* @throws IllegalStateException if this method is called multiple times
* @throws NullPointerException if the callback is null
*/
- public void setOnCompleteListener(@NonNull ContextHubTransaction.Listener<T> listener) {
+ public void setOnCompleteListener(
+ @NonNull ContextHubTransaction.OnCompleteListener<T> listener) {
setOnCompleteListener(listener, new HandlerExecutor(Handler.getMain()));
}
@@ -337,9 +340,7 @@ public class ContextHubTransaction<T> {
*/
/* package */ void setResponse(ContextHubTransaction.Response<T> response) {
synchronized (this) {
- if (response == null) {
- throw new NullPointerException("Response cannot be null");
- }
+ Preconditions.checkNotNull(response, "Response cannot be null");
if (mIsResponseSet) {
throw new IllegalStateException(
"Cannot set response of ContextHubTransaction multiple times");
diff --git a/core/java/android/hardware/location/NanoAppBinary.java b/core/java/android/hardware/location/NanoAppBinary.java
index 934e9e48c01a..ba01ca251321 100644
--- a/core/java/android/hardware/location/NanoAppBinary.java
+++ b/core/java/android/hardware/location/NanoAppBinary.java
@@ -15,6 +15,7 @@
*/
package android.hardware.location;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -27,6 +28,7 @@ import java.util.Arrays;
/**
* @hide
*/
+@SystemApi
public final class NanoAppBinary implements Parcelable {
private static final String TAG = "NanoAppBinary";
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index f73fd87b1a19..c00819bde6dc 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -90,11 +90,6 @@ public class NanoAppInstanceInfo {
/**
* Get the application version
*
- * NOTE: There is a race condition where shortly after loading, this
- * may return -1 instead of the correct version.
- *
- * TODO(b/30970527): Fix this race condition.
- *
* @return int - version of the app
*/
public int getAppVersion() {
diff --git a/core/java/android/hardware/location/NanoAppMessage.java b/core/java/android/hardware/location/NanoAppMessage.java
index 202867490fb9..716a1946c540 100644
--- a/core/java/android/hardware/location/NanoAppMessage.java
+++ b/core/java/android/hardware/location/NanoAppMessage.java
@@ -15,6 +15,7 @@
*/
package android.hardware.location;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,6 +26,7 @@ import android.os.Parcelable;
*
* @hide
*/
+@SystemApi
public final class NanoAppMessage implements Parcelable {
private long mNanoAppId;
private int mMessageType;
diff --git a/core/java/android/hardware/location/NanoAppState.java b/core/java/android/hardware/location/NanoAppState.java
index 644031b034d5..d05277d484a6 100644
--- a/core/java/android/hardware/location/NanoAppState.java
+++ b/core/java/android/hardware/location/NanoAppState.java
@@ -15,6 +15,7 @@
*/
package android.hardware.location;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,6 +24,7 @@ import android.os.Parcelable;
*
* @hide
*/
+@SystemApi
public final class NanoAppState implements Parcelable {
private long mNanoAppId;
private int mNanoAppVersion;
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 4d54e31b8c5d..9b6515c9ebf1 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -38,6 +38,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -645,7 +646,8 @@ public class RadioManager {
private final boolean mAf;
private final boolean mEa;
- FmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
+ /** @hide */
+ public FmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
boolean stereo, boolean rds, boolean ta, boolean af, boolean ea) {
super(region, type, lowerLimit, upperLimit, spacing);
mStereo = stereo;
@@ -771,7 +773,8 @@ public class RadioManager {
private final boolean mStereo;
- AmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
+ /** @hide */
+ public AmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
boolean stereo) {
super(region, type, lowerLimit, upperLimit, spacing);
mStereo = stereo;
@@ -843,10 +846,10 @@ public class RadioManager {
/** Radio band configuration. */
public static class BandConfig implements Parcelable {
- final BandDescriptor mDescriptor;
+ @NonNull final BandDescriptor mDescriptor;
BandConfig(BandDescriptor descriptor) {
- mDescriptor = descriptor;
+ mDescriptor = Objects.requireNonNull(descriptor);
}
BandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing) {
@@ -968,7 +971,8 @@ public class RadioManager {
private final boolean mAf;
private final boolean mEa;
- FmBandConfig(FmBandDescriptor descriptor) {
+ /** @hide */
+ public FmBandConfig(FmBandDescriptor descriptor) {
super((BandDescriptor)descriptor);
mStereo = descriptor.isStereoSupported();
mRds = descriptor.isRdsSupported();
@@ -1204,7 +1208,8 @@ public class RadioManager {
public static class AmBandConfig extends BandConfig {
private final boolean mStereo;
- AmBandConfig(AmBandDescriptor descriptor) {
+ /** @hide */
+ public AmBandConfig(AmBandDescriptor descriptor) {
super((BandDescriptor)descriptor);
mStereo = descriptor.isStereoSupported();
}
diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java
index 42e43c8aea1e..5425bf534ebd 100644
--- a/core/java/android/net/NetworkWatchlistManager.java
+++ b/core/java/android/net/NetworkWatchlistManager.java
@@ -59,8 +59,8 @@ public class NetworkWatchlistManager {
/**
* Report network watchlist records if necessary.
*
- * Watchlist report process will run summarize records into a single report, then the
- * report will be processed by differential privacy framework and store it on disk.
+ * Watchlist report process will summarize records into a single report, then the
+ * report will be processed by differential privacy framework and stored on disk.
*
* @hide
*/
@@ -72,4 +72,18 @@ public class NetworkWatchlistManager {
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Reload network watchlist.
+ *
+ * @hide
+ */
+ public void reloadWatchlist() {
+ try {
+ mNetworkWatchlistManager.reloadWatchlist();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to reload watchlist");
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1e847c595df0..d4d74f438e5d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -180,6 +180,11 @@ public abstract class BatteryStats implements Parcelable {
public static final int FOREGROUND_SERVICE = 22;
/**
+ * A constant indicating an aggregate wifi multicast timer
+ */
+ public static final int WIFI_AGGREGATE_MULTICAST_ENABLED = 23;
+
+ /**
* Include all of the data in the stats, including previously saved data.
*/
public static final int STATS_SINCE_CHARGED = 0;
@@ -2334,6 +2339,22 @@ public abstract class BatteryStats implements Parcelable {
};
/**
+ * Returns total time for WiFi Multicast Wakelock timer.
+ * Note that this may be different from the sum of per uid timer values.
+ *
+ * {@hide}
+ */
+ public abstract long getWifiMulticastWakelockTime(long elapsedRealtimeUs, int which);
+
+ /**
+ * Returns total time for WiFi Multicast Wakelock timer
+ * Note that this may be different from the sum of per uid timer values.
+ *
+ * {@hide}
+ */
+ public abstract int getWifiMulticastWakelockCount(int which);
+
+ /**
* Returns the time in microseconds that wifi has been on while the device was
* running on battery.
*
@@ -3442,16 +3463,13 @@ public abstract class BatteryStats implements Parcelable {
screenDozeTime / 1000);
- // Calculate both wakelock and wifi multicast wakelock times across all uids.
+ // Calculate wakelock times across all uids.
long fullWakeLockTimeTotal = 0;
long partialWakeLockTimeTotal = 0;
- long multicastWakeLockTimeTotalMicros = 0;
- int multicastWakeLockCountTotal = 0;
for (int iu = 0; iu < NU; iu++) {
final Uid u = uidStats.valueAt(iu);
- // First calculating the wakelock stats
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
= u.getWakelockStats();
for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -3469,13 +3487,6 @@ public abstract class BatteryStats implements Parcelable {
rawRealtime, which);
}
}
-
- // Now calculating the wifi multicast wakelock stats
- final Timer mcTimer = u.getMulticastWakelockStats();
- if (mcTimer != null) {
- multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
- multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
- }
}
// Dump network stats
@@ -3592,6 +3603,9 @@ public abstract class BatteryStats implements Parcelable {
dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_COUNT_DATA, args);
// Dump Multicast total stats
+ final long multicastWakeLockTimeTotalMicros =
+ getWifiMulticastWakelockTime(rawRealtime, which);
+ final int multicastWakeLockCountTotal = getWifiMulticastWakelockCount(which);
dumpLine(pw, 0 /* uid */, category, WIFI_MULTICAST_TOTAL_DATA,
multicastWakeLockTimeTotalMicros / 1000,
multicastWakeLockCountTotal);
@@ -4456,18 +4470,15 @@ public abstract class BatteryStats implements Parcelable {
pw.print(" Connectivity changes: "); pw.println(connChanges);
}
- // Calculate both wakelock and wifi multicast wakelock times across all uids.
+ // Calculate wakelock times across all uids.
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
- long multicastWakeLockTimeTotalMicros = 0;
- int multicastWakeLockCountTotal = 0;
final ArrayList<TimerEntry> timers = new ArrayList<>();
for (int iu = 0; iu < NU; iu++) {
final Uid u = uidStats.valueAt(iu);
- // First calculate wakelock statistics
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
= u.getWakelockStats();
for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -4495,13 +4506,6 @@ public abstract class BatteryStats implements Parcelable {
}
}
}
-
- // Next calculate wifi multicast wakelock statistics
- final Timer mcTimer = u.getMulticastWakelockStats();
- if (mcTimer != null) {
- multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
- multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
- }
}
final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
@@ -4531,6 +4535,9 @@ public abstract class BatteryStats implements Parcelable {
pw.println(sb.toString());
}
+ final long multicastWakeLockTimeTotalMicros =
+ getWifiMulticastWakelockTime(rawRealtime, which);
+ final int multicastWakeLockCountTotal = getWifiMulticastWakelockCount(which);
if (multicastWakeLockTimeTotalMicros != 0) {
sb.setLength(0);
sb.append(prefix);
@@ -7051,6 +7058,28 @@ public abstract class BatteryStats implements Parcelable {
}
}
}
+
+ for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) {
+ final long[] timesMs = u.getCpuFreqTimes(which, procState);
+ if (timesMs != null && timesMs.length == cpuFreqs.length) {
+ long[] screenOffTimesMs = u.getScreenOffCpuFreqTimes(which, procState);
+ if (screenOffTimesMs == null) {
+ screenOffTimesMs = new long[timesMs.length];
+ }
+ final long procToken = proto.start(UidProto.Cpu.BY_PROCESS_STATE);
+ proto.write(UidProto.Cpu.ByProcessState.PROCESS_STATE, procState);
+ for (int ic = 0; ic < timesMs.length; ++ic) {
+ long cToken = proto.start(UidProto.Cpu.ByProcessState.BY_FREQUENCY);
+ proto.write(UidProto.Cpu.ByFrequency.FREQUENCY_INDEX, ic + 1);
+ proto.write(UidProto.Cpu.ByFrequency.TOTAL_DURATION_MS,
+ timesMs[ic]);
+ proto.write(UidProto.Cpu.ByFrequency.SCREEN_OFF_DURATION_MS,
+ screenOffTimesMs[ic]);
+ proto.end(cToken);
+ }
+ proto.end(procToken);
+ }
+ }
proto.end(cpuToken);
// Flashlight (FLASHLIGHT_DATA)
@@ -7535,22 +7564,9 @@ public abstract class BatteryStats implements Parcelable {
proto.end(mToken);
// Wifi multicast wakelock total stats (WIFI_MULTICAST_WAKELOCK_TOTAL_DATA)
- // Calculate multicast wakelock stats across all uids.
- long multicastWakeLockTimeTotalUs = 0;
- int multicastWakeLockCountTotal = 0;
-
- for (int iu = 0; iu < uidStats.size(); iu++) {
- final Uid u = uidStats.valueAt(iu);
-
- final Timer mcTimer = u.getMulticastWakelockStats();
-
- if (mcTimer != null) {
- multicastWakeLockTimeTotalUs +=
- mcTimer.getTotalTimeLocked(rawRealtimeUs, which);
- multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
- }
- }
-
+ final long multicastWakeLockTimeTotalUs =
+ getWifiMulticastWakelockTime(rawRealtimeUs, which);
+ final int multicastWakeLockCountTotal = getWifiMulticastWakelockCount(which);
final long wmctToken = proto.start(SystemProto.WIFI_MULTICAST_WAKELOCK_TOTAL);
proto.write(SystemProto.WifiMulticastWakelockTotal.DURATION_MS,
multicastWakeLockTimeTotalUs / 1000);
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 3ca1005b8c98..5c5e351d2eeb 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -388,6 +388,8 @@ public class Handler {
* The runnable will be run on the thread to which this handler is attached.
*
* @param r The Runnable that will be executed.
+ * @param token An instance which can be used to cancel {@code r} via
+ * {@link #removeCallbacksAndMessages}.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
*
@@ -430,6 +432,32 @@ public class Handler {
}
/**
+ * Causes the Runnable r to be added to the message queue, to be run
+ * after the specified amount of time elapses.
+ * The runnable will be run on the thread to which this handler
+ * is attached.
+ * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
+ * Time spent in deep sleep will add an additional delay to execution.
+ *
+ * @param r The Runnable that will be executed.
+ * @param token An instance which can be used to cancel {@code r} via
+ * {@link #removeCallbacksAndMessages}.
+ * @param delayMillis The delay (in milliseconds) until the Runnable
+ * will be executed.
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting. Note that a
+ * result of true does not mean the Runnable will be processed --
+ * if the looper is quit before the delivery time of the message
+ * occurs then the message will be dropped.
+ */
+ public final boolean postDelayed(Runnable r, Object token, long delayMillis)
+ {
+ return sendMessageDelayed(getPostMessage(r, token), delayMillis);
+ }
+
+ /**
* Posts a message to an object that implements Runnable.
* Causes the Runnable r to executed on the next iteration through the
* message queue. The runnable will be run on the thread to which this
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 3db12ed0815f..29812e8ab06e 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -71,7 +71,7 @@ interface IStatsManager {
* Fetches data for the specified configuration key. Returns a byte array representing proto
* wire-encoded of ConfigMetricsReportList.
*/
- byte[] getData(in String key);
+ byte[] getData(in long key);
/**
* Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
@@ -86,7 +86,7 @@ interface IStatsManager {
*
* Returns if this configuration was correctly registered.
*/
- boolean addConfiguration(in String configKey, in byte[] config, in String pkg, in String cls);
+ boolean addConfiguration(in long configKey, in byte[] config, in String pkg, in String cls);
/**
* Removes the configuration with the matching config key. No-op if this config key does not
@@ -94,5 +94,5 @@ interface IStatsManager {
*
* Returns if this configuration key was removed.
*/
- boolean removeConfiguration(in String configKey);
+ boolean removeConfiguration(in long configKey);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index dd9fd93ed472..38993b71a31d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2197,7 +2197,8 @@ public class UserManager {
/**
* Similar to {@link #trySetQuietModeEnabled(boolean, UserHandle)}, except you can specify
- * a target to start when user is unlocked.
+ * a target to start when user is unlocked. If {@code target} is specified, caller must have
+ * the {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @see {@link #trySetQuietModeEnabled(boolean, UserHandle)}
* @hide
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 9833fe15dd3c..4c587a836de8 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1115,12 +1115,14 @@ public class StorageManager {
/** {@hide} */
public static Pair<String, Long> getPrimaryStoragePathAndSize() {
return Pair.create(null,
- FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()));
+ FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
+ + Environment.getRootDirectory().getTotalSpace()));
}
/** {@hide} */
public long getPrimaryStorageSize() {
- return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace());
+ return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
+ + Environment.getRootDirectory().getTotalSpace());
}
/** {@hide} */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index acac6718c9be..009fc395ff3b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5778,6 +5778,14 @@ public final class Settings {
"touch_exploration_granted_accessibility_services";
/**
+ * Uri of the slice that's presented on the keyguard.
+ * Defaults to a slice with the date and next alarm.
+ *
+ * @hide
+ */
+ public static final String KEYGUARD_SLICE_URI = "keyguard_slice_uri";
+
+ /**
* Whether to speak passwords while in accessibility mode.
*
* @deprecated The speaking of passwords is controlled by individual accessibility services.
@@ -8782,6 +8790,7 @@ public final class Settings {
* Type: string package name or null if the feature is either not provided or disabled.
* @hide
*/
+ @TestApi
public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
/**
diff --git a/core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java b/core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java
index 72a138a629cf..0cf8da5b3a86 100644
--- a/core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java
+++ b/core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java
@@ -426,7 +426,7 @@ public class RecoverableKeyStoreLoader {
* Imports keys.
*
* @param sessionId Id for recovery session, same as in
- * {@link #startRecoverySession(String, byte[], byte[], byte[], List)} on}.
+ * {@link #startRecoverySession(String, byte[], byte[], byte[], List)}.
* @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
* @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
* and session. KeyStore only uses package names from the application info in {@link
diff --git a/core/java/android/service/autofill/EditDistanceScorer.java b/core/java/android/service/autofill/EditDistanceScorer.java
index 0706b377bbe8..97a386866665 100644
--- a/core/java/android/service/autofill/EditDistanceScorer.java
+++ b/core/java/android/service/autofill/EditDistanceScorer.java
@@ -16,8 +16,7 @@
package android.service.autofill;
import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.annotation.TestApi;
import android.view.autofill.AutofillValue;
/**
@@ -25,13 +24,20 @@ import android.view.autofill.AutofillValue;
* by the user and the expected value predicted by an autofill service.
*/
// TODO(b/70291841): explain algorithm once it's fully implemented
-public final class EditDistanceScorer extends InternalScorer implements Scorer, Parcelable {
+/** @hide */
+@TestApi
+public final class EditDistanceScorer {
private static final EditDistanceScorer sInstance = new EditDistanceScorer();
+ /** @hide */
+ public static final String NAME = "EDIT_DISTANCE";
+
/**
* Gets the singleton instance.
*/
+ @TestApi
+ /** @hide */
public static EditDistanceScorer getInstance() {
return sInstance;
}
@@ -39,59 +45,32 @@ public final class EditDistanceScorer extends InternalScorer implements Scorer,
private EditDistanceScorer() {
}
- /** @hide */
- @Override
- public float getScore(@NonNull AutofillValue actualValue, @NonNull String userData) {
- if (actualValue == null || !actualValue.isText() || userData == null) return 0;
+ /**
+ * Returns the classification score between an actual {@link AutofillValue} filled
+ * by the user and the expected value predicted by an autofill service.
+ *
+ * <p>A full-match is {@code 1.0} (representing 100%), a full mismatch is {@code 0.0} and
+ * partial mathces are something in between, typically using edit-distance algorithms.
+ *
+ * @hide
+ */
+ @TestApi
+ public float getScore(@NonNull AutofillValue actualValue, @NonNull String userDataValue) {
+ if (actualValue == null || !actualValue.isText() || userDataValue == null) return 0;
// TODO(b/70291841): implement edit distance - currently it's returning either 0, 100%, or
// partial match when number of chars match
final String textValue = actualValue.getTextValue().toString();
final int total = textValue.length();
- if (total != userData.length()) return 0F;
+ if (total != userDataValue.length()) return 0F;
int matches = 0;
for (int i = 0; i < total; i++) {
if (Character.toLowerCase(textValue.charAt(i)) == Character
- .toLowerCase(userData.charAt(i))) {
+ .toLowerCase(userDataValue.charAt(i))) {
matches++;
}
}
return ((float) matches) / total;
}
-
- /////////////////////////////////////
- // Object "contract" methods. //
- /////////////////////////////////////
- @Override
- public String toString() {
- return "EditDistanceScorer";
- }
-
- /////////////////////////////////////
- // Parcelable "contract" methods. //
- /////////////////////////////////////
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- // Do nothing
- }
-
- public static final Parcelable.Creator<EditDistanceScorer> CREATOR =
- new Parcelable.Creator<EditDistanceScorer>() {
- @Override
- public EditDistanceScorer createFromParcel(Parcel parcel) {
- return EditDistanceScorer.getInstance();
- }
-
- @Override
- public EditDistanceScorer[] newArray(int size) {
- return new EditDistanceScorer[size];
- }
- };
}
diff --git a/core/java/android/service/autofill/FieldClassification.aidl b/core/java/android/service/autofill/FieldClassification.aidl
new file mode 100644
index 000000000000..42f7f0252d6d
--- /dev/null
+++ b/core/java/android/service/autofill/FieldClassification.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+
+package android.service.autofill;
+
+parcelable FieldClassification.AlgorithmInfo;
diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java
index 001b2917aadf..536180335a83 100644
--- a/core/java/android/service/autofill/FieldClassification.java
+++ b/core/java/android/service/autofill/FieldClassification.java
@@ -106,18 +106,20 @@ public final class FieldClassification {
/**
* Represents the score of a {@link UserData} entry for the field.
*
- * <p>The score is defined by {@link #getScore()} and the entry is identified by
- * {@link #getRemoteId()}.
+ * <p>The score is calculated by the given {@link #getAlgorithm() algorithm} and
+ * the entry is identified by {@link #getRemoteId()}.
*/
public static final class Match {
private final String mRemoteId;
private final float mScore;
+ private final String mAlgorithm;
/** @hide */
- public Match(String remoteId, float score) {
+ public Match(String remoteId, float score, String algorithm) {
mRemoteId = Preconditions.checkNotNull(remoteId);
mScore = score;
+ mAlgorithm = algorithm;
}
/**
@@ -140,29 +142,46 @@ public final class FieldClassification {
* <li>Any other value is a partial match.
* </ul>
*
- * <p>How the score is calculated depends on the algorithm used by the {@link Scorer}
- * implementation.
+ * <p>How the score is calculated depends on the
+ * {@link UserData.Builder#setFieldClassificationAlgorithm(String, android.os.Bundle)
+ * algorithm} used.
*/
public float getScore() {
return mScore;
}
+ /**
+ * Gets the algorithm used to calculate this score.
+ *
+ * <p>Typically, this is either the algorithm set by
+ * {@link UserData.Builder#setFieldClassificationAlgorithm(String, android.os.Bundle)},
+ * or the
+ * {@link android.view.autofill.AutofillManager#getDefaultFieldClassificationAlgorithm()}.
+ */
+ @NonNull
+ public String getAlgorithm() {
+ return mAlgorithm;
+ }
+
@Override
public String toString() {
if (!sDebug) return super.toString();
final StringBuilder string = new StringBuilder("Match: remoteId=");
Helper.appendRedacted(string, mRemoteId);
- return string.append(", score=").append(mScore).toString();
+ return string.append(", score=").append(mScore)
+ .append(", algorithm=").append(mAlgorithm)
+ .toString();
}
private void writeToParcel(@NonNull Parcel parcel) {
parcel.writeString(mRemoteId);
parcel.writeFloat(mScore);
+ parcel.writeString(mAlgorithm);
}
private static Match readFromParcel(@NonNull Parcel parcel) {
- return new Match(parcel.readString(), parcel.readFloat());
+ return new Match(parcel.readString(), parcel.readFloat(), parcel.readString());
}
}
}
diff --git a/core/java/android/service/autofill/InternalScorer.java b/core/java/android/service/autofill/InternalScorer.java
deleted file mode 100644
index 0da5afc2331d..000000000000
--- a/core/java/android/service/autofill/InternalScorer.java
+++ /dev/null
@@ -1,40 +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.
- */
-package android.service.autofill;
-
-import android.annotation.NonNull;
-import android.annotation.TestApi;
-import android.os.Parcelable;
-import android.view.autofill.AutofillValue;
-
-/**
- * Superclass of all scorer the system understands. As this is not public all
- * subclasses have to implement {@link Scorer} again.
- *
- * @hide
- */
-@TestApi
-public abstract class InternalScorer implements Scorer, Parcelable {
-
- /**
- * Returns the classification score between an actual {@link AutofillValue} filled
- * by the user and the expected value predicted by an autofill service.
- *
- * <p>A full-match is {@code 1.0} (representing 100%), a full mismatch is {@code 0.0} and
- * partial mathces are something in between, typically using edit-distance algorithms.
- */
- public abstract float getScore(@NonNull AutofillValue actualValue, @NonNull String userData);
-}
diff --git a/core/java/android/service/autofill/UserData.aidl b/core/java/android/service/autofill/UserData.aidl
index 76016ded424a..19282e0e7c85 100644
--- a/core/java/android/service/autofill/UserData.aidl
+++ b/core/java/android/service/autofill/UserData.aidl
@@ -17,4 +17,3 @@
package android.service.autofill;
parcelable UserData;
-parcelable UserData.Constraints;
diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java
index f0cc360fe075..2f9225acc520 100644
--- a/core/java/android/service/autofill/UserData.java
+++ b/core/java/android/service/autofill/UserData.java
@@ -25,10 +25,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.ContentResolver;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Settings;
+import android.service.autofill.FieldClassification.Match;
import android.util.Log;
+import android.view.autofill.AutofillManager;
import android.view.autofill.Helper;
import com.android.internal.util.Preconditions;
@@ -49,21 +52,32 @@ public final class UserData implements Parcelable {
private static final int DEFAULT_MIN_VALUE_LENGTH = 5;
private static final int DEFAULT_MAX_VALUE_LENGTH = 100;
- private final InternalScorer mScorer;
+ private final String mAlgorithm;
+ private final Bundle mAlgorithmArgs;
private final String[] mRemoteIds;
private final String[] mValues;
private UserData(Builder builder) {
- mScorer = builder.mScorer;
+ mAlgorithm = builder.mAlgorithm;
+ mAlgorithmArgs = builder.mAlgorithmArgs;
mRemoteIds = new String[builder.mRemoteIds.size()];
builder.mRemoteIds.toArray(mRemoteIds);
mValues = new String[builder.mValues.size()];
builder.mValues.toArray(mValues);
}
+ /**
+ * Gets the name of the algorithm that is used to calculate
+ * {@link Match#getScore() match scores}.
+ */
+ @Nullable
+ public String getFieldClassificationAlgorithm() {
+ return mAlgorithm;
+ }
+
/** @hide */
- public InternalScorer getScorer() {
- return mScorer;
+ public Bundle getAlgorithmArgs() {
+ return mAlgorithmArgs;
}
/** @hide */
@@ -78,7 +92,9 @@ public final class UserData implements Parcelable {
/** @hide */
public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("Scorer: "); pw.println(mScorer);
+ pw.print(prefix); pw.print("Algorithm: "); pw.print(mAlgorithm);
+ pw.print(" Args: "); pw.println(mAlgorithmArgs);
+
// Cannot disclose remote ids or values because they could contain PII
pw.print(prefix); pw.print("Remote ids size: "); pw.println(mRemoteIds.length);
for (int i = 0; i < mRemoteIds.length; i++) {
@@ -105,9 +121,10 @@ public final class UserData implements Parcelable {
* A builder for {@link UserData} objects.
*/
public static final class Builder {
- private final InternalScorer mScorer;
private final ArrayList<String> mRemoteIds;
private final ArrayList<String> mValues;
+ private String mAlgorithm;
+ private Bundle mAlgorithmArgs;
private boolean mDestroyed;
/**
@@ -120,13 +137,9 @@ public final class UserData implements Parcelable {
* <li>{@code value} is empty
* <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}
* <li>the length of {@code value} is higher than {@link UserData#getMaxValueLength()}
- * <li>{@code scorer} is not instance of a class provided by the Android System.
* </ol>
*/
- public Builder(@NonNull Scorer scorer, @NonNull String remoteId, @NonNull String value) {
- Preconditions.checkArgument((scorer instanceof InternalScorer),
- "not provided by Android System: " + scorer);
- mScorer = (InternalScorer) scorer;
+ public Builder(@NonNull String remoteId, @NonNull String value) {
checkValidRemoteId(remoteId);
checkValidValue(value);
final int capacity = getMaxUserDataSize();
@@ -137,6 +150,31 @@ public final class UserData implements Parcelable {
}
/**
+ * Sets the algorithm used for <a href="#FieldClassification">field classification</a>.
+ *
+ * <p>The currently available algorithms can be retrieve through
+ * {@link AutofillManager#getAvailableFieldClassificationAlgorithms()}.
+ *
+ * <p><b>Note: </b>The available algorithms in the Android System can change dinamically,
+ * so it's not guaranteed that the algorithm set here is the one that will be effectually
+ * used. If the algorithm set here is not available at runtime, the
+ * {@link AutofillManager#getDefaultFieldClassificationAlgorithm()} is used instead.
+ * You can verify which algorithm was used by calling
+ * {@link FieldClassification.Match#getAlgorithm()}.
+ *
+ * @param name name of the algorithm or {@code null} to used default.
+ * @param args optional arguments to the algorithm.
+ *
+ * @return this builder
+ */
+ public Builder setFieldClassificationAlgorithm(@Nullable String name,
+ @Nullable Bundle args) {
+ mAlgorithm = name;
+ mAlgorithmArgs = args;
+ return this;
+ }
+
+ /**
* Adds a new value for user data.
*
* @param remoteId unique string used to identify the user data.
@@ -211,7 +249,7 @@ public final class UserData implements Parcelable {
public String toString() {
if (!sDebug) return super.toString();
- final StringBuilder builder = new StringBuilder("UserData: [scorer=").append(mScorer);
+ final StringBuilder builder = new StringBuilder("UserData: [algorithm=").append(mAlgorithm);
// Cannot disclose remote ids or values because they could contain PII
builder.append(", remoteIds=");
Helper.appendRedacted(builder, mRemoteIds);
@@ -231,9 +269,10 @@ public final class UserData implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeParcelable(mScorer, flags);
parcel.writeStringArray(mRemoteIds);
parcel.writeStringArray(mValues);
+ parcel.writeString(mAlgorithm);
+ parcel.writeBundle(mAlgorithmArgs);
}
public static final Parcelable.Creator<UserData> CREATOR =
@@ -243,10 +282,10 @@ public final class UserData implements Parcelable {
// Always go through the builder to ensure the data ingested by
// the system obeys the contract of the builder to avoid attacks
// using specially crafted parcels.
- final InternalScorer scorer = parcel.readParcelable(null);
final String[] remoteIds = parcel.readStringArray();
final String[] values = parcel.readStringArray();
- final Builder builder = new Builder(scorer, remoteIds[0], values[0]);
+ final Builder builder = new Builder(remoteIds[0], values[0])
+ .setFieldClassificationAlgorithm(parcel.readString(), parcel.readBundle());
for (int i = 1; i < remoteIds.length; i++) {
builder.add(remoteIds[i], values[i]);
}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index df0842f7fb0d..fb530074d5b0 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -23,6 +23,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccInfo;
+import android.telephony.euicc.EuiccManager.OtaStatus;
import android.util.ArraySet;
import java.util.concurrent.LinkedBlockingQueue;
@@ -203,6 +204,16 @@ public abstract class EuiccService extends Service {
public abstract String onGetEid(int slotId);
/**
+ * Return the status of OTA update.
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @return The status of Euicc OTA update.
+ * @see android.telephony.euicc.EuiccManager#getOtaStatus
+ */
+ public abstract @OtaStatus int onGetOtaStatus(int slotId);
+
+ /**
* Populate {@link DownloadableSubscription} metadata for the given downloadable subscription.
*
* @param slotId ID of the SIM slot to use for the operation. This is currently not populated
@@ -385,6 +396,21 @@ public abstract class EuiccService extends Service {
}
@Override
+ public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ int status = EuiccService.this.onGetOtaStatus(slotId);
+ try {
+ callback.onSuccess(status);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+ });
+ }
+
+ @Override
public void getDownloadableSubscriptionMetadata(int slotId,
DownloadableSubscription subscription,
boolean forceDeactivateSim,
diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl
index e10dd8cdf616..a24e5c35c1cb 100644
--- a/core/java/android/service/euicc/IEuiccService.aidl
+++ b/core/java/android/service/euicc/IEuiccService.aidl
@@ -24,6 +24,7 @@ import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback;
import android.service.euicc.IGetEidCallback;
import android.service.euicc.IGetEuiccInfoCallback;
import android.service.euicc.IGetEuiccProfileInfoListCallback;
+import android.service.euicc.IGetOtaStatusCallback;
import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback;
import android.service.euicc.ISwitchToSubscriptionCallback;
import android.service.euicc.IUpdateSubscriptionNicknameCallback;
@@ -37,6 +38,7 @@ oneway interface IEuiccService {
void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription,
boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback);
void getEid(int slotId, in IGetEidCallback callback);
+ void getOtaStatus(int slotId, in IGetOtaStatusCallback callback);
void getEuiccProfileInfoList(int slotId, in IGetEuiccProfileInfoListCallback callback);
void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim,
in IGetDefaultDownloadableSubscriptionListCallback callback);
diff --git a/core/java/android/service/euicc/IGetOtaStatusCallback.aidl b/core/java/android/service/euicc/IGetOtaStatusCallback.aidl
new file mode 100644
index 000000000000..f6678889ccc7
--- /dev/null
+++ b/core/java/android/service/euicc/IGetOtaStatusCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package android.service.euicc;
+
+/** @hide */
+oneway interface IGetOtaStatusCallback {
+ void onSuccess(int status);
+} \ No newline at end of file
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 8c90156d159d..ad3b4b6d6343 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -20,11 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
-import android.icu.text.DecimalFormat;
import android.icu.text.MeasureFormat;
-import android.icu.text.NumberFormat;
-import android.icu.text.UnicodeSet;
-import android.icu.text.UnicodeSetSpanner;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
import android.net.NetworkUtils;
@@ -32,8 +28,6 @@ import android.text.BidiFormatter;
import android.text.TextUtils;
import android.view.View;
-import java.lang.reflect.Constructor;
-import java.math.BigDecimal;
import java.util.Locale;
/**
@@ -43,8 +37,6 @@ import java.util.Locale;
public final class Formatter {
/** {@hide} */
- public static final int FLAG_DEFAULT = 0;
- /** {@hide} */
public static final int FLAG_SHORTER = 1 << 0;
/** {@hide} */
public static final int FLAG_CALCULATE_ROUNDED = 1 << 1;
@@ -66,9 +58,7 @@ public final class Formatter {
return context.getResources().getConfiguration().getLocales().get(0);
}
- /**
- * Wraps the source string in bidi formatting characters in RTL locales.
- */
+ /* Wraps the source string in bidi formatting characters in RTL locales */
private static String bidiWrap(@NonNull Context context, String source) {
final Locale locale = localeFromContext(context);
if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) {
@@ -97,7 +87,12 @@ public final class Formatter {
* @return formatted string with the number
*/
public static String formatFileSize(@Nullable Context context, long sizeBytes) {
- return formatFileSize(context, sizeBytes, FLAG_DEFAULT);
+ if (context == null) {
+ return "";
+ }
+ final BytesResult res = formatBytes(context.getResources(), sizeBytes, 0);
+ return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
+ res.value, res.units));
}
/**
@@ -105,207 +100,88 @@ public final class Formatter {
* (showing fewer digits of precision).
*/
public static String formatShortFileSize(@Nullable Context context, long sizeBytes) {
- return formatFileSize(context, sizeBytes, FLAG_SHORTER);
- }
-
- private static String formatFileSize(@Nullable Context context, long sizeBytes, int flags) {
if (context == null) {
return "";
}
- final RoundedBytesResult res = RoundedBytesResult.roundBytes(sizeBytes, flags);
- return bidiWrap(context, formatRoundedBytesResult(context, res));
- }
-
- private static String getSuffixOverride(@NonNull Resources res, MeasureUnit unit) {
- if (unit == MeasureUnit.BYTE) {
- return res.getString(com.android.internal.R.string.byteShort);
- } else { // unit == PETABYTE
- return res.getString(com.android.internal.R.string.petabyteShort);
- }
- }
-
- private static NumberFormat getNumberFormatter(Locale locale, int fractionDigits) {
- final NumberFormat numberFormatter = NumberFormat.getInstance(locale);
- numberFormatter.setMinimumFractionDigits(fractionDigits);
- numberFormatter.setMaximumFractionDigits(fractionDigits);
- numberFormatter.setGroupingUsed(false);
- if (numberFormatter instanceof DecimalFormat) {
- // We do this only for DecimalFormat, since in the general NumberFormat case, calling
- // setRoundingMode may throw an exception.
- numberFormatter.setRoundingMode(BigDecimal.ROUND_HALF_UP);
- }
- return numberFormatter;
- }
-
- private static String deleteFirstFromString(String source, String toDelete) {
- final int location = source.indexOf(toDelete);
- if (location == -1) {
- return source;
- } else {
- return source.substring(0, location)
- + source.substring(location + toDelete.length(), source.length());
- }
- }
-
- private static String formatMeasureShort(Locale locale, NumberFormat numberFormatter,
- float value, MeasureUnit units) {
- final MeasureFormat measureFormatter = MeasureFormat.getInstance(
- locale, MeasureFormat.FormatWidth.SHORT, numberFormatter);
- return measureFormatter.format(new Measure(value, units));
- }
-
- private static final UnicodeSetSpanner SPACES_AND_CONTROLS =
- new UnicodeSetSpanner(new UnicodeSet("[[:Zs:][:Cf:]]").freeze());
-
- private static String formatRoundedBytesResult(
- @NonNull Context context, @NonNull RoundedBytesResult input) {
- final Locale locale = localeFromContext(context);
- final NumberFormat numberFormatter = getNumberFormatter(locale, input.fractionDigits);
- if (input.units == MeasureUnit.BYTE || input.units == PETABYTE) {
- // ICU spells out "byte" instead of "B", and can't format petabytes yet.
- final String formattedNumber = numberFormatter.format(input.value);
- return context.getString(com.android.internal.R.string.fileSizeSuffix,
- formattedNumber, getSuffixOverride(context.getResources(), input.units));
- } else {
- return formatMeasureShort(locale, numberFormatter, input.value, input.units);
- }
+ final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SHORTER);
+ return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
+ res.value, res.units));
}
/** {@hide} */
public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
- final RoundedBytesResult rounded = RoundedBytesResult.roundBytes(sizeBytes, flags);
- final Locale locale = res.getConfiguration().getLocales().get(0);
- final NumberFormat numberFormatter = getNumberFormatter(locale, rounded.fractionDigits);
- final String formattedNumber = numberFormatter.format(rounded.value);
- final String units;
- if (rounded.units == MeasureUnit.BYTE || rounded.units == PETABYTE) {
- // ICU spells out "byte" instead of "B", and can't format petabytes yet.
- units = getSuffixOverride(res, rounded.units);
- } else {
- // Since ICU does not give us access to the pattern, we need to extract the unit string
- // from ICU, which we do by taking out the formatted number out of the formatted string
- // and trimming the result of spaces and controls.
- final String formattedMeasure = formatMeasureShort(
- locale, numberFormatter, rounded.value, rounded.units);
- final String numberRemoved = deleteFirstFromString(formattedMeasure, formattedNumber);
- units = SPACES_AND_CONTROLS.trim(numberRemoved).toString();
+ final boolean isNegative = (sizeBytes < 0);
+ float result = isNegative ? -sizeBytes : sizeBytes;
+ int suffix = com.android.internal.R.string.byteShort;
+ long mult = 1;
+ if (result > 900) {
+ suffix = com.android.internal.R.string.kilobyteShort;
+ mult = 1000;
+ result = result / 1000;
}
- return new BytesResult(formattedNumber, units, rounded.roundedBytes);
- }
-
- /**
- * ICU doesn't support PETABYTE yet. Fake it so that we can treat all units the same way.
- */
- private static final MeasureUnit PETABYTE = createPetaByte();
-
- /**
- * Create a petabyte MeasureUnit without registering it with ICU.
- * ICU doesn't support user-create MeasureUnit and the only public (but hidden) method to do so
- * is {@link MeasureUnit#internalGetInstance(String, String)} which also registers the unit as
- * an available type and thus leaks it to code that doesn't expect or support it.
- * <p>This method uses reflection to create an instance of MeasureUnit to avoid leaking it. This
- * instance is <b>only</b> to be used in this class.
- */
- private static MeasureUnit createPetaByte() {
- try {
- Constructor<MeasureUnit> constructor = MeasureUnit.class
- .getDeclaredConstructor(String.class, String.class);
- constructor.setAccessible(true);
- return constructor.newInstance("digital", "petabyte");
- } catch (ReflectiveOperationException e) {
- throw new RuntimeException("Failed to create petabyte MeasureUnit", e);
+ if (result > 900) {
+ suffix = com.android.internal.R.string.megabyteShort;
+ mult *= 1000;
+ result = result / 1000;
}
- }
-
- private static class RoundedBytesResult {
- public final float value;
- public final MeasureUnit units;
- public final int fractionDigits;
- public final long roundedBytes;
-
- private RoundedBytesResult(
- float value, MeasureUnit units, int fractionDigits, long roundedBytes) {
- this.value = value;
- this.units = units;
- this.fractionDigits = fractionDigits;
- this.roundedBytes = roundedBytes;
+ if (result > 900) {
+ suffix = com.android.internal.R.string.gigabyteShort;
+ mult *= 1000;
+ result = result / 1000;
}
-
- /**
- * Returns a RoundedBytesResult object based on the input size in bytes and the rounding
- * flags. The result can be used for formatting.
- */
- static RoundedBytesResult roundBytes(long sizeBytes, int flags) {
- final boolean isNegative = (sizeBytes < 0);
- float result = isNegative ? -sizeBytes : sizeBytes;
- MeasureUnit units = MeasureUnit.BYTE;
- long mult = 1;
- if (result > 900) {
- units = MeasureUnit.KILOBYTE;
- mult = 1000;
- result = result / 1000;
- }
- if (result > 900) {
- units = MeasureUnit.MEGABYTE;
- mult *= 1000;
- result = result / 1000;
- }
- if (result > 900) {
- units = MeasureUnit.GIGABYTE;
- mult *= 1000;
- result = result / 1000;
- }
- if (result > 900) {
- units = MeasureUnit.TERABYTE;
- mult *= 1000;
- result = result / 1000;
- }
- if (result > 900) {
- units = PETABYTE;
- mult *= 1000;
- result = result / 1000;
+ if (result > 900) {
+ suffix = com.android.internal.R.string.terabyteShort;
+ mult *= 1000;
+ result = result / 1000;
+ }
+ if (result > 900) {
+ suffix = com.android.internal.R.string.petabyteShort;
+ mult *= 1000;
+ result = result / 1000;
+ }
+ // Note we calculate the rounded long by ourselves, but still let String.format()
+ // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
+ // floating point errors.
+ final int roundFactor;
+ final String roundFormat;
+ if (mult == 1 || result >= 100) {
+ roundFactor = 1;
+ roundFormat = "%.0f";
+ } else if (result < 1) {
+ roundFactor = 100;
+ roundFormat = "%.2f";
+ } else if (result < 10) {
+ if ((flags & FLAG_SHORTER) != 0) {
+ roundFactor = 10;
+ roundFormat = "%.1f";
+ } else {
+ roundFactor = 100;
+ roundFormat = "%.2f";
}
- // Note we calculate the rounded long by ourselves, but still let NumberFormat compute
- // the rounded value. NumberFormat.format(0.1) might not return "0.1" due to floating
- // point errors.
- final int roundFactor;
- final int roundDigits;
- if (mult == 1 || result >= 100) {
+ } else { // 10 <= result < 100
+ if ((flags & FLAG_SHORTER) != 0) {
roundFactor = 1;
- roundDigits = 0;
- } else if (result < 1) {
+ roundFormat = "%.0f";
+ } else {
roundFactor = 100;
- roundDigits = 2;
- } else if (result < 10) {
- if ((flags & FLAG_SHORTER) != 0) {
- roundFactor = 10;
- roundDigits = 1;
- } else {
- roundFactor = 100;
- roundDigits = 2;
- }
- } else { // 10 <= result < 100
- if ((flags & FLAG_SHORTER) != 0) {
- roundFactor = 1;
- roundDigits = 0;
- } else {
- roundFactor = 100;
- roundDigits = 2;
- }
+ roundFormat = "%.2f";
}
+ }
- if (isNegative) {
- result = -result;
- }
+ if (isNegative) {
+ result = -result;
+ }
+ final String roundedString = String.format(roundFormat, result);
- // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like
- // 80PB so it's okay (for now)...
- final long roundedBytes =
- (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
- : (((long) Math.round(result * roundFactor)) * mult / roundFactor);
+ // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
+ // it's okay (for now)...
+ final long roundedBytes =
+ (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
+ : (((long) Math.round(result * roundFactor)) * mult / roundFactor);
- return new RoundedBytesResult(result, units, roundDigits, roundedBytes);
- }
+ final String units = res.getString(suffix);
+
+ return new BytesResult(roundedString, units, roundedBytes);
}
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index bfb513092c31..d31bc1fbda76 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -38,7 +38,6 @@ public class FeatureFlagUtils {
static {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("device_info_v2", "true");
- DEFAULT_FLAGS.put("new_settings_suggestion", "true");
DEFAULT_FLAGS.put("settings_search_v2", "true");
DEFAULT_FLAGS.put("settings_app_info_v2", "false");
DEFAULT_FLAGS.put("settings_connected_device_v2", "true");
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
index 26a3c361e8c1..c25b272c11b9 100644
--- a/core/java/android/util/StatsManager.java
+++ b/core/java/android/util/StatsManager.java
@@ -53,7 +53,7 @@ public final class StatsManager {
* @return true if successful
*/
@RequiresPermission(Manifest.permission.DUMP)
- public boolean addConfiguration(String configKey, byte[] config, String pkg, String cls) {
+ public boolean addConfiguration(long configKey, byte[] config, String pkg, String cls) {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
@@ -76,7 +76,7 @@ public final class StatsManager {
* @return true if successful
*/
@RequiresPermission(Manifest.permission.DUMP)
- public boolean removeConfiguration(String configKey) {
+ public boolean removeConfiguration(long configKey) {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
@@ -100,7 +100,7 @@ public final class StatsManager {
* @return Serialized ConfigMetricsReportList proto. Returns null on failure.
*/
@RequiresPermission(Manifest.permission.DUMP)
- public byte[] getData(String configKey) {
+ public byte[] getData(long configKey) {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 0a54f3a59a7d..530937e720a7 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -16,6 +16,21 @@
package android.util.apk;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getLengthPrefixedSlice;
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmContentDigestAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
+
import android.util.ArrayMap;
import android.util.Pair;
@@ -23,56 +38,47 @@ import java.io.ByteArrayInputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.math.BigInteger;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.security.DigestException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Principal;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
-import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
-import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
-import java.security.spec.MGF1ParameterSpec;
-import java.security.spec.PSSParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Date;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* APK Signature Scheme v2 verifier.
*
+ * <p>APK Signature Scheme v2 is a whole-file signature scheme which aims to protect every single
+ * bit of the APK, as opposed to the JAR Signature Scheme which protects only the names and
+ * uncompressed contents of ZIP entries.
+ *
+ * @see <a href="https://source.android.com/security/apksigning/v2.html">APK Signature Scheme v2</a>
+ *
* @hide for internal use only.
*/
public class ApkSignatureSchemeV2Verifier {
/**
- * {@code .SF} file header section attribute indicating that the APK is signed not just with
- * JAR signature scheme but also with APK Signature Scheme v2 or newer. This attribute
- * facilitates v2 signature stripping detection.
- *
- * <p>The attribute contains a comma-separated set of signature scheme IDs.
+ * ID of this signature scheme as used in X-Android-APK-Signed header used in JAR signing.
*/
- public static final String SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME = "X-Android-APK-Signed";
public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 2;
+ private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
+
/**
* Returns {@code true} if the provided APK contains an APK Signature Scheme V2 signature.
*
@@ -103,7 +109,7 @@ public class ApkSignatureSchemeV2Verifier {
/**
* Returns the certificates associated with each signer for the given APK without verification.
* This method is dangerous and should not be used, unless the caller is absolutely certain the
- * APK is trusted. Specifically, verification is only done for the APK Signature Scheme V2
+ * APK is trusted. Specifically, verification is only done for the APK Signature Scheme v2
* Block while gathering signer information. The APK contents are not verified.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v2.
@@ -120,6 +126,7 @@ public class ApkSignatureSchemeV2Verifier {
return verify(apk, verifyIntegrity);
}
}
+
/**
* Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
* associated with each signer.
@@ -144,30 +151,7 @@ public class ApkSignatureSchemeV2Verifier {
*/
private static SignatureInfo findSignature(RandomAccessFile apk)
throws IOException, SignatureNotFoundException {
- // Find the ZIP End of Central Directory (EoCD) record.
- Pair<ByteBuffer, Long> eocdAndOffsetInFile = getEocd(apk);
- ByteBuffer eocd = eocdAndOffsetInFile.first;
- long eocdOffset = eocdAndOffsetInFile.second;
- if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apk, eocdOffset)) {
- throw new SignatureNotFoundException("ZIP64 APK not supported");
- }
-
- // Find the APK Signing Block. The block immediately precedes the Central Directory.
- long centralDirOffset = getCentralDirOffset(eocd, eocdOffset);
- Pair<ByteBuffer, Long> apkSigningBlockAndOffsetInFile =
- findApkSigningBlock(apk, centralDirOffset);
- ByteBuffer apkSigningBlock = apkSigningBlockAndOffsetInFile.first;
- long apkSigningBlockOffset = apkSigningBlockAndOffsetInFile.second;
-
- // Find the APK Signature Scheme v2 Block inside the APK Signing Block.
- ByteBuffer apkSignatureSchemeV2Block = findApkSignatureSchemeV2Block(apkSigningBlock);
-
- return new SignatureInfo(
- apkSignatureSchemeV2Block,
- apkSigningBlockOffset,
- centralDirOffset,
- eocdOffset,
- eocd);
+ return ApkSigningBlockUtils.findSignature(apk, APK_SIGNATURE_SCHEME_V2_BLOCK_ID);
}
/**
@@ -218,7 +202,7 @@ public class ApkSignatureSchemeV2Verifier {
}
if (doVerifyIntegrity) {
- verifyIntegrity(
+ ApkSigningBlockUtils.verifyIntegrity(
contentDigests,
apkFileDescriptor,
signatureInfo.apkSigningBlockOffset,
@@ -349,7 +333,8 @@ public class ApkSignatureSchemeV2Verifier {
} catch (CertificateException e) {
throw new SecurityException("Failed to decode certificate #" + certificateCount, e);
}
- certificate = new VerbatimX509Certificate(certificate, encodedCert);
+ certificate = new VerbatimX509Certificate(
+ certificate, encodedCert);
certs.add(certificate);
}
@@ -363,235 +348,44 @@ public class ApkSignatureSchemeV2Verifier {
"Public key mismatch between certificate and signature record");
}
+ ByteBuffer additionalAttrs = getLengthPrefixedSlice(signedData);
+ verifyAdditionalAttributes(additionalAttrs);
+
return certs.toArray(new X509Certificate[certs.size()]);
}
- private static void verifyIntegrity(
- Map<Integer, byte[]> expectedDigests,
- FileDescriptor apkFileDescriptor,
- long apkSigningBlockOffset,
- long centralDirOffset,
- long eocdOffset,
- ByteBuffer eocdBuf) throws SecurityException {
-
- if (expectedDigests.isEmpty()) {
- throw new SecurityException("No digests provided");
- }
-
- // We need to verify the integrity of the following three sections of the file:
- // 1. Everything up to the start of the APK Signing Block.
- // 2. ZIP Central Directory.
- // 3. ZIP End of Central Directory (EoCD).
- // Each of these sections is represented as a separate DataSource instance below.
-
- // To handle large APKs, these sections are read in 1 MB chunks using memory-mapped I/O to
- // avoid wasting physical memory. In most APK verification scenarios, the contents of the
- // APK are already there in the OS's page cache and thus mmap does not use additional
- // physical memory.
- DataSource beforeApkSigningBlock =
- new MemoryMappedFileDataSource(apkFileDescriptor, 0, apkSigningBlockOffset);
- DataSource centralDir =
- new MemoryMappedFileDataSource(
- apkFileDescriptor, centralDirOffset, eocdOffset - centralDirOffset);
+ // Attribute to check whether a newer APK Signature Scheme signature was stripped
+ private static final int STRIPPING_PROTECTION_ATTR_ID = 0xbeeff00d;
- // For the purposes of integrity verification, ZIP End of Central Directory's field Start of
- // Central Directory must be considered to point to the offset of the APK Signing Block.
- eocdBuf = eocdBuf.duplicate();
- eocdBuf.order(ByteOrder.LITTLE_ENDIAN);
- ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, apkSigningBlockOffset);
- DataSource eocd = new ByteBufferDataSource(eocdBuf);
-
- int[] digestAlgorithms = new int[expectedDigests.size()];
- int digestAlgorithmCount = 0;
- for (int digestAlgorithm : expectedDigests.keySet()) {
- digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
- digestAlgorithmCount++;
- }
- byte[][] actualDigests;
- try {
- actualDigests =
- computeContentDigests(
- digestAlgorithms,
- new DataSource[] {beforeApkSigningBlock, centralDir, eocd});
- } catch (DigestException e) {
- throw new SecurityException("Failed to compute digest(s) of contents", e);
- }
- for (int i = 0; i < digestAlgorithms.length; i++) {
- int digestAlgorithm = digestAlgorithms[i];
- byte[] expectedDigest = expectedDigests.get(digestAlgorithm);
- byte[] actualDigest = actualDigests[i];
- if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
- throw new SecurityException(
- getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
- + " digest of contents did not verify");
+ private static void verifyAdditionalAttributes(ByteBuffer attrs)
+ throws SecurityException, IOException {
+ while (attrs.hasRemaining()) {
+ ByteBuffer attr = getLengthPrefixedSlice(attrs);
+ if (attr.remaining() < 4) {
+ throw new IOException("Remaining buffer too short to contain additional attribute "
+ + "ID. Remaining: " + attr.remaining());
}
- }
- }
-
- private static byte[][] computeContentDigests(
- int[] digestAlgorithms,
- DataSource[] contents) throws DigestException {
- // For each digest algorithm the result is computed as follows:
- // 1. Each segment of contents is split into consecutive chunks of 1 MB in size.
- // The final chunk will be shorter iff the length of segment is not a multiple of 1 MB.
- // No chunks are produced for empty (zero length) segments.
- // 2. The digest of each chunk is computed over the concatenation of byte 0xa5, the chunk's
- // length in bytes (uint32 little-endian) and the chunk's contents.
- // 3. The output digest is computed over the concatenation of the byte 0x5a, the number of
- // chunks (uint32 little-endian) and the concatenation of digests of chunks of all
- // segments in-order.
-
- long totalChunkCountLong = 0;
- for (DataSource input : contents) {
- totalChunkCountLong += getChunkCount(input.size());
- }
- if (totalChunkCountLong >= Integer.MAX_VALUE / 1024) {
- throw new DigestException("Too many chunks: " + totalChunkCountLong);
- }
- int totalChunkCount = (int) totalChunkCountLong;
-
- byte[][] digestsOfChunks = new byte[digestAlgorithms.length][];
- for (int i = 0; i < digestAlgorithms.length; i++) {
- int digestAlgorithm = digestAlgorithms[i];
- int digestOutputSizeBytes = getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
- byte[] concatenationOfChunkCountAndChunkDigests =
- new byte[5 + totalChunkCount * digestOutputSizeBytes];
- concatenationOfChunkCountAndChunkDigests[0] = 0x5a;
- setUnsignedInt32LittleEndian(
- totalChunkCount,
- concatenationOfChunkCountAndChunkDigests,
- 1);
- digestsOfChunks[i] = concatenationOfChunkCountAndChunkDigests;
- }
-
- byte[] chunkContentPrefix = new byte[5];
- chunkContentPrefix[0] = (byte) 0xa5;
- int chunkIndex = 0;
- MessageDigest[] mds = new MessageDigest[digestAlgorithms.length];
- for (int i = 0; i < digestAlgorithms.length; i++) {
- String jcaAlgorithmName =
- getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithms[i]);
- try {
- mds[i] = MessageDigest.getInstance(jcaAlgorithmName);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
- }
- }
- // TODO: Compute digests of chunks in parallel when beneficial. This requires some research
- // into how to parallelize (if at all) based on the capabilities of the hardware on which
- // this code is running and based on the size of input.
- DataDigester digester = new MultipleDigestDataDigester(mds);
- int dataSourceIndex = 0;
- for (DataSource input : contents) {
- long inputOffset = 0;
- long inputRemaining = input.size();
- while (inputRemaining > 0) {
- int chunkSize = (int) Math.min(inputRemaining, CHUNK_SIZE_BYTES);
- setUnsignedInt32LittleEndian(chunkSize, chunkContentPrefix, 1);
- for (int i = 0; i < mds.length; i++) {
- mds[i].update(chunkContentPrefix);
- }
- try {
- input.feedIntoDataDigester(digester, inputOffset, chunkSize);
- } catch (IOException e) {
- throw new DigestException(
- "Failed to digest chunk #" + chunkIndex + " of section #"
- + dataSourceIndex,
- e);
- }
- for (int i = 0; i < digestAlgorithms.length; i++) {
- int digestAlgorithm = digestAlgorithms[i];
- byte[] concatenationOfChunkCountAndChunkDigests = digestsOfChunks[i];
- int expectedDigestSizeBytes =
- getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
- MessageDigest md = mds[i];
- int actualDigestSizeBytes =
- md.digest(
- concatenationOfChunkCountAndChunkDigests,
- 5 + chunkIndex * expectedDigestSizeBytes,
- expectedDigestSizeBytes);
- if (actualDigestSizeBytes != expectedDigestSizeBytes) {
- throw new RuntimeException(
- "Unexpected output size of " + md.getAlgorithm() + " digest: "
- + actualDigestSizeBytes);
+ int id = attr.getInt();
+ switch (id) {
+ case STRIPPING_PROTECTION_ATTR_ID:
+ if (attr.remaining() < 4) {
+ throw new IOException("V2 Signature Scheme Stripping Protection Attribute "
+ + " value too small. Expected 4 bytes, but found "
+ + attr.remaining());
}
- }
- inputOffset += chunkSize;
- inputRemaining -= chunkSize;
- chunkIndex++;
- }
- dataSourceIndex++;
- }
-
- byte[][] result = new byte[digestAlgorithms.length][];
- for (int i = 0; i < digestAlgorithms.length; i++) {
- int digestAlgorithm = digestAlgorithms[i];
- byte[] input = digestsOfChunks[i];
- String jcaAlgorithmName = getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm);
- MessageDigest md;
- try {
- md = MessageDigest.getInstance(jcaAlgorithmName);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
+ int vers = attr.getInt();
+ if (vers == ApkSignatureSchemeV3Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) {
+ throw new SecurityException("V2 signature indicates APK is signed using APK"
+ + " Signature Scheme v3, but none was found. Signature stripped?");
+ }
+ break;
+ default:
+ // not the droid we're looking for, move along, move along.
+ break;
}
- byte[] output = md.digest(input);
- result[i] = output;
}
- return result;
+ return;
}
-
- /**
- * Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
- *
- * @throws IOException if an I/O error occurs while reading the file.
- * @throws SignatureNotFoundException if the EoCD could not be found.
- */
- private static Pair<ByteBuffer, Long> getEocd(RandomAccessFile apk)
- throws IOException, SignatureNotFoundException {
- Pair<ByteBuffer, Long> eocdAndOffsetInFile =
- ZipUtils.findZipEndOfCentralDirectoryRecord(apk);
- if (eocdAndOffsetInFile == null) {
- throw new SignatureNotFoundException(
- "Not an APK file: ZIP End of Central Directory record not found");
- }
- return eocdAndOffsetInFile;
- }
-
- private static long getCentralDirOffset(ByteBuffer eocd, long eocdOffset)
- throws SignatureNotFoundException {
- // Look up the offset of ZIP Central Directory.
- long centralDirOffset = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
- if (centralDirOffset > eocdOffset) {
- throw new SignatureNotFoundException(
- "ZIP Central Directory offset out of range: " + centralDirOffset
- + ". ZIP End of Central Directory offset: " + eocdOffset);
- }
- long centralDirSize = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
- if (centralDirOffset + centralDirSize != eocdOffset) {
- throw new SignatureNotFoundException(
- "ZIP Central Directory is not immediately followed by End of Central"
- + " Directory");
- }
- return centralDirOffset;
- }
-
- private static final long getChunkCount(long inputSizeBytes) {
- return (inputSizeBytes + CHUNK_SIZE_BYTES - 1) / CHUNK_SIZE_BYTES;
- }
-
- private static final int CHUNK_SIZE_BYTES = 1024 * 1024;
-
- private static final int SIGNATURE_RSA_PSS_WITH_SHA256 = 0x0101;
- private static final int SIGNATURE_RSA_PSS_WITH_SHA512 = 0x0102;
- private static final int SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0103;
- private static final int SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512 = 0x0104;
- private static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
- private static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
- private static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
-
- private static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
- private static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
-
private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
@@ -606,519 +400,4 @@ public class ApkSignatureSchemeV2Verifier {
return false;
}
}
-
- private static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) {
- int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1);
- int digestAlgorithm2 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm2);
- return compareContentDigestAlgorithm(digestAlgorithm1, digestAlgorithm2);
- }
-
- private static int compareContentDigestAlgorithm(int digestAlgorithm1, int digestAlgorithm2) {
- switch (digestAlgorithm1) {
- case CONTENT_DIGEST_CHUNKED_SHA256:
- switch (digestAlgorithm2) {
- case CONTENT_DIGEST_CHUNKED_SHA256:
- return 0;
- case CONTENT_DIGEST_CHUNKED_SHA512:
- return -1;
- default:
- throw new IllegalArgumentException(
- "Unknown digestAlgorithm2: " + digestAlgorithm2);
- }
- case CONTENT_DIGEST_CHUNKED_SHA512:
- switch (digestAlgorithm2) {
- case CONTENT_DIGEST_CHUNKED_SHA256:
- return 1;
- case CONTENT_DIGEST_CHUNKED_SHA512:
- return 0;
- default:
- throw new IllegalArgumentException(
- "Unknown digestAlgorithm2: " + digestAlgorithm2);
- }
- default:
- throw new IllegalArgumentException("Unknown digestAlgorithm1: " + digestAlgorithm1);
- }
- }
-
- private static int getSignatureAlgorithmContentDigestAlgorithm(int sigAlgorithm) {
- switch (sigAlgorithm) {
- case SIGNATURE_RSA_PSS_WITH_SHA256:
- case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
- case SIGNATURE_ECDSA_WITH_SHA256:
- case SIGNATURE_DSA_WITH_SHA256:
- return CONTENT_DIGEST_CHUNKED_SHA256;
- case SIGNATURE_RSA_PSS_WITH_SHA512:
- case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
- case SIGNATURE_ECDSA_WITH_SHA512:
- return CONTENT_DIGEST_CHUNKED_SHA512;
- default:
- throw new IllegalArgumentException(
- "Unknown signature algorithm: 0x"
- + Long.toHexString(sigAlgorithm & 0xffffffff));
- }
- }
-
- private static String getContentDigestAlgorithmJcaDigestAlgorithm(int digestAlgorithm) {
- switch (digestAlgorithm) {
- case CONTENT_DIGEST_CHUNKED_SHA256:
- return "SHA-256";
- case CONTENT_DIGEST_CHUNKED_SHA512:
- return "SHA-512";
- default:
- throw new IllegalArgumentException(
- "Unknown content digest algorthm: " + digestAlgorithm);
- }
- }
-
- private static int getContentDigestAlgorithmOutputSizeBytes(int digestAlgorithm) {
- switch (digestAlgorithm) {
- case CONTENT_DIGEST_CHUNKED_SHA256:
- return 256 / 8;
- case CONTENT_DIGEST_CHUNKED_SHA512:
- return 512 / 8;
- default:
- throw new IllegalArgumentException(
- "Unknown content digest algorthm: " + digestAlgorithm);
- }
- }
-
- private static String getSignatureAlgorithmJcaKeyAlgorithm(int sigAlgorithm) {
- switch (sigAlgorithm) {
- case SIGNATURE_RSA_PSS_WITH_SHA256:
- case SIGNATURE_RSA_PSS_WITH_SHA512:
- case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
- case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
- return "RSA";
- case SIGNATURE_ECDSA_WITH_SHA256:
- case SIGNATURE_ECDSA_WITH_SHA512:
- return "EC";
- case SIGNATURE_DSA_WITH_SHA256:
- return "DSA";
- default:
- throw new IllegalArgumentException(
- "Unknown signature algorithm: 0x"
- + Long.toHexString(sigAlgorithm & 0xffffffff));
- }
- }
-
- private static Pair<String, ? extends AlgorithmParameterSpec>
- getSignatureAlgorithmJcaSignatureAlgorithm(int sigAlgorithm) {
- switch (sigAlgorithm) {
- case SIGNATURE_RSA_PSS_WITH_SHA256:
- return Pair.create(
- "SHA256withRSA/PSS",
- new PSSParameterSpec(
- "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 256 / 8, 1));
- case SIGNATURE_RSA_PSS_WITH_SHA512:
- return Pair.create(
- "SHA512withRSA/PSS",
- new PSSParameterSpec(
- "SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 512 / 8, 1));
- case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
- return Pair.create("SHA256withRSA", null);
- case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
- return Pair.create("SHA512withRSA", null);
- case SIGNATURE_ECDSA_WITH_SHA256:
- return Pair.create("SHA256withECDSA", null);
- case SIGNATURE_ECDSA_WITH_SHA512:
- return Pair.create("SHA512withECDSA", null);
- case SIGNATURE_DSA_WITH_SHA256:
- return Pair.create("SHA256withDSA", null);
- default:
- throw new IllegalArgumentException(
- "Unknown signature algorithm: 0x"
- + Long.toHexString(sigAlgorithm & 0xffffffff));
- }
- }
-
- /**
- * Returns new byte buffer whose content is a shared subsequence of this buffer's content
- * between the specified start (inclusive) and end (exclusive) positions. As opposed to
- * {@link ByteBuffer#slice()}, the returned buffer's byte order is the same as the source
- * buffer's byte order.
- */
- private static ByteBuffer sliceFromTo(ByteBuffer source, int start, int end) {
- if (start < 0) {
- throw new IllegalArgumentException("start: " + start);
- }
- if (end < start) {
- throw new IllegalArgumentException("end < start: " + end + " < " + start);
- }
- int capacity = source.capacity();
- if (end > source.capacity()) {
- throw new IllegalArgumentException("end > capacity: " + end + " > " + capacity);
- }
- int originalLimit = source.limit();
- int originalPosition = source.position();
- try {
- source.position(0);
- source.limit(end);
- source.position(start);
- ByteBuffer result = source.slice();
- result.order(source.order());
- return result;
- } finally {
- source.position(0);
- source.limit(originalLimit);
- source.position(originalPosition);
- }
- }
-
- /**
- * Relative <em>get</em> method for reading {@code size} number of bytes from the current
- * position of this buffer.
- *
- * <p>This method reads the next {@code size} bytes at this buffer's current position,
- * returning them as a {@code ByteBuffer} with start set to 0, limit and capacity set to
- * {@code size}, byte order set to this buffer's byte order; and then increments the position by
- * {@code size}.
- */
- private static ByteBuffer getByteBuffer(ByteBuffer source, int size)
- throws BufferUnderflowException {
- if (size < 0) {
- throw new IllegalArgumentException("size: " + size);
- }
- int originalLimit = source.limit();
- int position = source.position();
- int limit = position + size;
- if ((limit < position) || (limit > originalLimit)) {
- throw new BufferUnderflowException();
- }
- source.limit(limit);
- try {
- ByteBuffer result = source.slice();
- result.order(source.order());
- source.position(limit);
- return result;
- } finally {
- source.limit(originalLimit);
- }
- }
-
- private static ByteBuffer getLengthPrefixedSlice(ByteBuffer source) throws IOException {
- if (source.remaining() < 4) {
- throw new IOException(
- "Remaining buffer too short to contain length of length-prefixed field."
- + " Remaining: " + source.remaining());
- }
- int len = source.getInt();
- if (len < 0) {
- throw new IllegalArgumentException("Negative length");
- } else if (len > source.remaining()) {
- throw new IOException("Length-prefixed field longer than remaining buffer."
- + " Field length: " + len + ", remaining: " + source.remaining());
- }
- return getByteBuffer(source, len);
- }
-
- private static byte[] readLengthPrefixedByteArray(ByteBuffer buf) throws IOException {
- int len = buf.getInt();
- if (len < 0) {
- throw new IOException("Negative length");
- } else if (len > buf.remaining()) {
- throw new IOException("Underflow while reading length-prefixed value. Length: " + len
- + ", available: " + buf.remaining());
- }
- byte[] result = new byte[len];
- buf.get(result);
- return result;
- }
-
- private static void setUnsignedInt32LittleEndian(int value, byte[] result, int offset) {
- result[offset] = (byte) (value & 0xff);
- result[offset + 1] = (byte) ((value >>> 8) & 0xff);
- result[offset + 2] = (byte) ((value >>> 16) & 0xff);
- result[offset + 3] = (byte) ((value >>> 24) & 0xff);
- }
-
- private static final long APK_SIG_BLOCK_MAGIC_HI = 0x3234206b636f6c42L;
- private static final long APK_SIG_BLOCK_MAGIC_LO = 0x20676953204b5041L;
- private static final int APK_SIG_BLOCK_MIN_SIZE = 32;
-
- private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
-
- private static Pair<ByteBuffer, Long> findApkSigningBlock(
- RandomAccessFile apk, long centralDirOffset)
- throws IOException, SignatureNotFoundException {
- // FORMAT:
- // OFFSET DATA TYPE DESCRIPTION
- // * @+0 bytes uint64: size in bytes (excluding this field)
- // * @+8 bytes payload
- // * @-24 bytes uint64: size in bytes (same as the one above)
- // * @-16 bytes uint128: magic
-
- if (centralDirOffset < APK_SIG_BLOCK_MIN_SIZE) {
- throw new SignatureNotFoundException(
- "APK too small for APK Signing Block. ZIP Central Directory offset: "
- + centralDirOffset);
- }
- // Read the magic and offset in file from the footer section of the block:
- // * uint64: size of block
- // * 16 bytes: magic
- ByteBuffer footer = ByteBuffer.allocate(24);
- footer.order(ByteOrder.LITTLE_ENDIAN);
- apk.seek(centralDirOffset - footer.capacity());
- apk.readFully(footer.array(), footer.arrayOffset(), footer.capacity());
- if ((footer.getLong(8) != APK_SIG_BLOCK_MAGIC_LO)
- || (footer.getLong(16) != APK_SIG_BLOCK_MAGIC_HI)) {
- throw new SignatureNotFoundException(
- "No APK Signing Block before ZIP Central Directory");
- }
- // Read and compare size fields
- long apkSigBlockSizeInFooter = footer.getLong(0);
- if ((apkSigBlockSizeInFooter < footer.capacity())
- || (apkSigBlockSizeInFooter > Integer.MAX_VALUE - 8)) {
- throw new SignatureNotFoundException(
- "APK Signing Block size out of range: " + apkSigBlockSizeInFooter);
- }
- int totalSize = (int) (apkSigBlockSizeInFooter + 8);
- long apkSigBlockOffset = centralDirOffset - totalSize;
- if (apkSigBlockOffset < 0) {
- throw new SignatureNotFoundException(
- "APK Signing Block offset out of range: " + apkSigBlockOffset);
- }
- ByteBuffer apkSigBlock = ByteBuffer.allocate(totalSize);
- apkSigBlock.order(ByteOrder.LITTLE_ENDIAN);
- apk.seek(apkSigBlockOffset);
- apk.readFully(apkSigBlock.array(), apkSigBlock.arrayOffset(), apkSigBlock.capacity());
- long apkSigBlockSizeInHeader = apkSigBlock.getLong(0);
- if (apkSigBlockSizeInHeader != apkSigBlockSizeInFooter) {
- throw new SignatureNotFoundException(
- "APK Signing Block sizes in header and footer do not match: "
- + apkSigBlockSizeInHeader + " vs " + apkSigBlockSizeInFooter);
- }
- return Pair.create(apkSigBlock, apkSigBlockOffset);
- }
-
- private static ByteBuffer findApkSignatureSchemeV2Block(ByteBuffer apkSigningBlock)
- throws SignatureNotFoundException {
- checkByteOrderLittleEndian(apkSigningBlock);
- // FORMAT:
- // OFFSET DATA TYPE DESCRIPTION
- // * @+0 bytes uint64: size in bytes (excluding this field)
- // * @+8 bytes pairs
- // * @-24 bytes uint64: size in bytes (same as the one above)
- // * @-16 bytes uint128: magic
- ByteBuffer pairs = sliceFromTo(apkSigningBlock, 8, apkSigningBlock.capacity() - 24);
-
- int entryCount = 0;
- while (pairs.hasRemaining()) {
- entryCount++;
- if (pairs.remaining() < 8) {
- throw new SignatureNotFoundException(
- "Insufficient data to read size of APK Signing Block entry #" + entryCount);
- }
- long lenLong = pairs.getLong();
- if ((lenLong < 4) || (lenLong > Integer.MAX_VALUE)) {
- throw new SignatureNotFoundException(
- "APK Signing Block entry #" + entryCount
- + " size out of range: " + lenLong);
- }
- int len = (int) lenLong;
- int nextEntryPos = pairs.position() + len;
- if (len > pairs.remaining()) {
- throw new SignatureNotFoundException(
- "APK Signing Block entry #" + entryCount + " size out of range: " + len
- + ", available: " + pairs.remaining());
- }
- int id = pairs.getInt();
- if (id == APK_SIGNATURE_SCHEME_V2_BLOCK_ID) {
- return getByteBuffer(pairs, len - 4);
- }
- pairs.position(nextEntryPos);
- }
-
- throw new SignatureNotFoundException(
- "No APK Signature Scheme v2 block in APK Signing Block");
- }
-
- private static void checkByteOrderLittleEndian(ByteBuffer buffer) {
- if (buffer.order() != ByteOrder.LITTLE_ENDIAN) {
- throw new IllegalArgumentException("ByteBuffer byte order must be little endian");
- }
- }
-
- /**
- * {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is feeded.
- */
- private static class MultipleDigestDataDigester implements DataDigester {
- private final MessageDigest[] mMds;
-
- MultipleDigestDataDigester(MessageDigest[] mds) {
- mMds = mds;
- }
-
- @Override
- public void consume(ByteBuffer buffer) {
- buffer = buffer.slice();
- for (MessageDigest md : mMds) {
- buffer.position(0);
- md.update(buffer);
- }
- }
-
- @Override
- public void finish() {}
- }
-
- /**
- * For legacy reasons we need to return exactly the original encoded certificate bytes, instead
- * of letting the underlying implementation have a shot at re-encoding the data.
- */
- private static class VerbatimX509Certificate extends WrappedX509Certificate {
- private byte[] encodedVerbatim;
-
- public VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) {
- super(wrapped);
- this.encodedVerbatim = encodedVerbatim;
- }
-
- @Override
- public byte[] getEncoded() throws CertificateEncodingException {
- return encodedVerbatim;
- }
- }
-
- private static class WrappedX509Certificate extends X509Certificate {
- private final X509Certificate wrapped;
-
- public WrappedX509Certificate(X509Certificate wrapped) {
- this.wrapped = wrapped;
- }
-
- @Override
- public Set<String> getCriticalExtensionOIDs() {
- return wrapped.getCriticalExtensionOIDs();
- }
-
- @Override
- public byte[] getExtensionValue(String oid) {
- return wrapped.getExtensionValue(oid);
- }
-
- @Override
- public Set<String> getNonCriticalExtensionOIDs() {
- return wrapped.getNonCriticalExtensionOIDs();
- }
-
- @Override
- public boolean hasUnsupportedCriticalExtension() {
- return wrapped.hasUnsupportedCriticalExtension();
- }
-
- @Override
- public void checkValidity()
- throws CertificateExpiredException, CertificateNotYetValidException {
- wrapped.checkValidity();
- }
-
- @Override
- public void checkValidity(Date date)
- throws CertificateExpiredException, CertificateNotYetValidException {
- wrapped.checkValidity(date);
- }
-
- @Override
- public int getVersion() {
- return wrapped.getVersion();
- }
-
- @Override
- public BigInteger getSerialNumber() {
- return wrapped.getSerialNumber();
- }
-
- @Override
- public Principal getIssuerDN() {
- return wrapped.getIssuerDN();
- }
-
- @Override
- public Principal getSubjectDN() {
- return wrapped.getSubjectDN();
- }
-
- @Override
- public Date getNotBefore() {
- return wrapped.getNotBefore();
- }
-
- @Override
- public Date getNotAfter() {
- return wrapped.getNotAfter();
- }
-
- @Override
- public byte[] getTBSCertificate() throws CertificateEncodingException {
- return wrapped.getTBSCertificate();
- }
-
- @Override
- public byte[] getSignature() {
- return wrapped.getSignature();
- }
-
- @Override
- public String getSigAlgName() {
- return wrapped.getSigAlgName();
- }
-
- @Override
- public String getSigAlgOID() {
- return wrapped.getSigAlgOID();
- }
-
- @Override
- public byte[] getSigAlgParams() {
- return wrapped.getSigAlgParams();
- }
-
- @Override
- public boolean[] getIssuerUniqueID() {
- return wrapped.getIssuerUniqueID();
- }
-
- @Override
- public boolean[] getSubjectUniqueID() {
- return wrapped.getSubjectUniqueID();
- }
-
- @Override
- public boolean[] getKeyUsage() {
- return wrapped.getKeyUsage();
- }
-
- @Override
- public int getBasicConstraints() {
- return wrapped.getBasicConstraints();
- }
-
- @Override
- public byte[] getEncoded() throws CertificateEncodingException {
- return wrapped.getEncoded();
- }
-
- @Override
- public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
- InvalidKeyException, NoSuchProviderException, SignatureException {
- wrapped.verify(key);
- }
-
- @Override
- public void verify(PublicKey key, String sigProvider)
- throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
- NoSuchProviderException, SignatureException {
- wrapped.verify(key, sigProvider);
- }
-
- @Override
- public String toString() {
- return wrapped.toString();
- }
-
- @Override
- public PublicKey getPublicKey() {
- return wrapped.getPublicKey();
- }
- }
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
new file mode 100644
index 000000000000..e43dee356064
--- /dev/null
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getLengthPrefixedSlice;
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmContentDigestAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
+
+import android.os.Build;
+import android.util.ArrayMap;
+import android.util.Pair;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * APK Signature Scheme v3 verifier.
+ *
+ * @hide for internal use only.
+ */
+public class ApkSignatureSchemeV3Verifier {
+
+ /**
+ * ID of this signature scheme as used in X-Android-APK-Signed header used in JAR signing.
+ */
+ public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 3;
+
+ private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0;
+
+ /**
+ * Returns {@code true} if the provided APK contains an APK Signature Scheme V3 signature.
+ *
+ * <p><b>NOTE: This method does not verify the signature.</b>
+ */
+ public static boolean hasSignature(String apkFile) throws IOException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
+ findSignature(apk);
+ return true;
+ } catch (SignatureNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Verifies APK Signature Scheme v3 signatures of the provided APK and returns the certificates
+ * associated with each signer.
+ *
+ * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
+ * @throws SecurityException if the APK Signature Scheme v3 signature of this APK does not
+ * verify.
+ * @throws IOException if an I/O error occurs while reading the APK file.
+ */
+ public static VerifiedSigner verify(String apkFile)
+ throws SignatureNotFoundException, SecurityException, IOException {
+ return verify(apkFile, true);
+ }
+
+ /**
+ * Returns the certificates associated with each signer for the given APK without verification.
+ * This method is dangerous and should not be used, unless the caller is absolutely certain the
+ * APK is trusted. Specifically, verification is only done for the APK Signature Scheme v3
+ * Block while gathering signer information. The APK contents are not verified.
+ *
+ * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
+ * @throws IOException if an I/O error occurs while reading the APK file.
+ */
+ public static VerifiedSigner plsCertsNoVerifyOnlyCerts(String apkFile)
+ throws SignatureNotFoundException, SecurityException, IOException {
+ return verify(apkFile, false);
+ }
+
+ private static VerifiedSigner verify(String apkFile, boolean verifyIntegrity)
+ throws SignatureNotFoundException, SecurityException, IOException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
+ return verify(apk, verifyIntegrity);
+ }
+ }
+
+ /**
+ * Verifies APK Signature Scheme v3 signatures of the provided APK and returns the certificates
+ * associated with each signer.
+ *
+ * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
+ * @throws SecurityException if an APK Signature Scheme v3 signature of this APK does not
+ * verify.
+ * @throws IOException if an I/O error occurs while reading the APK file.
+ */
+ private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity)
+ throws SignatureNotFoundException, SecurityException, IOException {
+ SignatureInfo signatureInfo = findSignature(apk);
+ return verify(apk.getFD(), signatureInfo, verifyIntegrity);
+ }
+
+ /**
+ * Returns the APK Signature Scheme v3 block contained in the provided APK file and the
+ * additional information relevant for verifying the block against the file.
+ *
+ * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
+ * @throws IOException if an I/O error occurs while reading the APK file.
+ */
+ private static SignatureInfo findSignature(RandomAccessFile apk)
+ throws IOException, SignatureNotFoundException {
+ return ApkSigningBlockUtils.findSignature(apk, APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
+ }
+
+ /**
+ * Verifies the contents of the provided APK file against the provided APK Signature Scheme v3
+ * Block.
+ *
+ * @param signatureInfo APK Signature Scheme v3 Block and information relevant for verifying it
+ * against the APK file.
+ */
+ private static VerifiedSigner verify(
+ FileDescriptor apkFileDescriptor,
+ SignatureInfo signatureInfo,
+ boolean doVerifyIntegrity) throws SecurityException {
+ int signerCount = 0;
+ Map<Integer, byte[]> contentDigests = new ArrayMap<>();
+ VerifiedSigner result = null;
+ CertificateFactory certFactory;
+ try {
+ certFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new RuntimeException("Failed to obtain X.509 CertificateFactory", e);
+ }
+ ByteBuffer signers;
+ try {
+ signers = getLengthPrefixedSlice(signatureInfo.signatureBlock);
+ } catch (IOException e) {
+ throw new SecurityException("Failed to read list of signers", e);
+ }
+ while (signers.hasRemaining()) {
+ try {
+ ByteBuffer signer = getLengthPrefixedSlice(signers);
+ result = verifySigner(signer, contentDigests, certFactory);
+ signerCount++;
+ } catch (PlatformNotSupportedException e) {
+ // this signer is for a different platform, ignore it.
+ continue;
+ } catch (IOException | BufferUnderflowException | SecurityException e) {
+ throw new SecurityException(
+ "Failed to parse/verify signer #" + signerCount + " block",
+ e);
+ }
+ }
+
+ if (signerCount < 1 || result == null) {
+ throw new SecurityException("No signers found");
+ }
+
+ if (signerCount != 1) {
+ throw new SecurityException("APK Signature Scheme V3 only supports one signer: "
+ + "multiple signers found.");
+ }
+
+ if (contentDigests.isEmpty()) {
+ throw new SecurityException("No content digests found");
+ }
+
+ if (doVerifyIntegrity) {
+ ApkSigningBlockUtils.verifyIntegrity(
+ contentDigests,
+ apkFileDescriptor,
+ signatureInfo.apkSigningBlockOffset,
+ signatureInfo.centralDirOffset,
+ signatureInfo.eocdOffset,
+ signatureInfo.eocd);
+ }
+
+ return result;
+ }
+
+ private static VerifiedSigner verifySigner(
+ ByteBuffer signerBlock,
+ Map<Integer, byte[]> contentDigests,
+ CertificateFactory certFactory)
+ throws SecurityException, IOException, PlatformNotSupportedException {
+ ByteBuffer signedData = getLengthPrefixedSlice(signerBlock);
+ int minSdkVersion = signerBlock.getInt();
+ int maxSdkVersion = signerBlock.getInt();
+
+ if (Build.VERSION.SDK_INT < minSdkVersion || Build.VERSION.SDK_INT > maxSdkVersion) {
+ // this signature isn't meant to be used with this platform, skip it.
+ throw new PlatformNotSupportedException(
+ "Signer not supported by this platform "
+ + "version. This platform: " + Build.VERSION.SDK_INT
+ + ", signer minSdkVersion: " + minSdkVersion
+ + ", maxSdkVersion: " + maxSdkVersion);
+ }
+
+ ByteBuffer signatures = getLengthPrefixedSlice(signerBlock);
+ byte[] publicKeyBytes = readLengthPrefixedByteArray(signerBlock);
+
+ int signatureCount = 0;
+ int bestSigAlgorithm = -1;
+ byte[] bestSigAlgorithmSignatureBytes = null;
+ List<Integer> signaturesSigAlgorithms = new ArrayList<>();
+ while (signatures.hasRemaining()) {
+ signatureCount++;
+ try {
+ ByteBuffer signature = getLengthPrefixedSlice(signatures);
+ if (signature.remaining() < 8) {
+ throw new SecurityException("Signature record too short");
+ }
+ int sigAlgorithm = signature.getInt();
+ signaturesSigAlgorithms.add(sigAlgorithm);
+ if (!isSupportedSignatureAlgorithm(sigAlgorithm)) {
+ continue;
+ }
+ if ((bestSigAlgorithm == -1)
+ || (compareSignatureAlgorithm(sigAlgorithm, bestSigAlgorithm) > 0)) {
+ bestSigAlgorithm = sigAlgorithm;
+ bestSigAlgorithmSignatureBytes = readLengthPrefixedByteArray(signature);
+ }
+ } catch (IOException | BufferUnderflowException e) {
+ throw new SecurityException(
+ "Failed to parse signature record #" + signatureCount,
+ e);
+ }
+ }
+ if (bestSigAlgorithm == -1) {
+ if (signatureCount == 0) {
+ throw new SecurityException("No signatures found");
+ } else {
+ throw new SecurityException("No supported signatures found");
+ }
+ }
+
+ String keyAlgorithm = getSignatureAlgorithmJcaKeyAlgorithm(bestSigAlgorithm);
+ Pair<String, ? extends AlgorithmParameterSpec> signatureAlgorithmParams =
+ getSignatureAlgorithmJcaSignatureAlgorithm(bestSigAlgorithm);
+ String jcaSignatureAlgorithm = signatureAlgorithmParams.first;
+ AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithmParams.second;
+ boolean sigVerified;
+ try {
+ PublicKey publicKey =
+ KeyFactory.getInstance(keyAlgorithm)
+ .generatePublic(new X509EncodedKeySpec(publicKeyBytes));
+ Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
+ sig.initVerify(publicKey);
+ if (jcaSignatureAlgorithmParams != null) {
+ sig.setParameter(jcaSignatureAlgorithmParams);
+ }
+ sig.update(signedData);
+ sigVerified = sig.verify(bestSigAlgorithmSignatureBytes);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException
+ | InvalidAlgorithmParameterException | SignatureException e) {
+ throw new SecurityException(
+ "Failed to verify " + jcaSignatureAlgorithm + " signature", e);
+ }
+ if (!sigVerified) {
+ throw new SecurityException(jcaSignatureAlgorithm + " signature did not verify");
+ }
+
+ // Signature over signedData has verified.
+
+ byte[] contentDigest = null;
+ signedData.clear();
+ ByteBuffer digests = getLengthPrefixedSlice(signedData);
+ List<Integer> digestsSigAlgorithms = new ArrayList<>();
+ int digestCount = 0;
+ while (digests.hasRemaining()) {
+ digestCount++;
+ try {
+ ByteBuffer digest = getLengthPrefixedSlice(digests);
+ if (digest.remaining() < 8) {
+ throw new IOException("Record too short");
+ }
+ int sigAlgorithm = digest.getInt();
+ digestsSigAlgorithms.add(sigAlgorithm);
+ if (sigAlgorithm == bestSigAlgorithm) {
+ contentDigest = readLengthPrefixedByteArray(digest);
+ }
+ } catch (IOException | BufferUnderflowException e) {
+ throw new IOException("Failed to parse digest record #" + digestCount, e);
+ }
+ }
+
+ if (!signaturesSigAlgorithms.equals(digestsSigAlgorithms)) {
+ throw new SecurityException(
+ "Signature algorithms don't match between digests and signatures records");
+ }
+ int digestAlgorithm = getSignatureAlgorithmContentDigestAlgorithm(bestSigAlgorithm);
+ byte[] previousSignerDigest = contentDigests.put(digestAlgorithm, contentDigest);
+ if ((previousSignerDigest != null)
+ && (!MessageDigest.isEqual(previousSignerDigest, contentDigest))) {
+ throw new SecurityException(
+ getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
+ + " contents digest does not match the digest specified by a preceding signer");
+ }
+
+ ByteBuffer certificates = getLengthPrefixedSlice(signedData);
+ List<X509Certificate> certs = new ArrayList<>();
+ int certificateCount = 0;
+ while (certificates.hasRemaining()) {
+ certificateCount++;
+ byte[] encodedCert = readLengthPrefixedByteArray(certificates);
+ X509Certificate certificate;
+ try {
+ certificate = (X509Certificate)
+ certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
+ } catch (CertificateException e) {
+ throw new SecurityException("Failed to decode certificate #" + certificateCount, e);
+ }
+ certificate = new VerbatimX509Certificate(
+ certificate, encodedCert);
+ certs.add(certificate);
+ }
+
+ if (certs.isEmpty()) {
+ throw new SecurityException("No certificates listed");
+ }
+ X509Certificate mainCertificate = certs.get(0);
+ byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
+ if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
+ throw new SecurityException(
+ "Public key mismatch between certificate and signature record");
+ }
+
+ int signedMinSDK = signedData.getInt();
+ if (signedMinSDK != minSdkVersion) {
+ throw new SecurityException(
+ "minSdkVersion mismatch between signed and unsigned in v3 signer block.");
+ }
+
+ int signedMaxSDK = signedData.getInt();
+ if (signedMaxSDK != maxSdkVersion) {
+ throw new SecurityException(
+ "maxSdkVersion mismatch between signed and unsigned in v3 signer block.");
+ }
+
+ ByteBuffer additionalAttrs = getLengthPrefixedSlice(signedData);
+ return verifyAdditionalAttributes(additionalAttrs, certs, certFactory);
+ }
+
+ private static final int PROOF_OF_ROTATION_ATTR_ID = 0x3ba06f8c;
+
+ private static VerifiedSigner verifyAdditionalAttributes(ByteBuffer attrs,
+ List<X509Certificate> certs, CertificateFactory certFactory) throws IOException {
+ X509Certificate[] certChain = certs.toArray(new X509Certificate[certs.size()]);
+ VerifiedProofOfRotation por = null;
+
+ while (attrs.hasRemaining()) {
+ ByteBuffer attr = getLengthPrefixedSlice(attrs);
+ if (attr.remaining() < 4) {
+ throw new IOException("Remaining buffer too short to contain additional attribute "
+ + "ID. Remaining: " + attr.remaining());
+ }
+ int id = attr.getInt();
+ switch(id) {
+ case PROOF_OF_ROTATION_ATTR_ID:
+ if (por != null) {
+ throw new SecurityException("Encountered multiple Proof-of-rotation records"
+ + " when verifying APK Signature Scheme v3 signature");
+ }
+ por = verifyProofOfRotationStruct(attr, certFactory);
+ // make sure that the last certificate in the Proof-of-rotation record matches
+ // the one used to sign this APK.
+ try {
+ if (por.certs.size() > 0
+ && !Arrays.equals(por.certs.get(por.certs.size() - 1).getEncoded(),
+ certChain[0].getEncoded())) {
+ throw new SecurityException("Terminal certificate in Proof-of-rotation"
+ + " record does not match APK signing certificate");
+ }
+ } catch (CertificateEncodingException e) {
+ throw new SecurityException("Failed to encode certificate when comparing"
+ + " Proof-of-rotation record and signing certificate", e);
+ }
+
+ break;
+ default:
+ // not the droid we're looking for, move along, move along.
+ break;
+ }
+ }
+ return new VerifiedSigner(certChain, por);
+ }
+
+ private static VerifiedProofOfRotation verifyProofOfRotationStruct(
+ ByteBuffer porBuf,
+ CertificateFactory certFactory)
+ throws SecurityException, IOException {
+ int levelCount = 0;
+ int lastSigAlgorithm = -1;
+ X509Certificate lastCert = null;
+ List<X509Certificate> certs = new ArrayList<>();
+ List<Integer> flagsList = new ArrayList<>();
+
+ // Proof-of-rotation struct:
+ // is basically a singly linked list of nodes, called levels here, each of which have the
+ // following structure:
+ // * length-prefix for the entire level
+ // - length-prefixed signed data (if previous level exists)
+ // * length-prefixed X509 Certificate
+ // * uint32 signature algorithm ID describing how this signed data was signed
+ // - uint32 flags describing how to treat the cert contained in this level
+ // - uint32 signature algorithm ID to use to verify the signature of the next level. The
+ // algorithm here must match the one in the signed data section of the next level.
+ // - length-prefixed signature over the signed data in this level. The signature here
+ // is verified using the certificate from the previous level.
+ // The linking is provided by the certificate of each level signing the one of the next.
+ while (porBuf.hasRemaining()) {
+ levelCount++;
+ try {
+ ByteBuffer level = getLengthPrefixedSlice(porBuf);
+ ByteBuffer signedData = getLengthPrefixedSlice(level);
+ int flags = level.getInt();
+ int sigAlgorithm = level.getInt();
+ byte[] signature = readLengthPrefixedByteArray(level);
+
+ if (lastCert != null) {
+ // Use previous level cert to verify current level
+ Pair<String, ? extends AlgorithmParameterSpec> sigAlgParams =
+ getSignatureAlgorithmJcaSignatureAlgorithm(lastSigAlgorithm);
+ PublicKey publicKey = lastCert.getPublicKey();
+ Signature sig = Signature.getInstance(sigAlgParams.first);
+ sig.initVerify(publicKey);
+ if (sigAlgParams.second != null) {
+ sig.setParameter(sigAlgParams.second);
+ }
+ sig.update(signedData);
+ if (!sig.verify(signature)) {
+ throw new SecurityException("Unable to verify signature of certificate #"
+ + levelCount + " using " + sigAlgParams.first + " when verifying"
+ + " Proof-of-rotation record");
+ }
+ }
+
+ byte[] encodedCert = readLengthPrefixedByteArray(signedData);
+ int signedSigAlgorithm = signedData.getInt();
+ if (lastCert != null && lastSigAlgorithm != signedSigAlgorithm) {
+ throw new SecurityException("Signing algorithm ID mismatch for certificate #"
+ + levelCount + " when verifying Proof-of-rotation record");
+ }
+ lastCert = (X509Certificate)
+ certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
+ lastCert = new VerbatimX509Certificate(lastCert, encodedCert);
+
+ lastSigAlgorithm = sigAlgorithm;
+ certs.add(lastCert);
+ flagsList.add(flags);
+ } catch (IOException | BufferUnderflowException e) {
+ throw new IOException("Failed to parse Proof-of-rotation record", e);
+ } catch (NoSuchAlgorithmException | InvalidKeyException
+ | InvalidAlgorithmParameterException | SignatureException e) {
+ throw new SecurityException(
+ "Failed to verify signature over signed data for certificate #"
+ + levelCount + " when verifying Proof-of-rotation record", e);
+ } catch (CertificateException e) {
+ throw new SecurityException("Failed to decode certificate #" + levelCount
+ + " when verifying Proof-of-rotation record", e);
+ }
+ }
+ return new VerifiedProofOfRotation(certs, flagsList);
+ }
+
+ private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
+ switch (sigAlgorithm) {
+ case SIGNATURE_RSA_PSS_WITH_SHA256:
+ case SIGNATURE_RSA_PSS_WITH_SHA512:
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+ case SIGNATURE_ECDSA_WITH_SHA256:
+ case SIGNATURE_ECDSA_WITH_SHA512:
+ case SIGNATURE_DSA_WITH_SHA256:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Verified processed proof of rotation.
+ *
+ * @hide for internal use only.
+ */
+ public static class VerifiedProofOfRotation {
+ public final List<X509Certificate> certs;
+ public final List<Integer> flagsList;
+
+ public VerifiedProofOfRotation(List<X509Certificate> certs, List<Integer> flagsList) {
+ this.certs = certs;
+ this.flagsList = flagsList;
+ }
+ }
+
+ /**
+ * Verified APK Signature Scheme v3 signer, including the proof of rotation structure.
+ *
+ * @hide for internal use only.
+ */
+ public static class VerifiedSigner {
+ public final X509Certificate[] certs;
+ public final VerifiedProofOfRotation por;
+
+ public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por) {
+ this.certs = certs;
+ this.por = por;
+ }
+
+ }
+
+ private static class PlatformNotSupportedException extends Exception {
+
+ PlatformNotSupportedException(String s) {
+ super(s);
+ }
+ }
+}
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 17b11a9b5170..81467292d491 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -54,6 +54,7 @@ public class ApkSignatureVerifier {
public static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
public static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
+ public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3;
private static final AtomicReference<byte[]> sBuffer = new AtomicReference<>();
@@ -65,7 +66,45 @@ public class ApkSignatureVerifier {
public static Result verify(String apkPath, int minSignatureSchemeVersion)
throws PackageParserException {
- // first try v2
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V3) {
+ // V3 and before are older than the requested minimum signing version
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No signature found in package of version " + minSignatureSchemeVersion
+ + " or newer for package " + apkPath);
+ }
+
+ // first try v3
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3");
+ try {
+ ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
+ ApkSignatureSchemeV3Verifier.verify(apkPath);
+ Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
+ Signature[] signerSigs = convertToSignatures(signerCerts);
+ return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V3);
+ } catch (SignatureNotFoundException e) {
+ // not signed with v2, try older if allowed
+ if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V3) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No APK Signature Scheme v3 signature in package " + apkPath, e);
+ }
+ } catch (Exception e) {
+ // APK Signature Scheme v2 signature found but did not verify
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + apkPath
+ + " using APK Signature Scheme v2", e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // redundant, protective version check
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V2) {
+ // V2 and before are older than the requested minimum signing version
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No signature found in package of version " + minSignatureSchemeVersion
+ + " or newer for package " + apkPath);
+ }
+
+ // try v2
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
try {
Certificate[][] signerCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
@@ -87,6 +126,14 @@ public class ApkSignatureVerifier {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ // redundant, protective version check
+ if (minSignatureSchemeVersion > VERSION_JAR_SIGNATURE_SCHEME) {
+ // V1 and is older than the requested minimum signing version
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No signature found in package of version " + minSignatureSchemeVersion
+ + " or newer for package " + apkPath);
+ }
+
// v2 didn't work, try jarsigner
return verifyV1Signature(apkPath, true);
}
@@ -245,6 +292,44 @@ public class ApkSignatureVerifier {
public static Result plsCertsNoVerifyOnlyCerts(String apkPath, int minSignatureSchemeVersion)
throws PackageParserException {
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V3) {
+ // V3 and before are older than the requested minimum signing version
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No signature found in package of version " + minSignatureSchemeVersion
+ + " or newer for package " + apkPath);
+ }
+
+ // first try v3
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3");
+ try {
+ ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
+ ApkSignatureSchemeV3Verifier.plsCertsNoVerifyOnlyCerts(apkPath);
+ Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
+ Signature[] signerSigs = convertToSignatures(signerCerts);
+ return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V3);
+ } catch (SignatureNotFoundException e) {
+ // not signed with v2, try older if allowed
+ if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V3) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No APK Signature Scheme v3 signature in package " + apkPath, e);
+ }
+ } catch (Exception e) {
+ // APK Signature Scheme v2 signature found but did not verify
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + apkPath
+ + " using APK Signature Scheme v2", e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // redundant, protective version check
+ if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V2) {
+ // V2 and before are older than the requested minimum signing version
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No signature found in package of version " + minSignatureSchemeVersion
+ + " or newer for package " + apkPath);
+ }
+
// first try v2
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV2");
try {
@@ -267,6 +352,14 @@ public class ApkSignatureVerifier {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ // redundant, protective version check
+ if (minSignatureSchemeVersion > VERSION_JAR_SIGNATURE_SCHEME) {
+ // V1 and is older than the requested minimum signing version
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No signature found in package of version " + minSignatureSchemeVersion
+ + " or newer for package " + apkPath);
+ }
+
// v2 didn't work, try jarsigner
return verifyV1Signature(apkPath, false);
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
new file mode 100644
index 000000000000..9279510ae58f
--- /dev/null
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -0,0 +1,663 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import android.util.Pair;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+import java.util.Map;
+
+/**
+ * Utility class for an APK Signature Scheme using the APK Signing Block.
+ *
+ * @hide for internal use only.
+ */
+final class ApkSigningBlockUtils {
+
+ private ApkSigningBlockUtils() {
+ }
+
+ /**
+ * Returns the APK Signature Scheme block contained in the provided APK file and the
+ * additional information relevant for verifying the block against the file.
+ *
+ * @param blockId the ID value in the APK Signing Block's sequence of ID-value pairs
+ * identifying the appropriate block to find, e.g. the APK Signature Scheme v2
+ * block ID.
+ *
+ * @throws SignatureNotFoundException if the APK is not signed using this scheme.
+ * @throws IOException if an I/O error occurs while reading the APK file.
+ */
+ static SignatureInfo findSignature(RandomAccessFile apk, int blockId)
+ throws IOException, SignatureNotFoundException {
+ // Find the ZIP End of Central Directory (EoCD) record.
+ Pair<ByteBuffer, Long> eocdAndOffsetInFile = getEocd(apk);
+ ByteBuffer eocd = eocdAndOffsetInFile.first;
+ long eocdOffset = eocdAndOffsetInFile.second;
+ if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apk, eocdOffset)) {
+ throw new SignatureNotFoundException("ZIP64 APK not supported");
+ }
+
+ // Find the APK Signing Block. The block immediately precedes the Central Directory.
+ long centralDirOffset = getCentralDirOffset(eocd, eocdOffset);
+ Pair<ByteBuffer, Long> apkSigningBlockAndOffsetInFile =
+ findApkSigningBlock(apk, centralDirOffset);
+ ByteBuffer apkSigningBlock = apkSigningBlockAndOffsetInFile.first;
+ long apkSigningBlockOffset = apkSigningBlockAndOffsetInFile.second;
+
+ // Find the APK Signature Scheme Block inside the APK Signing Block.
+ ByteBuffer apkSignatureSchemeBlock = findApkSignatureSchemeBlock(apkSigningBlock,
+ blockId);
+
+ return new SignatureInfo(
+ apkSignatureSchemeBlock,
+ apkSigningBlockOffset,
+ centralDirOffset,
+ eocdOffset,
+ eocd);
+ }
+
+ static void verifyIntegrity(
+ Map<Integer, byte[]> expectedDigests,
+ FileDescriptor apkFileDescriptor,
+ long apkSigningBlockOffset,
+ long centralDirOffset,
+ long eocdOffset,
+ ByteBuffer eocdBuf) throws SecurityException {
+
+ if (expectedDigests.isEmpty()) {
+ throw new SecurityException("No digests provided");
+ }
+
+ // We need to verify the integrity of the following three sections of the file:
+ // 1. Everything up to the start of the APK Signing Block.
+ // 2. ZIP Central Directory.
+ // 3. ZIP End of Central Directory (EoCD).
+ // Each of these sections is represented as a separate DataSource instance below.
+
+ // To handle large APKs, these sections are read in 1 MB chunks using memory-mapped I/O to
+ // avoid wasting physical memory. In most APK verification scenarios, the contents of the
+ // APK are already there in the OS's page cache and thus mmap does not use additional
+ // physical memory.
+ DataSource beforeApkSigningBlock =
+ new MemoryMappedFileDataSource(apkFileDescriptor, 0, apkSigningBlockOffset);
+ DataSource centralDir =
+ new MemoryMappedFileDataSource(
+ apkFileDescriptor, centralDirOffset, eocdOffset - centralDirOffset);
+
+ // For the purposes of integrity verification, ZIP End of Central Directory's field Start of
+ // Central Directory must be considered to point to the offset of the APK Signing Block.
+ eocdBuf = eocdBuf.duplicate();
+ eocdBuf.order(ByteOrder.LITTLE_ENDIAN);
+ ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, apkSigningBlockOffset);
+ DataSource eocd = new ByteBufferDataSource(eocdBuf);
+
+ int[] digestAlgorithms = new int[expectedDigests.size()];
+ int digestAlgorithmCount = 0;
+ for (int digestAlgorithm : expectedDigests.keySet()) {
+ digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
+ digestAlgorithmCount++;
+ }
+ byte[][] actualDigests;
+ try {
+ actualDigests =
+ computeContentDigests(
+ digestAlgorithms,
+ new DataSource[] {beforeApkSigningBlock, centralDir, eocd});
+ } catch (DigestException e) {
+ throw new SecurityException("Failed to compute digest(s) of contents", e);
+ }
+ for (int i = 0; i < digestAlgorithms.length; i++) {
+ int digestAlgorithm = digestAlgorithms[i];
+ byte[] expectedDigest = expectedDigests.get(digestAlgorithm);
+ byte[] actualDigest = actualDigests[i];
+ if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
+ throw new SecurityException(
+ getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
+ + " digest of contents did not verify");
+ }
+ }
+ }
+
+ private static byte[][] computeContentDigests(
+ int[] digestAlgorithms,
+ DataSource[] contents) throws DigestException {
+ // For each digest algorithm the result is computed as follows:
+ // 1. Each segment of contents is split into consecutive chunks of 1 MB in size.
+ // The final chunk will be shorter iff the length of segment is not a multiple of 1 MB.
+ // No chunks are produced for empty (zero length) segments.
+ // 2. The digest of each chunk is computed over the concatenation of byte 0xa5, the chunk's
+ // length in bytes (uint32 little-endian) and the chunk's contents.
+ // 3. The output digest is computed over the concatenation of the byte 0x5a, the number of
+ // chunks (uint32 little-endian) and the concatenation of digests of chunks of all
+ // segments in-order.
+
+ long totalChunkCountLong = 0;
+ for (DataSource input : contents) {
+ totalChunkCountLong += getChunkCount(input.size());
+ }
+ if (totalChunkCountLong >= Integer.MAX_VALUE / 1024) {
+ throw new DigestException("Too many chunks: " + totalChunkCountLong);
+ }
+ int totalChunkCount = (int) totalChunkCountLong;
+
+ byte[][] digestsOfChunks = new byte[digestAlgorithms.length][];
+ for (int i = 0; i < digestAlgorithms.length; i++) {
+ int digestAlgorithm = digestAlgorithms[i];
+ int digestOutputSizeBytes = getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
+ byte[] concatenationOfChunkCountAndChunkDigests =
+ new byte[5 + totalChunkCount * digestOutputSizeBytes];
+ concatenationOfChunkCountAndChunkDigests[0] = 0x5a;
+ setUnsignedInt32LittleEndian(
+ totalChunkCount,
+ concatenationOfChunkCountAndChunkDigests,
+ 1);
+ digestsOfChunks[i] = concatenationOfChunkCountAndChunkDigests;
+ }
+
+ byte[] chunkContentPrefix = new byte[5];
+ chunkContentPrefix[0] = (byte) 0xa5;
+ int chunkIndex = 0;
+ MessageDigest[] mds = new MessageDigest[digestAlgorithms.length];
+ for (int i = 0; i < digestAlgorithms.length; i++) {
+ String jcaAlgorithmName =
+ getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithms[i]);
+ try {
+ mds[i] = MessageDigest.getInstance(jcaAlgorithmName);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
+ }
+ }
+ // TODO: Compute digests of chunks in parallel when beneficial. This requires some research
+ // into how to parallelize (if at all) based on the capabilities of the hardware on which
+ // this code is running and based on the size of input.
+ DataDigester digester = new MultipleDigestDataDigester(mds);
+ int dataSourceIndex = 0;
+ for (DataSource input : contents) {
+ long inputOffset = 0;
+ long inputRemaining = input.size();
+ while (inputRemaining > 0) {
+ int chunkSize = (int) Math.min(inputRemaining, CHUNK_SIZE_BYTES);
+ setUnsignedInt32LittleEndian(chunkSize, chunkContentPrefix, 1);
+ for (int i = 0; i < mds.length; i++) {
+ mds[i].update(chunkContentPrefix);
+ }
+ try {
+ input.feedIntoDataDigester(digester, inputOffset, chunkSize);
+ } catch (IOException e) {
+ throw new DigestException(
+ "Failed to digest chunk #" + chunkIndex + " of section #"
+ + dataSourceIndex,
+ e);
+ }
+ for (int i = 0; i < digestAlgorithms.length; i++) {
+ int digestAlgorithm = digestAlgorithms[i];
+ byte[] concatenationOfChunkCountAndChunkDigests = digestsOfChunks[i];
+ int expectedDigestSizeBytes =
+ getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
+ MessageDigest md = mds[i];
+ int actualDigestSizeBytes =
+ md.digest(
+ concatenationOfChunkCountAndChunkDigests,
+ 5 + chunkIndex * expectedDigestSizeBytes,
+ expectedDigestSizeBytes);
+ if (actualDigestSizeBytes != expectedDigestSizeBytes) {
+ throw new RuntimeException(
+ "Unexpected output size of " + md.getAlgorithm() + " digest: "
+ + actualDigestSizeBytes);
+ }
+ }
+ inputOffset += chunkSize;
+ inputRemaining -= chunkSize;
+ chunkIndex++;
+ }
+ dataSourceIndex++;
+ }
+
+ byte[][] result = new byte[digestAlgorithms.length][];
+ for (int i = 0; i < digestAlgorithms.length; i++) {
+ int digestAlgorithm = digestAlgorithms[i];
+ byte[] input = digestsOfChunks[i];
+ String jcaAlgorithmName = getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm);
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance(jcaAlgorithmName);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
+ }
+ byte[] output = md.digest(input);
+ result[i] = output;
+ }
+ return result;
+ }
+
+ /**
+ * Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
+ *
+ * @throws IOException if an I/O error occurs while reading the file.
+ * @throws SignatureNotFoundException if the EoCD could not be found.
+ */
+ static Pair<ByteBuffer, Long> getEocd(RandomAccessFile apk)
+ throws IOException, SignatureNotFoundException {
+ Pair<ByteBuffer, Long> eocdAndOffsetInFile =
+ ZipUtils.findZipEndOfCentralDirectoryRecord(apk);
+ if (eocdAndOffsetInFile == null) {
+ throw new SignatureNotFoundException(
+ "Not an APK file: ZIP End of Central Directory record not found");
+ }
+ return eocdAndOffsetInFile;
+ }
+
+ static long getCentralDirOffset(ByteBuffer eocd, long eocdOffset)
+ throws SignatureNotFoundException {
+ // Look up the offset of ZIP Central Directory.
+ long centralDirOffset = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
+ if (centralDirOffset > eocdOffset) {
+ throw new SignatureNotFoundException(
+ "ZIP Central Directory offset out of range: " + centralDirOffset
+ + ". ZIP End of Central Directory offset: " + eocdOffset);
+ }
+ long centralDirSize = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
+ if (centralDirOffset + centralDirSize != eocdOffset) {
+ throw new SignatureNotFoundException(
+ "ZIP Central Directory is not immediately followed by End of Central"
+ + " Directory");
+ }
+ return centralDirOffset;
+ }
+
+ private static long getChunkCount(long inputSizeBytes) {
+ return (inputSizeBytes + CHUNK_SIZE_BYTES - 1) / CHUNK_SIZE_BYTES;
+ }
+
+ private static final int CHUNK_SIZE_BYTES = 1024 * 1024;
+
+ static final int SIGNATURE_RSA_PSS_WITH_SHA256 = 0x0101;
+ static final int SIGNATURE_RSA_PSS_WITH_SHA512 = 0x0102;
+ static final int SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0103;
+ static final int SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512 = 0x0104;
+ static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
+ static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
+ static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
+
+ static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
+ static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
+
+ static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) {
+ int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1);
+ int digestAlgorithm2 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm2);
+ return compareContentDigestAlgorithm(digestAlgorithm1, digestAlgorithm2);
+ }
+
+ private static int compareContentDigestAlgorithm(int digestAlgorithm1, int digestAlgorithm2) {
+ switch (digestAlgorithm1) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ switch (digestAlgorithm2) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ return 0;
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ return -1;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown digestAlgorithm2: " + digestAlgorithm2);
+ }
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ switch (digestAlgorithm2) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ return 1;
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ return 0;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown digestAlgorithm2: " + digestAlgorithm2);
+ }
+ default:
+ throw new IllegalArgumentException("Unknown digestAlgorithm1: " + digestAlgorithm1);
+ }
+ }
+
+ static int getSignatureAlgorithmContentDigestAlgorithm(int sigAlgorithm) {
+ switch (sigAlgorithm) {
+ case SIGNATURE_RSA_PSS_WITH_SHA256:
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+ case SIGNATURE_ECDSA_WITH_SHA256:
+ case SIGNATURE_DSA_WITH_SHA256:
+ return CONTENT_DIGEST_CHUNKED_SHA256;
+ case SIGNATURE_RSA_PSS_WITH_SHA512:
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+ case SIGNATURE_ECDSA_WITH_SHA512:
+ return CONTENT_DIGEST_CHUNKED_SHA512;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown signature algorithm: 0x"
+ + Long.toHexString(sigAlgorithm & 0xffffffff));
+ }
+ }
+
+ static String getContentDigestAlgorithmJcaDigestAlgorithm(int digestAlgorithm) {
+ switch (digestAlgorithm) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ return "SHA-256";
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ return "SHA-512";
+ default:
+ throw new IllegalArgumentException(
+ "Unknown content digest algorthm: " + digestAlgorithm);
+ }
+ }
+
+ private static int getContentDigestAlgorithmOutputSizeBytes(int digestAlgorithm) {
+ switch (digestAlgorithm) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ return 256 / 8;
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ return 512 / 8;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown content digest algorthm: " + digestAlgorithm);
+ }
+ }
+
+ static String getSignatureAlgorithmJcaKeyAlgorithm(int sigAlgorithm) {
+ switch (sigAlgorithm) {
+ case SIGNATURE_RSA_PSS_WITH_SHA256:
+ case SIGNATURE_RSA_PSS_WITH_SHA512:
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+ return "RSA";
+ case SIGNATURE_ECDSA_WITH_SHA256:
+ case SIGNATURE_ECDSA_WITH_SHA512:
+ return "EC";
+ case SIGNATURE_DSA_WITH_SHA256:
+ return "DSA";
+ default:
+ throw new IllegalArgumentException(
+ "Unknown signature algorithm: 0x"
+ + Long.toHexString(sigAlgorithm & 0xffffffff));
+ }
+ }
+
+ static Pair<String, ? extends AlgorithmParameterSpec>
+ getSignatureAlgorithmJcaSignatureAlgorithm(int sigAlgorithm) {
+ switch (sigAlgorithm) {
+ case SIGNATURE_RSA_PSS_WITH_SHA256:
+ return Pair.create(
+ "SHA256withRSA/PSS",
+ new PSSParameterSpec(
+ "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 256 / 8, 1));
+ case SIGNATURE_RSA_PSS_WITH_SHA512:
+ return Pair.create(
+ "SHA512withRSA/PSS",
+ new PSSParameterSpec(
+ "SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 512 / 8, 1));
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+ return Pair.create("SHA256withRSA", null);
+ case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+ return Pair.create("SHA512withRSA", null);
+ case SIGNATURE_ECDSA_WITH_SHA256:
+ return Pair.create("SHA256withECDSA", null);
+ case SIGNATURE_ECDSA_WITH_SHA512:
+ return Pair.create("SHA512withECDSA", null);
+ case SIGNATURE_DSA_WITH_SHA256:
+ return Pair.create("SHA256withDSA", null);
+ default:
+ throw new IllegalArgumentException(
+ "Unknown signature algorithm: 0x"
+ + Long.toHexString(sigAlgorithm & 0xffffffff));
+ }
+ }
+
+ /**
+ * Returns new byte buffer whose content is a shared subsequence of this buffer's content
+ * between the specified start (inclusive) and end (exclusive) positions. As opposed to
+ * {@link ByteBuffer#slice()}, the returned buffer's byte order is the same as the source
+ * buffer's byte order.
+ */
+ static ByteBuffer sliceFromTo(ByteBuffer source, int start, int end) {
+ if (start < 0) {
+ throw new IllegalArgumentException("start: " + start);
+ }
+ if (end < start) {
+ throw new IllegalArgumentException("end < start: " + end + " < " + start);
+ }
+ int capacity = source.capacity();
+ if (end > source.capacity()) {
+ throw new IllegalArgumentException("end > capacity: " + end + " > " + capacity);
+ }
+ int originalLimit = source.limit();
+ int originalPosition = source.position();
+ try {
+ source.position(0);
+ source.limit(end);
+ source.position(start);
+ ByteBuffer result = source.slice();
+ result.order(source.order());
+ return result;
+ } finally {
+ source.position(0);
+ source.limit(originalLimit);
+ source.position(originalPosition);
+ }
+ }
+
+ /**
+ * Relative <em>get</em> method for reading {@code size} number of bytes from the current
+ * position of this buffer.
+ *
+ * <p>This method reads the next {@code size} bytes at this buffer's current position,
+ * returning them as a {@code ByteBuffer} with start set to 0, limit and capacity set to
+ * {@code size}, byte order set to this buffer's byte order; and then increments the position by
+ * {@code size}.
+ */
+ static ByteBuffer getByteBuffer(ByteBuffer source, int size)
+ throws BufferUnderflowException {
+ if (size < 0) {
+ throw new IllegalArgumentException("size: " + size);
+ }
+ int originalLimit = source.limit();
+ int position = source.position();
+ int limit = position + size;
+ if ((limit < position) || (limit > originalLimit)) {
+ throw new BufferUnderflowException();
+ }
+ source.limit(limit);
+ try {
+ ByteBuffer result = source.slice();
+ result.order(source.order());
+ source.position(limit);
+ return result;
+ } finally {
+ source.limit(originalLimit);
+ }
+ }
+
+ static ByteBuffer getLengthPrefixedSlice(ByteBuffer source) throws IOException {
+ if (source.remaining() < 4) {
+ throw new IOException(
+ "Remaining buffer too short to contain length of length-prefixed field."
+ + " Remaining: " + source.remaining());
+ }
+ int len = source.getInt();
+ if (len < 0) {
+ throw new IllegalArgumentException("Negative length");
+ } else if (len > source.remaining()) {
+ throw new IOException("Length-prefixed field longer than remaining buffer."
+ + " Field length: " + len + ", remaining: " + source.remaining());
+ }
+ return getByteBuffer(source, len);
+ }
+
+ static byte[] readLengthPrefixedByteArray(ByteBuffer buf) throws IOException {
+ int len = buf.getInt();
+ if (len < 0) {
+ throw new IOException("Negative length");
+ } else if (len > buf.remaining()) {
+ throw new IOException("Underflow while reading length-prefixed value. Length: " + len
+ + ", available: " + buf.remaining());
+ }
+ byte[] result = new byte[len];
+ buf.get(result);
+ return result;
+ }
+
+ static void setUnsignedInt32LittleEndian(int value, byte[] result, int offset) {
+ result[offset] = (byte) (value & 0xff);
+ result[offset + 1] = (byte) ((value >>> 8) & 0xff);
+ result[offset + 2] = (byte) ((value >>> 16) & 0xff);
+ result[offset + 3] = (byte) ((value >>> 24) & 0xff);
+ }
+
+ private static final long APK_SIG_BLOCK_MAGIC_HI = 0x3234206b636f6c42L;
+ private static final long APK_SIG_BLOCK_MAGIC_LO = 0x20676953204b5041L;
+ private static final int APK_SIG_BLOCK_MIN_SIZE = 32;
+
+ static Pair<ByteBuffer, Long> findApkSigningBlock(
+ RandomAccessFile apk, long centralDirOffset)
+ throws IOException, SignatureNotFoundException {
+ // FORMAT:
+ // OFFSET DATA TYPE DESCRIPTION
+ // * @+0 bytes uint64: size in bytes (excluding this field)
+ // * @+8 bytes payload
+ // * @-24 bytes uint64: size in bytes (same as the one above)
+ // * @-16 bytes uint128: magic
+
+ if (centralDirOffset < APK_SIG_BLOCK_MIN_SIZE) {
+ throw new SignatureNotFoundException(
+ "APK too small for APK Signing Block. ZIP Central Directory offset: "
+ + centralDirOffset);
+ }
+ // Read the magic and offset in file from the footer section of the block:
+ // * uint64: size of block
+ // * 16 bytes: magic
+ ByteBuffer footer = ByteBuffer.allocate(24);
+ footer.order(ByteOrder.LITTLE_ENDIAN);
+ apk.seek(centralDirOffset - footer.capacity());
+ apk.readFully(footer.array(), footer.arrayOffset(), footer.capacity());
+ if ((footer.getLong(8) != APK_SIG_BLOCK_MAGIC_LO)
+ || (footer.getLong(16) != APK_SIG_BLOCK_MAGIC_HI)) {
+ throw new SignatureNotFoundException(
+ "No APK Signing Block before ZIP Central Directory");
+ }
+ // Read and compare size fields
+ long apkSigBlockSizeInFooter = footer.getLong(0);
+ if ((apkSigBlockSizeInFooter < footer.capacity())
+ || (apkSigBlockSizeInFooter > Integer.MAX_VALUE - 8)) {
+ throw new SignatureNotFoundException(
+ "APK Signing Block size out of range: " + apkSigBlockSizeInFooter);
+ }
+ int totalSize = (int) (apkSigBlockSizeInFooter + 8);
+ long apkSigBlockOffset = centralDirOffset - totalSize;
+ if (apkSigBlockOffset < 0) {
+ throw new SignatureNotFoundException(
+ "APK Signing Block offset out of range: " + apkSigBlockOffset);
+ }
+ ByteBuffer apkSigBlock = ByteBuffer.allocate(totalSize);
+ apkSigBlock.order(ByteOrder.LITTLE_ENDIAN);
+ apk.seek(apkSigBlockOffset);
+ apk.readFully(apkSigBlock.array(), apkSigBlock.arrayOffset(), apkSigBlock.capacity());
+ long apkSigBlockSizeInHeader = apkSigBlock.getLong(0);
+ if (apkSigBlockSizeInHeader != apkSigBlockSizeInFooter) {
+ throw new SignatureNotFoundException(
+ "APK Signing Block sizes in header and footer do not match: "
+ + apkSigBlockSizeInHeader + " vs " + apkSigBlockSizeInFooter);
+ }
+ return Pair.create(apkSigBlock, apkSigBlockOffset);
+ }
+
+ static ByteBuffer findApkSignatureSchemeBlock(ByteBuffer apkSigningBlock, int blockId)
+ throws SignatureNotFoundException {
+ checkByteOrderLittleEndian(apkSigningBlock);
+ // FORMAT:
+ // OFFSET DATA TYPE DESCRIPTION
+ // * @+0 bytes uint64: size in bytes (excluding this field)
+ // * @+8 bytes pairs
+ // * @-24 bytes uint64: size in bytes (same as the one above)
+ // * @-16 bytes uint128: magic
+ ByteBuffer pairs = sliceFromTo(apkSigningBlock, 8, apkSigningBlock.capacity() - 24);
+
+ int entryCount = 0;
+ while (pairs.hasRemaining()) {
+ entryCount++;
+ if (pairs.remaining() < 8) {
+ throw new SignatureNotFoundException(
+ "Insufficient data to read size of APK Signing Block entry #" + entryCount);
+ }
+ long lenLong = pairs.getLong();
+ if ((lenLong < 4) || (lenLong > Integer.MAX_VALUE)) {
+ throw new SignatureNotFoundException(
+ "APK Signing Block entry #" + entryCount
+ + " size out of range: " + lenLong);
+ }
+ int len = (int) lenLong;
+ int nextEntryPos = pairs.position() + len;
+ if (len > pairs.remaining()) {
+ throw new SignatureNotFoundException(
+ "APK Signing Block entry #" + entryCount + " size out of range: " + len
+ + ", available: " + pairs.remaining());
+ }
+ int id = pairs.getInt();
+ if (id == blockId) {
+ return getByteBuffer(pairs, len - 4);
+ }
+ pairs.position(nextEntryPos);
+ }
+
+ throw new SignatureNotFoundException(
+ "No block with ID " + blockId + " in APK Signing Block.");
+ }
+
+ private static void checkByteOrderLittleEndian(ByteBuffer buffer) {
+ if (buffer.order() != ByteOrder.LITTLE_ENDIAN) {
+ throw new IllegalArgumentException("ByteBuffer byte order must be little endian");
+ }
+ }
+
+ /**
+ * {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is fed.
+ */
+ private static class MultipleDigestDataDigester implements DataDigester {
+ private final MessageDigest[] mMds;
+
+ MultipleDigestDataDigester(MessageDigest[] mds) {
+ mMds = mds;
+ }
+
+ @Override
+ public void consume(ByteBuffer buffer) {
+ buffer = buffer.slice();
+ for (MessageDigest md : mMds) {
+ buffer.position(0);
+ md.update(buffer);
+ }
+ }
+
+ @Override
+ public void finish() {}
+ }
+
+}
diff --git a/core/java/android/util/apk/VerbatimX509Certificate.java b/core/java/android/util/apk/VerbatimX509Certificate.java
new file mode 100644
index 000000000000..9984c6d26c64
--- /dev/null
+++ b/core/java/android/util/apk/VerbatimX509Certificate.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+/**
+ * For legacy reasons we need to return exactly the original encoded certificate bytes, instead
+ * of letting the underlying implementation have a shot at re-encoding the data.
+ */
+class VerbatimX509Certificate extends WrappedX509Certificate {
+ private final byte[] mEncodedVerbatim;
+
+ VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) {
+ super(wrapped);
+ this.mEncodedVerbatim = encodedVerbatim;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return mEncodedVerbatim;
+ }
+}
diff --git a/core/java/android/util/apk/WrappedX509Certificate.java b/core/java/android/util/apk/WrappedX509Certificate.java
new file mode 100644
index 000000000000..fdaa42028e8d
--- /dev/null
+++ b/core/java/android/util/apk/WrappedX509Certificate.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Set;
+
+class WrappedX509Certificate extends X509Certificate {
+ private final X509Certificate mWrapped;
+
+ WrappedX509Certificate(X509Certificate wrapped) {
+ this.mWrapped = wrapped;
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ return mWrapped.getCriticalExtensionOIDs();
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return mWrapped.getExtensionValue(oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ return mWrapped.getNonCriticalExtensionOIDs();
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ return mWrapped.hasUnsupportedCriticalExtension();
+ }
+
+ @Override
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException {
+ mWrapped.checkValidity();
+ }
+
+ @Override
+ public void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException {
+ mWrapped.checkValidity(date);
+ }
+
+ @Override
+ public int getVersion() {
+ return mWrapped.getVersion();
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return mWrapped.getSerialNumber();
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return mWrapped.getIssuerDN();
+ }
+
+ @Override
+ public Principal getSubjectDN() {
+ return mWrapped.getSubjectDN();
+ }
+
+ @Override
+ public Date getNotBefore() {
+ return mWrapped.getNotBefore();
+ }
+
+ @Override
+ public Date getNotAfter() {
+ return mWrapped.getNotAfter();
+ }
+
+ @Override
+ public byte[] getTBSCertificate() throws CertificateEncodingException {
+ return mWrapped.getTBSCertificate();
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return mWrapped.getSignature();
+ }
+
+ @Override
+ public String getSigAlgName() {
+ return mWrapped.getSigAlgName();
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return mWrapped.getSigAlgOID();
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return mWrapped.getSigAlgParams();
+ }
+
+ @Override
+ public boolean[] getIssuerUniqueID() {
+ return mWrapped.getIssuerUniqueID();
+ }
+
+ @Override
+ public boolean[] getSubjectUniqueID() {
+ return mWrapped.getSubjectUniqueID();
+ }
+
+ @Override
+ public boolean[] getKeyUsage() {
+ return mWrapped.getKeyUsage();
+ }
+
+ @Override
+ public int getBasicConstraints() {
+ return mWrapped.getBasicConstraints();
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return mWrapped.getEncoded();
+ }
+
+ @Override
+ public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ mWrapped.verify(key);
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException {
+ mWrapped.verify(key, sigProvider);
+ }
+
+ @Override
+ public String toString() {
+ return mWrapped.toString();
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ return mWrapped.getPublicKey();
+ }
+}
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index debc170fa537..45254908c5c9 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -18,6 +18,8 @@
package android.util.jar;
import android.util.apk.ApkSignatureSchemeV2Verifier;
+import android.util.apk.ApkSignatureSchemeV3Verifier;
+
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
@@ -36,6 +38,7 @@ import java.util.Map;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
+
import sun.security.jca.Providers;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
@@ -56,6 +59,15 @@ import sun.security.pkcs.SignerInfo;
*/
class StrictJarVerifier {
/**
+ * {@code .SF} file header section attribute indicating that the APK is signed not just with
+ * JAR signature scheme but also with APK Signature Scheme v2 or newer. This attribute
+ * facilitates v2 signature stripping detection.
+ *
+ * <p>The attribute contains a comma-separated set of signature scheme IDs.
+ */
+ private static final String SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME = "X-Android-APK-Signed";
+
+ /**
* List of accepted digest algorithms. This list is in order from most
* preferred to least preferred.
*/
@@ -373,17 +385,17 @@ class StrictJarVerifier {
return;
}
- // If requested, check whether APK Signature Scheme v2 signature was stripped.
+ // If requested, check whether a newer APK Signature Scheme signature was stripped.
if (signatureSchemeRollbackProtectionsEnforced) {
String apkSignatureSchemeIdList =
- attributes.getValue(
- ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME);
+ attributes.getValue(SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME);
if (apkSignatureSchemeIdList != null) {
// This field contains a comma-separated list of APK signature scheme IDs which
// were used to sign this APK. If an ID is known to us, it means signatures of that
// scheme were stripped from the APK because otherwise we wouldn't have fallen back
// to verifying the APK using the JAR signature scheme.
boolean v2SignatureGenerated = false;
+ boolean v3SignatureGenerated = false;
StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
while (tokenizer.hasMoreTokens()) {
String idText = tokenizer.nextToken().trim();
@@ -402,6 +414,12 @@ class StrictJarVerifier {
v2SignatureGenerated = true;
break;
}
+ if (id == ApkSignatureSchemeV3Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) {
+ // This APK was supposed to be signed with APK Signature Scheme v3 but no
+ // such signature was found.
+ v3SignatureGenerated = true;
+ break;
+ }
}
if (v2SignatureGenerated) {
@@ -409,6 +427,11 @@ class StrictJarVerifier {
+ " is signed using APK Signature Scheme v2, but no such signature was"
+ " found. Signature stripped?");
}
+ if (v3SignatureGenerated) {
+ throw new SecurityException(signatureFile + " indicates " + jarName
+ + " is signed using APK Signature Scheme v3, but no such signature was"
+ + " found. Signature stripped?");
+ }
}
}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index e448f14ca97d..3dcfd00bc34c 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.DisplayCutoutProto.BOUNDS;
+import static android.view.DisplayCutoutProto.INSETS;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
@@ -28,6 +30,7 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -155,6 +158,16 @@ public final class DisplayCutout {
}
/**
+ * @hide
+ */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ mSafeInsets.writeToProto(proto, INSETS);
+ mBounds.getBounds().writeToProto(proto, BOUNDS);
+ proto.end(token);
+ }
+
+ /**
* Insets the reference frame of the cutout in the given directions.
*
* @return a copy of this instance which has been inset
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cc63a62c5651..841888f96d63 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4182,6 +4182,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private static boolean sUseDefaultFocusHighlight;
+ /**
+ * True if zero-sized views can be focused.
+ */
+ private static boolean sCanFocusZeroSized;
+
private String mTransitionName;
static class TintInfo {
@@ -4798,6 +4803,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P;
+ sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P;
+
sCompatibilityDone = true;
}
}
@@ -7010,6 +7017,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
mPrivateFlags &= ~PFLAG_FOCUSED;
+ clearParentsWantFocus();
if (propagate && mParent != null) {
mParent.clearChildFocus(this);
@@ -10046,6 +10054,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @return {@code true} if laid-out and not about to do another layout.
+ */
+ boolean isLayoutValid() {
+ return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0);
+ }
+
+ /**
* If this view doesn't do any drawing on its own, set this flag to
* allow further optimizations. By default, this flag is not set on
* View, but could be set on some View subclasses such as ViewGroup.
@@ -10817,7 +10832,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (views == null) {
return;
}
- if (!isFocusable() || !isEnabled()) {
+ if (!canTakeFocus()) {
return;
}
if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE
@@ -11031,8 +11046,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* descendants.
*
* A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
- * false), or if it is focusable and it is not focusable in touch mode
- * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
+ * false), or if it can't be focused due to other conditions (not focusable in touch mode
+ * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not
+ * enabled, or has no size).
*
* See also {@link #focusSearch(int)}, which is what you call to say that you
* have focus, and you want your parent to look for the next one.
@@ -11139,9 +11155,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
// need to be focusable
- if ((mViewFlags & FOCUSABLE) != FOCUSABLE
- || (mViewFlags & VISIBILITY_MASK) != VISIBLE
- || (mViewFlags & ENABLED_MASK) != ENABLED) {
+ if (!canTakeFocus()) {
return false;
}
@@ -11156,10 +11170,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return false;
}
+ if (!isLayoutValid()) {
+ mPrivateFlags |= PFLAG_WANTS_FOCUS;
+ }
+
handleFocusGainInternal(direction, previouslyFocusedRect);
return true;
}
+ void clearParentsWantFocus() {
+ if (mParent instanceof View) {
+ ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
+ ((View) mParent).clearParentsWantFocus();
+ }
+ }
+
/**
* Call this to try to give focus to a specific view or to one of its descendants. This is a
* special variant of {@link #requestFocus() } that will allow views that are not focusable in
@@ -13531,6 +13556,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mAttachInfo.mUnbufferedDispatchRequested = true;
}
+ private boolean canTakeFocus() {
+ return ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
+ && ((mViewFlags & FOCUSABLE) == FOCUSABLE)
+ && ((mViewFlags & ENABLED_MASK) == ENABLED)
+ && (sCanFocusZeroSized || !isLayoutValid() || (mBottom > mTop) && (mRight > mLeft));
+ }
+
/**
* Set flags controlling behavior of this view.
*
@@ -13550,6 +13582,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return;
}
int privateFlags = mPrivateFlags;
+ boolean shouldNotifyFocusableAvailable = false;
// If focusable is auto, update the FOCUSABLE bit.
int focusableChangedByAuto = 0;
@@ -13588,7 +13621,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|| focusableChangedByAuto == 0
|| viewRootImpl == null
|| viewRootImpl.mThread == Thread.currentThread()) {
- mParent.focusableViewAvailable(this);
+ shouldNotifyFocusableAvailable = true;
}
}
}
@@ -13611,10 +13644,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// about in case nothing has focus. even if this specific view
// isn't focusable, it may contain something that is, so let
// the root view try to give this focus if nothing else does.
- if ((mParent != null) && ((mViewFlags & ENABLED_MASK) == ENABLED)
- && (mBottom > mTop) && (mRight > mLeft)) {
- mParent.focusableViewAvailable(this);
- }
+ shouldNotifyFocusableAvailable = true;
}
}
@@ -13623,17 +13653,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// a view becoming enabled should notify the parent as long as the view is also
// visible and the parent wasn't already notified by becoming visible during this
// setFlags invocation.
- if ((mViewFlags & VISIBILITY_MASK) == VISIBLE
- && ((changed & VISIBILITY_MASK) == 0)) {
- if ((mParent != null) && (mViewFlags & ENABLED_MASK) == ENABLED) {
- mParent.focusableViewAvailable(this);
- }
- }
+ shouldNotifyFocusableAvailable = true;
} else {
if (hasFocus()) clearFocus();
}
}
+ if (shouldNotifyFocusableAvailable) {
+ if (mParent != null && canTakeFocus()) {
+ mParent.focusableViewAvailable(this);
+ }
+ }
+
/* Check if the GONE bit has changed */
if ((changed & GONE) != 0) {
needGlobalAttributesUpdate(false);
@@ -20160,15 +20191,58 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ final boolean wasLayoutValid = isLayoutValid();
+
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
+ if (!wasLayoutValid && isFocused()) {
+ mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
+ if (canTakeFocus()) {
+ // We have a robust focus, so parents should no longer be wanting focus.
+ clearParentsWantFocus();
+ } else if (!getViewRootImpl().isInLayout()) {
+ // This is a weird case. Most-likely the user, rather than ViewRootImpl, called
+ // layout. In this case, there's no guarantee that parent layouts will be evaluated
+ // and thus the safest action is to clear focus here.
+ clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
+ clearParentsWantFocus();
+ } else if (!hasParentWantsFocus()) {
+ // original requestFocus was likely on this view directly, so just clear focus
+ clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
+ }
+ // otherwise, we let parents handle re-assigning focus during their layout passes.
+ } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) {
+ mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
+ View focused = findFocus();
+ if (focused != null) {
+ // Try to restore focus as close as possible to our starting focus.
+ if (!restoreDefaultFocus() && !hasParentWantsFocus()) {
+ // Give up and clear focus once we've reached the top-most parent which wants
+ // focus.
+ focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
+ }
+ }
+ }
+
if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
notifyEnterOrExitForAutoFillIfNeeded(true);
}
}
+ private boolean hasParentWantsFocus() {
+ ViewParent parent = mParent;
+ while (parent instanceof ViewGroup) {
+ ViewGroup pv = (ViewGroup) parent;
+ if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) {
+ return true;
+ }
+ parent = pv.mParent;
+ }
+ return false;
+ }
+
/**
* Called from layout when this view should
* assign a size and position to each of its children.
@@ -20275,6 +20349,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mOverlay.getOverlayView().setRight(newWidth);
mOverlay.getOverlayView().setBottom(newHeight);
}
+ // If this isn't laid out yet, focus assignment will be handled during the "deferment/
+ // backtracking" of requestFocus during layout, so don't touch focus here.
+ if (!sCanFocusZeroSized && isLayoutValid()) {
+ if (newWidth <= 0 || newHeight <= 0) {
+ if (hasFocus()) {
+ clearFocus();
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).clearFocusedInCluster();
+ }
+ }
+ clearAccessibilityFocus();
+ } else if (oldWidth <= 0 || oldHeight <= 0) {
+ if (mParent != null && canTakeFocus()) {
+ mParent.focusableViewAvailable(this);
+ }
+ }
+ }
rebuildOutline();
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 122df934111d..e21abf0a637b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3215,22 +3215,31 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
int descendantFocusability = getDescendantFocusability();
+ boolean result;
switch (descendantFocusability) {
case FOCUS_BLOCK_DESCENDANTS:
- return super.requestFocus(direction, previouslyFocusedRect);
+ result = super.requestFocus(direction, previouslyFocusedRect);
+ break;
case FOCUS_BEFORE_DESCENDANTS: {
final boolean took = super.requestFocus(direction, previouslyFocusedRect);
- return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
+ result = took ? took : onRequestFocusInDescendants(direction,
+ previouslyFocusedRect);
+ break;
}
case FOCUS_AFTER_DESCENDANTS: {
final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
- return took ? took : super.requestFocus(direction, previouslyFocusedRect);
+ result = took ? took : super.requestFocus(direction, previouslyFocusedRect);
+ break;
}
default:
throw new IllegalStateException("descendant focusability must be "
+ "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
+ "but is " + descendantFocusability);
}
+ if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {
+ mPrivateFlags |= PFLAG_WANTS_FOCUS;
+ }
+ return result;
}
/**
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index d665dde39afe..1d94abeb51a2 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -26,6 +26,8 @@ import android.util.Pair;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import com.android.internal.util.Preconditions;
+
import java.util.List;
/**
@@ -204,6 +206,16 @@ public abstract class ViewStructure {
public abstract void setTextLines(int[] charOffsets, int[] baselines);
/**
+ * Sets the identifier used to set the text associated with this view.
+ *
+ * <p>Should only be set when the node is used for autofill purposes - it will be ignored
+ * when used for Assist.
+ */
+ public void setTextIdEntry(@NonNull String entryName) {
+ Preconditions.checkNotNull(entryName);
+ }
+
+ /**
* Set optional hint text associated with this view; this is for example the text that is
* shown by an EditText when it is empty to indicate to the user the kind of text to input.
*/
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index cbe012af0b21..a65aba152c83 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -17,6 +17,32 @@
package android.view;
import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT;
+import static android.view.WindowLayoutParamsProto.ALPHA;
+import static android.view.WindowLayoutParamsProto.BUTTON_BRIGHTNESS;
+import static android.view.WindowLayoutParamsProto.COLOR_MODE;
+import static android.view.WindowLayoutParamsProto.FLAGS;
+import static android.view.WindowLayoutParamsProto.FLAGS_EXTRA;
+import static android.view.WindowLayoutParamsProto.FORMAT;
+import static android.view.WindowLayoutParamsProto.GRAVITY;
+import static android.view.WindowLayoutParamsProto.HAS_SYSTEM_UI_LISTENERS;
+import static android.view.WindowLayoutParamsProto.HEIGHT;
+import static android.view.WindowLayoutParamsProto.HORIZONTAL_MARGIN;
+import static android.view.WindowLayoutParamsProto.INPUT_FEATURE_FLAGS;
+import static android.view.WindowLayoutParamsProto.NEEDS_MENU_KEY;
+import static android.view.WindowLayoutParamsProto.PREFERRED_REFRESH_RATE;
+import static android.view.WindowLayoutParamsProto.PRIVATE_FLAGS;
+import static android.view.WindowLayoutParamsProto.ROTATION_ANIMATION;
+import static android.view.WindowLayoutParamsProto.SCREEN_BRIGHTNESS;
+import static android.view.WindowLayoutParamsProto.SOFT_INPUT_MODE;
+import static android.view.WindowLayoutParamsProto.SUBTREE_SYSTEM_UI_VISIBILITY_FLAGS;
+import static android.view.WindowLayoutParamsProto.SYSTEM_UI_VISIBILITY_FLAGS;
+import static android.view.WindowLayoutParamsProto.TYPE;
+import static android.view.WindowLayoutParamsProto.USER_ACTIVITY_TIMEOUT;
+import static android.view.WindowLayoutParamsProto.VERTICAL_MARGIN;
+import static android.view.WindowLayoutParamsProto.WIDTH;
+import static android.view.WindowLayoutParamsProto.WINDOW_ANIMATIONS;
+import static android.view.WindowLayoutParamsProto.X;
+import static android.view.WindowLayoutParamsProto.Y;
import android.Manifest.permission;
import android.annotation.IntDef;
@@ -2722,7 +2748,33 @@ public interface WindowManager extends ViewManager {
*/
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- proto.write(WindowLayoutParamsProto.TYPE, type);
+ proto.write(TYPE, type);
+ proto.write(X, x);
+ proto.write(Y, y);
+ proto.write(WIDTH, width);
+ proto.write(HEIGHT, height);
+ proto.write(HORIZONTAL_MARGIN, horizontalMargin);
+ proto.write(VERTICAL_MARGIN, verticalMargin);
+ proto.write(GRAVITY, gravity);
+ proto.write(SOFT_INPUT_MODE, softInputMode);
+ proto.write(FORMAT, format);
+ proto.write(WINDOW_ANIMATIONS, windowAnimations);
+ proto.write(ALPHA, alpha);
+ proto.write(SCREEN_BRIGHTNESS, screenBrightness);
+ proto.write(BUTTON_BRIGHTNESS, buttonBrightness);
+ proto.write(ROTATION_ANIMATION, rotationAnimation);
+ proto.write(PREFERRED_REFRESH_RATE, preferredRefreshRate);
+ proto.write(WindowLayoutParamsProto.PREFERRED_DISPLAY_MODE_ID, preferredDisplayModeId);
+ proto.write(HAS_SYSTEM_UI_LISTENERS, hasSystemUiListeners);
+ proto.write(INPUT_FEATURE_FLAGS, inputFeatures);
+ proto.write(USER_ACTIVITY_TIMEOUT, userActivityTimeout);
+ proto.write(NEEDS_MENU_KEY, needsMenuKey);
+ proto.write(COLOR_MODE, mColorMode);
+ proto.write(FLAGS, flags);
+ proto.write(FLAGS_EXTRA, flags2);
+ proto.write(PRIVATE_FLAGS, privateFlags);
+ proto.write(SYSTEM_UI_VISIBILITY_FLAGS, systemUiVisibility);
+ proto.write(SUBTREE_SYSTEM_UI_VISIBILITY_FLAGS, subtreeSystemUiVisibility);
proto.end(token);
}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 1d19a9f5969a..6c2d34988896 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -38,19 +38,14 @@ import java.util.List;
* <p>
* An accessibility event is fired by an individual view which populates the event with
* data for its state and requests from its parent to send the event to interested
- * parties. The parent can optionally add an {@link AccessibilityRecord} for itself before
- * dispatching a similar request to its parent. A parent can also choose not to respect the
- * request for sending an event. The accessibility event is sent by the topmost view in the
- * view tree. Therefore, an {@link android.accessibilityservice.AccessibilityService} can
- * explore all records in an accessibility event to obtain more information about the
- * context in which the event was fired.
+ * parties. The parent can optionally modify or even block the event based on its broader
+ * understanding of the user interface's context.
* </p>
* <p>
- * The main purpose of an accessibility event is to expose enough information for an
- * {@link android.accessibilityservice.AccessibilityService} to provide meaningful feedback
- * to the user. Sometimes however, an accessibility service may need more contextual
- * information then the one in the event pay-load. In such cases the service can obtain
- * the event source which is an {@link AccessibilityNodeInfo} (snapshot of a View state)
+ * The main purpose of an accessibility event is to communicate changes in the UI to an
+ * {@link android.accessibilityservice.AccessibilityService}. The service may then inspect,
+ * if needed the user interface by examining the View hierarchy, as represented by a tree of
+ * {@link AccessibilityNodeInfo}s (snapshot of a View state)
* which can be used for exploring the window content. Note that the privilege for accessing
* an event's source, thus the window content, has to be explicitly requested. For more
* details refer to {@link android.accessibilityservice.AccessibilityService}. If an
@@ -85,21 +80,6 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #isPassword()} - Whether the source is password.</li>
- * <li>{@link #isChecked()} - Whether the source is checked.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getScrollX()} - The offset of the source left edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getScrollY()} - The offset of the source top edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getItemCount()} - The total items of the source
- * (for descendants of AdapterView).</li>
* </ul>
* </p>
* <p>
@@ -113,21 +93,6 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #isPassword()} - Whether the source is password.</li>
- * <li>{@link #isChecked()} - Whether the source is checked.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getScrollX()} - The offset of the source left edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getScrollY()} - The offset of the source top edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getItemCount()} - The total items of the source
- * (for descendants of AdapterView).</li>
* </ul>
* </p>
* <p>
@@ -141,23 +106,6 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #isPassword()} - Whether the source is password.</li>
- * <li>{@link #isChecked()} - Whether the source is checked.</li>
- * <li>{@link #getItemCount()} - The number of selectable items of the source.</li>
- * <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getScrollX()} - The offset of the source left edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getScrollY()} - The offset of the source top edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getItemCount()} - The total items of the source
- * (for descendants of AdapterView).</li>
* </ul>
* </p>
* <p>
@@ -171,23 +119,6 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #isPassword()} - Whether the source is password.</li>
- * <li>{@link #isChecked()} - Whether the source is checked.</li>
- * <li>{@link #getItemCount()} - The number of focusable items on the screen.</li>
- * <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getScrollX()} - The offset of the source left edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getScrollY()} - The offset of the source top edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getItemCount()} - The total items of the source
- * (for descendants of AdapterView).</li>
* </ul>
* </p>
* <p>
@@ -201,15 +132,11 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #isPassword()} - Whether the source is password.</li>
- * <li>{@link #isChecked()} - Whether the source is checked.</li>
+ * <li>{@link #getText()} - The new text of the source.</li>
+ * <li>{@link #getBeforeText()} - The text of the source before the change.</li>
* <li>{@link #getFromIndex()} - The text change start index.</li>
* <li>{@link #getAddedCount()} - The number of added characters.</li>
* <li>{@link #getRemovedCount()} - The number of removed characters.</li>
- * <li>{@link #getBeforeText()} - The text of the source before the change.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
* </p>
* <p>
@@ -223,13 +150,6 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
- * <li>{@link #isPassword()} - Whether the source is password.</li>
- * <li>{@link #getFromIndex()} - The selection start index.</li>
- * <li>{@link #getToIndex()} - The selection end index.</li>
- * <li>{@link #getItemCount()} - The length of the source text.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
* </p>
* <b>View text traversed at movement granularity</b> - represents the event of traversing the
@@ -251,23 +171,11 @@ import java.util.List;
* <li>{@link #getToIndex()} - The end of the text that was skipped over in this movement.
* This is the ending point when moving forward through the text, but not when moving
* back.</li>
- * <li>{@link #isPassword()} - Whether the source is password.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getMovementGranularity()} - Sets the granularity at which a view's text
- * was traversed.</li>
* <li>{@link #getAction()} - Gets traversal action which specifies the direction.</li>
* </ul>
* </p>
* <p>
- * <b>View scrolled</b> - represents the event of scrolling a view. If
- * the source is a descendant of {@link android.widget.AdapterView} the
- * scroll is reported in terms of visible items - the first visible item,
- * the last visible item, and the total items - because the the source
- * is unaware of its pixel size since its adapter is responsible for
- * creating views. In all other cases the scroll is reported as the current
- * scroll on the X and Y axis respectively plus the height of the source in
- * pixels.</br>
+ * <b>View scrolled</b> - represents the event of scrolling a view. </br>
* <em>Type:</em> {@link #TYPE_VIEW_SCROLLED}</br>
* <em>Properties:</em></br>
* <ul>
@@ -276,29 +184,9 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getScrollX()} - The offset of the source left edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getScrollY()} - The offset of the source top edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getItemCount()} - The total items of the source
- * (for descendants of AdapterView).</li>
+ * <li>{@link #getScrollDeltaX()} - The difference in the horizontal position.</li>
+ * <li>{@link #getScrollDeltaY()} - The difference in the vertical position.</li>
* </ul>
- * <em>Note:</em> This event type is not dispatched to descendants though
- * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
- * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
- * source {@link android.view.View} and the sub-tree rooted at it will not receive
- * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
- * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
- * text content to such events is by setting the
- * {@link android.R.styleable#View_contentDescription contentDescription} of the source
- * view.</br>
* </p>
* <p>
* <b>TRANSITION TYPES</b></br>
@@ -316,7 +204,6 @@ import java.util.List;
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
* <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* </ul>
* </p>
* <p>
@@ -325,10 +212,6 @@ import java.util.List;
* a view size, etc.</br>
* </p>
* <p>
- * <strong>Note:</strong> This event is fired only for the window source of the
- * last accessibility event different from {@link #TYPE_NOTIFICATION_STATE_CHANGED}
- * and its purpose is to notify clients that the content of the user interaction
- * window has changed.</br>
* <em>Type:</em> {@link #TYPE_WINDOW_CONTENT_CHANGED}</br>
* <em>Properties:</em></br>
* <ul>
@@ -339,32 +222,26 @@ import java.util.List;
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
* </ul>
- * <em>Note:</em> This event type is not dispatched to descendants though
- * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
- * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
- * source {@link android.view.View} and the sub-tree rooted at it will not receive
- * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
- * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
- * text content to such events is by setting the
- * {@link android.R.styleable#View_contentDescription contentDescription} of the source
- * view.</br>
* </p>
* <p>
- * <b>Windows changed</b> - represents the event of changes in the windows shown on
+ * <b>Windows changed</b> - represents a change in the windows shown on
* the screen such as a window appeared, a window disappeared, a window size changed,
- * a window layer changed, etc.</br>
+ * a window layer changed, etc. These events should only come from the system, which is responsible
+ * for managing windows. The list of windows is available from
+ * {@link android.accessibilityservice.AccessibilityService#getWindows()}.
+ * For regions of the user interface that are presented as windows but are
+ * controlled by an app's process, use {@link #TYPE_WINDOW_STATE_CHANGED}.</br>
* <em>Type:</em> {@link #TYPE_WINDOWS_CHANGED}</br>
* <em>Properties:</em></br>
* <ul>
* <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getEventTime()} - The event time.</li>
+ * <li>{@link #getWindowChanges()}</li> - The specific change to the source window
* </ul>
* <em>Note:</em> You can retrieve the {@link AccessibilityWindowInfo} for the window
- * source of the event via {@link AccessibilityEvent#getSource()} to get the source
- * node on which then call {@link AccessibilityNodeInfo#getWindow()
- * AccessibilityNodeInfo.getWindow()} to get the window. Also all windows on the screen can
- * be retrieved by a call to {@link android.accessibilityservice.AccessibilityService#getWindows()
- * android.accessibilityservice.AccessibilityService.getWindows()}.
+ * source of the event by looking through the list returned by
+ * {@link android.accessibilityservice.AccessibilityService#getWindows()} for the window whose ID
+ * matches {@link #getWindowId()}.
* </p>
* <p>
* <b>NOTIFICATION TYPES</b></br>
@@ -402,19 +279,6 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getScrollX()} - The offset of the source left edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getScrollY()} - The offset of the source top edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getItemCount()} - The total items of the source
- * (for descendants of AdapterView).</li>
* </ul>
* </p>
* <b>View hover exit</b> - represents the event of stopping to hover
@@ -428,19 +292,6 @@ import java.util.List;
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
- * <li>{@link #getContentDescription()} - The content description of the source.</li>
- * <li>{@link #getScrollX()} - The offset of the source left edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getScrollY()} - The offset of the source top edge in pixels
- * (without descendants of AdapterView).</li>
- * <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
- * inclusive (for descendants of AdapterView).</li>
- * <li>{@link #getItemCount()} - The total items of the source
- * (for descendants of AdapterView).</li>
* </ul>
* </p>
* <p>
@@ -513,10 +364,10 @@ import java.util.List;
* <b>MISCELLANEOUS TYPES</b></br>
* </p>
* <p>
- * <b>Announcement</b> - represents the event of an application making an
- * announcement. Usually this announcement is related to some sort of a context
- * change for which none of the events representing UI transitions is a good fit.
- * For example, announcing a new page in a book.</br>
+ * <b>Announcement</b> - represents the event of an application requesting a screen reader to make
+ * an announcement. Because the event carries no semantic meaning, this event is appropriate only
+ * in exceptional situations where additional screen reader output is needed but other types of
+ * accessibility services do not need to be aware of the change.</br>
* <em>Type:</em> {@link #TYPE_ANNOUNCEMENT}</br>
* <em>Properties:</em></br>
* <ul>
@@ -526,7 +377,6 @@ import java.util.List;
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
* <li>{@link #getText()} - The text of the announcement.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* </ul>
* </p>
*
@@ -674,7 +524,8 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
public static final int TYPE_TOUCH_INTERACTION_END = 0x00200000;
/**
- * Represents the event change in the windows shown on the screen.
+ * Represents the event change in the system windows shown on the screen. This event type should
+ * only be dispatched by the system.
*/
public static final int TYPE_WINDOWS_CHANGED = 0x00400000;
@@ -696,7 +547,8 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
/**
* Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
- * A node in the subtree rooted at the source node was added or removed.
+ * One or more content changes occurred in the the subtree rooted at the source node,
+ * or the subtree's structure changed when a node was added or removed.
*/
public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0x00000001;
@@ -712,6 +564,99 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
*/
public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004;
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window was added.
+ */
+ public static final int WINDOWS_CHANGE_ADDED = 0x00000001;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * A window was removed.
+ */
+ public static final int WINDOWS_CHANGE_REMOVED = 0x00000002;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's title changed.
+ */
+ public static final int WINDOWS_CHANGE_TITLE = 0x00000004;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's bounds changed.
+ */
+ public static final int WINDOWS_CHANGE_BOUNDS = 0x00000008;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's layer changed.
+ */
+ public static final int WINDOWS_CHANGE_LAYER = 0x00000010;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's {@link AccessibilityWindowInfo#isActive()} changed.
+ */
+ public static final int WINDOWS_CHANGE_ACTIVE = 0x00000020;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's {@link AccessibilityWindowInfo#isFocused()} changed.
+ */
+ public static final int WINDOWS_CHANGE_FOCUSED = 0x00000040;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's {@link AccessibilityWindowInfo#isAccessibilityFocused()} changed.
+ */
+ public static final int WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED = 0x00000080;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's parent changed.
+ */
+ public static final int WINDOWS_CHANGE_PARENT = 0x00000100;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window's children changed.
+ */
+ public static final int WINDOWS_CHANGE_CHILDREN = 0x00000200;
+
+ /**
+ * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
+ * The window either entered or exited picture-in-picture mode.
+ */
+ public static final int WINDOWS_CHANGE_PIP = 0x00000400;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "WINDOWS_CHANGE_" }, value = {
+ WINDOWS_CHANGE_ADDED,
+ WINDOWS_CHANGE_REMOVED,
+ WINDOWS_CHANGE_TITLE,
+ WINDOWS_CHANGE_BOUNDS,
+ WINDOWS_CHANGE_LAYER,
+ WINDOWS_CHANGE_ACTIVE,
+ WINDOWS_CHANGE_FOCUSED,
+ WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED,
+ WINDOWS_CHANGE_PARENT,
+ WINDOWS_CHANGE_CHILDREN,
+ WINDOWS_CHANGE_PIP
+ })
+ public @interface WindowsChangeTypes {}
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "CONTENT_CHANGE_TYPE_" },
+ value = {
+ CONTENT_CHANGE_TYPE_UNDEFINED,
+ CONTENT_CHANGE_TYPE_SUBTREE,
+ CONTENT_CHANGE_TYPE_TEXT,
+ CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION
+ })
+ public @interface ContentChangeTypes {}
/** @hide */
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
@@ -782,6 +727,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
int mMovementGranularity;
int mAction;
int mContentChangeTypes;
+ int mWindowChangeTypes;
private ArrayList<AccessibilityRecord> mRecords;
@@ -802,6 +748,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
mMovementGranularity = event.mMovementGranularity;
mAction = event.mAction;
mContentChangeTypes = event.mContentChangeTypes;
+ mWindowChangeTypes = event.mWindowChangeTypes;
mEventTime = event.mEventTime;
mPackageName = event.mPackageName;
}
@@ -885,6 +832,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
* </ul>
*/
+ @ContentChangeTypes
public int getContentChangeTypes() {
return mContentChangeTypes;
}
@@ -913,12 +861,49 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* @throws IllegalStateException If called from an AccessibilityService.
* @see #getContentChangeTypes()
*/
- public void setContentChangeTypes(int changeTypes) {
+ public void setContentChangeTypes(@ContentChangeTypes int changeTypes) {
enforceNotSealed();
mContentChangeTypes = changeTypes;
}
/**
+ * Get the bit mask of change types signaled by a {@link #TYPE_WINDOWS_CHANGED} event. A
+ * single event may represent multiple change types.
+ *
+ * @return The bit mask of change types.
+ */
+ @WindowsChangeTypes
+ public int getWindowChanges() {
+ return mWindowChangeTypes;
+ }
+
+ /** @hide */
+ public void setWindowChanges(@WindowsChangeTypes int changes) {
+ mWindowChangeTypes = changes;
+ }
+
+ private static String windowChangeTypesToString(@WindowsChangeTypes int types) {
+ return BitUtils.flagsToString(types, AccessibilityEvent::singleWindowChangeTypeToString);
+ }
+
+ private static String singleWindowChangeTypeToString(int type) {
+ switch (type) {
+ case WINDOWS_CHANGE_ADDED: return "WINDOWS_CHANGE_ADDED";
+ case WINDOWS_CHANGE_REMOVED: return "WINDOWS_CHANGE_REMOVED";
+ case WINDOWS_CHANGE_TITLE: return "WINDOWS_CHANGE_TITLE";
+ case WINDOWS_CHANGE_BOUNDS: return "WINDOWS_CHANGE_BOUNDS";
+ case WINDOWS_CHANGE_LAYER: return "WINDOWS_CHANGE_LAYER";
+ case WINDOWS_CHANGE_ACTIVE: return "WINDOWS_CHANGE_ACTIVE";
+ case WINDOWS_CHANGE_FOCUSED: return "WINDOWS_CHANGE_FOCUSED";
+ case WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED:
+ return "WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED";
+ case WINDOWS_CHANGE_PARENT: return "WINDOWS_CHANGE_PARENT";
+ case WINDOWS_CHANGE_CHILDREN: return "WINDOWS_CHANGE_CHILDREN";
+ default: return Integer.toHexString(type);
+ }
+ }
+
+ /**
* Sets the event type.
*
* @param eventType The event type.
@@ -1025,6 +1010,26 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
}
/**
+ * Convenience method to obtain a {@link #TYPE_WINDOWS_CHANGED} event for a specific window and
+ * change set.
+ *
+ * @param windowId The ID of the window that changed
+ * @param windowChangeTypes The changes to populate
+ * @return An instance of a TYPE_WINDOWS_CHANGED, populated with the requested fields and with
+ * importantForAccessibility set to {@code true}.
+ *
+ * @hide
+ */
+ public static AccessibilityEvent obtainWindowsChangedEvent(
+ int windowId, int windowChangeTypes) {
+ final AccessibilityEvent event = AccessibilityEvent.obtain(TYPE_WINDOWS_CHANGED);
+ event.setWindowId(windowId);
+ event.setWindowChanges(windowChangeTypes);
+ event.setImportantForAccessibility(true);
+ return event;
+ }
+
+ /**
* Returns a cached instance if such is available or a new one is
* instantiated with its type property set.
*
@@ -1099,6 +1104,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
mMovementGranularity = 0;
mAction = 0;
mContentChangeTypes = 0;
+ mWindowChangeTypes = 0;
mPackageName = null;
mEventTime = 0;
if (mRecords != null) {
@@ -1120,6 +1126,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
mMovementGranularity = parcel.readInt();
mAction = parcel.readInt();
mContentChangeTypes = parcel.readInt();
+ mWindowChangeTypes = parcel.readInt();
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mEventTime = parcel.readLong();
mConnectionId = parcel.readInt();
@@ -1178,6 +1185,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
parcel.writeInt(mMovementGranularity);
parcel.writeInt(mAction);
parcel.writeInt(mContentChangeTypes);
+ parcel.writeInt(mWindowChangeTypes);
TextUtils.writeToParcel(mPackageName, parcel, 0);
parcel.writeLong(mEventTime);
parcel.writeInt(mConnectionId);
@@ -1238,11 +1246,13 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
builder.append("; PackageName: ").append(mPackageName);
builder.append("; MovementGranularity: ").append(mMovementGranularity);
builder.append("; Action: ").append(mAction);
+ builder.append("; ContentChangeTypes: ").append(
+ contentChangeTypesToString(mContentChangeTypes));
+ builder.append("; WindowChangeTypes: ").append(
+ windowChangeTypesToString(mWindowChangeTypes));
builder.append(super.toString());
if (DEBUG) {
builder.append("\n");
- builder.append("; ContentChangeTypes: ").append(
- contentChangeTypesToString(mContentChangeTypes));
builder.append("; sourceWindowId: ").append(mSourceWindowId);
builder.append("; mSourceNodeId: ").append(mSourceNodeId);
for (int i = 0; i < getRecordCount(); i++) {
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ef1a3f3bcc8f..c1c9174c0f9f 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -21,9 +21,12 @@ import android.annotation.TestApi;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
+import android.view.accessibility.AccessibilityEvent.WindowsChangeTypes;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -575,7 +578,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
StringBuilder builder = new StringBuilder();
builder.append("AccessibilityWindowInfo[");
builder.append("title=").append(mTitle);
- builder.append("id=").append(mId);
+ builder.append(", id=").append(mId);
builder.append(", type=").append(typeToString(mType));
builder.append(", layer=").append(mLayer);
builder.append(", bounds=").append(mBoundsInScreen);
@@ -713,6 +716,60 @@ public final class AccessibilityWindowInfo implements Parcelable {
return false;
}
+ /**
+ * Reports how this window differs from a possibly different state of the same window. The
+ * argument must have the same id and type as neither of those properties may change.
+ *
+ * @param other The new state.
+ * @return A set of flags showing how the window has changes, or 0 if the two states are the
+ * same.
+ *
+ * @hide
+ */
+ @WindowsChangeTypes
+ public int differenceFrom(AccessibilityWindowInfo other) {
+ if (other.mId != mId) {
+ throw new IllegalArgumentException("Not same window.");
+ }
+ if (other.mType != mType) {
+ throw new IllegalArgumentException("Not same type.");
+ }
+ int changes = 0;
+ if (!TextUtils.equals(mTitle, other.mTitle)) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_TITLE;
+ }
+
+ if (!mBoundsInScreen.equals(other.mBoundsInScreen)) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_BOUNDS;
+ }
+ if (mLayer != other.mLayer) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_LAYER;
+ }
+ if (getBooleanProperty(BOOLEAN_PROPERTY_ACTIVE)
+ != other.getBooleanProperty(BOOLEAN_PROPERTY_ACTIVE)) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_ACTIVE;
+ }
+ if (getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED)
+ != other.getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED)) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_FOCUSED;
+ }
+ if (getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED)
+ != other.getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED)) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
+ }
+ if (getBooleanProperty(BOOLEAN_PROPERTY_PICTURE_IN_PICTURE)
+ != other.getBooleanProperty(BOOLEAN_PROPERTY_PICTURE_IN_PICTURE)) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_PIP;
+ }
+ if (mParentId != other.mParentId) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_PARENT;
+ }
+ if (!Objects.equals(mChildIds, other.mChildIds)) {
+ changes |= AccessibilityEvent.WINDOWS_CHANGE_CHILDREN;
+ }
+ return changes;
+ }
+
public static final Parcelable.Creator<AccessibilityWindowInfo> CREATOR =
new Creator<AccessibilityWindowInfo>() {
@Override
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 269745455517..78b41c6f4c7b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -53,6 +53,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -1027,7 +1028,9 @@ public final class AutofillManager {
* Gets the user data used for
* <a href="AutofillService.html#FieldClassification">field classification</a>.
*
- * <p><b>Note:</b> This method should only be called by an app providing an autofill service.
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+ * and it's ignored if the caller currently doesn't have an enabled autofill service for
+ * the user.
*
* @return value previously set by {@link #setUserData(UserData)} or {@code null} if it was
* reset or if the caller currently does not have an enabled autofill service for the user.
@@ -1079,6 +1082,49 @@ public final class AutofillManager {
}
/**
+ * Gets the name of the default algorithm used for
+ * <a href="AutofillService.html#FieldClassification">field classification</a>.
+ *
+ * <p>The default algorithm is used when the algorithm on {@link UserData} is invalid or not
+ * set.
+ *
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+ * and it's ignored if the caller currently doesn't have an enabled autofill service for
+ * the user.
+ */
+ @Nullable
+ public String getDefaultFieldClassificationAlgorithm() {
+ try {
+ return mService.getDefaultFieldClassificationAlgorithm();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
+ /**
+ * Gets the name of all algorithms currently available for
+ * <a href="AutofillService.html#FieldClassification">field classification</a>.
+ *
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+ * and it's ignored if the caller currently doesn't have an enabled autofill service for
+ * the user.
+ *
+ * @return list of all algorithms currently available, or an empty list if the caller currently
+ * does not have an enabled autofill service for the user.
+ */
+ @NonNull
+ public List<String> getAvailableFieldClassificationAlgorithms() {
+ try {
+ final List<String> names = mService.getAvailableFieldClassificationAlgorithms();
+ return names != null ? names : Collections.emptyList();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
+ /**
* Returns {@code true} if autofill is supported by the current device and
* is supported for this user.
*
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 38bb311986e8..1afa35e80a26 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -58,4 +58,6 @@ interface IAutoFillManager {
void setUserData(in UserData userData);
boolean isFieldClassificationEnabled();
ComponentName getAutofillServiceComponentName();
+ List<String> getAvailableFieldClassificationAlgorithms();
+ String getDefaultFieldClassificationAlgorithm();
}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 56c3e4a5ee77..336c20cdcdc0 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -105,6 +105,11 @@ public class EditText extends TextView {
@Override
public Editable getText() {
+ CharSequence text = super.getText();
+ if (text instanceof Editable) {
+ return (Editable) super.getText();
+ }
+ super.setText(text, BufferType.EDITABLE);
return (Editable) super.getText();
}
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index bd48f4554c5d..26dfcc2d668a 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -125,7 +125,7 @@ public final class Magnifier {
mView.getWidth() - mBitmap.getWidth()));
final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
- if (startX != mPrevStartCoordsInSurface.x || startY != mPrevStartCoordsInSurface.y) {
+ if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) {
performPixelCopy(startX, startY);
mPrevPosInView.x = xPosInView;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1e17f34af2a6..1618d620738f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -44,6 +44,7 @@ import android.content.UndoManager;
import android.content.res.ColorStateList;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.ResourceId;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -785,9 +786,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// mAutoSizeStepGranularityInPx.
private boolean mHasPresetAutoSizeValues = false;
- // Indicates whether the text was set from resources or dynamically, so it can be used to
+ // Indicates whether the text was set statically or dynamically, so it can be used to
// sanitize autofill requests.
- private boolean mTextFromResource = false;
+ private boolean mSetFromXmlOrResourceId = false;
+ // Resource id used to set the text - used for autofill purposes.
+ private @StringRes int mTextId = ResourceId.ID_NULL;
/**
* Kick-start the font cache for the zygote process (to pay the cost of
@@ -926,7 +929,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int n = a.getIndexCount();
- boolean fromResourceId = false;
+ // Must set id in a temporary variable because it will be reset by setText()
+ boolean setFromXml = false;
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
@@ -1068,7 +1072,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextView_text:
- fromResourceId = true;
+ setFromXml = true;
+ mTextId = a.getResourceId(attr, ResourceId.ID_NULL);
text = a.getText(attr);
break;
@@ -1460,8 +1465,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
setText(text, bufferType);
- if (fromResourceId) {
- mTextFromResource = true;
+ if (setFromXml) {
+ mSetFromXmlOrResourceId = true;
}
if (hint != null) setHint(hint);
@@ -5278,7 +5283,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
- mTextFromResource = false;
+ mSetFromXmlOrResourceId = false;
if (text == null) {
text = "";
}
@@ -5516,7 +5521,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@android.view.RemotableViewMethod
public final void setText(@StringRes int resid) {
setText(getContext().getResources().getText(resid));
- mTextFromResource = true;
+ mSetFromXmlOrResourceId = true;
+ mTextId = resid;
}
/**
@@ -5543,7 +5549,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public final void setText(@StringRes int resid, BufferType type) {
setText(getContext().getResources().getText(resid), type);
- mTextFromResource = true;
+ mSetFromXmlOrResourceId = true;
+ mTextId = resid;
}
/**
@@ -10234,7 +10241,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final boolean isPassword = hasPasswordTransformationMethod()
|| isPasswordInputType(getInputType());
if (forAutofill) {
- structure.setDataIsSensitive(!mTextFromResource);
+ structure.setDataIsSensitive(!mSetFromXmlOrResourceId);
+ if (mTextId != ResourceId.ID_NULL) {
+ structure.setTextIdEntry(getResources().getResourceEntryName(mTextId));
+ }
}
if (!isPassword || forAutofill) {
diff --git a/core/java/com/android/internal/net/INetworkWatchlistManager.aidl b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
index 7e88369055b8..ee01a23af686 100644
--- a/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
+++ b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
@@ -22,5 +22,6 @@ import android.os.SharedMemory;
interface INetworkWatchlistManager {
boolean startWatchlistLogging();
boolean stopWatchlistLogging();
+ void reloadWatchlist();
void reportWatchlistIfNecessary();
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 72f07b7c8f20..1739bed7112f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -506,8 +506,8 @@ public class BatteryStatsImpl extends BatteryStats {
final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
long mHistoryBaseTime;
- boolean mHaveBatteryLevel = false;
- boolean mRecordingHistory = false;
+ protected boolean mHaveBatteryLevel = false;
+ protected boolean mRecordingHistory = false;
int mNumHistoryItems;
final Parcel mHistoryBuffer = Parcel.obtain();
@@ -652,6 +652,14 @@ public class BatteryStatsImpl extends BatteryStats {
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
/**
+ * The WiFi Overall wakelock timer
+ * This timer tracks the actual aggregate time for which MC wakelocks are enabled
+ * since addition of per UID timers would not result in an accurate value due to overlapp of
+ * per uid wakelock timers
+ */
+ StopwatchTimer mWifiMulticastWakelockTimer;
+
+ /**
* The WiFi controller activity (time in tx, rx, idle, and power consumed) for the device.
*/
ControllerActivityCounterImpl mWifiActivity;
@@ -3975,30 +3983,85 @@ public class BatteryStatsImpl extends BatteryStats {
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_JOB_FINISH, name, uid);
}
- public void noteAlarmStartLocked(String name, int uid) {
+ public void noteAlarmStartLocked(String name, WorkSource workSource, int uid) {
+ noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_START, name, workSource, uid);
+ }
+
+ public void noteAlarmFinishLocked(String name, WorkSource workSource, int uid) {
+ noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_FINISH, name, workSource, uid);
+ }
+
+ private void noteAlarmStartOrFinishLocked(int historyItem, String name, WorkSource workSource,
+ int uid) {
if (!mRecordAllHistory) {
return;
}
- uid = mapUid(uid);
+
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
- if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_START, name, uid, 0)) {
- return;
+
+ if (workSource != null) {
+ for (int i = 0; i < workSource.size(); ++i) {
+ uid = mapUid(workSource.get(i));
+ if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
+ addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+ }
+ }
+
+ List<WorkChain> workChains = workSource.getWorkChains();
+ if (workChains != null) {
+ for (int i = 0; i < workChains.size(); ++i) {
+ uid = mapUid(workChains.get(i).getAttributionUid());
+ if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
+ addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+ }
+ }
+ }
+ } else {
+ uid = mapUid(uid);
+
+ if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
+ addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+ }
}
- addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_START, name, uid);
}
- public void noteAlarmFinishLocked(String name, int uid) {
- if (!mRecordAllHistory) {
+ public void noteWakupAlarmLocked(String packageName, int uid, WorkSource workSource,
+ String tag) {
+ if (!isOnBattery()) {
return;
}
- uid = mapUid(uid);
- final long elapsedRealtime = mClocks.elapsedRealtime();
- final long uptime = mClocks.uptimeMillis();
- if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_FINISH, name, uid, 0)) {
- return;
+
+ if (workSource != null) {
+ for (int i = 0; i < workSource.size(); ++i) {
+ uid = workSource.get(i);
+ final String workSourceName = workSource.getName(i);
+
+ BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid,
+ workSourceName != null ? workSourceName : packageName);
+ pkg.noteWakeupAlarmLocked(tag);
+
+ StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+ }
+
+ ArrayList<WorkChain> workChains = workSource.getWorkChains();
+ if (workChains != null) {
+ for (int i = 0; i < workChains.size(); ++i) {
+ final WorkChain wc = workChains.get(i);
+ uid = wc.getAttributionUid();
+
+ BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
+ pkg.noteWakeupAlarmLocked(tag);
+
+ // TODO(statsd): Log the full attribution chain here once it's available
+ StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+ }
+ }
+ } else {
+ BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
+ pkg.noteWakeupAlarmLocked(tag);
+ StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
}
- addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_FINISH, name, uid);
}
private void requestWakelockCpuUpdate() {
@@ -5534,6 +5597,12 @@ public class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+
+ // Start Wifi Multicast overall timer
+ if (!mWifiMulticastWakelockTimer.isRunningLocked()) {
+ if (DEBUG_HISTORY) Slog.v(TAG, "WiFi Multicast Overall Timer Started");
+ mWifiMulticastWakelockTimer.startRunningLocked(elapsedRealtime);
+ }
}
mWifiMulticastNesting++;
getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
@@ -5549,6 +5618,12 @@ public class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+
+ // Stop Wifi Multicast overall timer
+ if (mWifiMulticastWakelockTimer.isRunningLocked()) {
+ if (DEBUG_HISTORY) Slog.v(TAG, "Multicast Overall Timer Stopped");
+ mWifiMulticastWakelockTimer.stopRunningLocked(elapsedRealtime);
+ }
}
getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
}
@@ -5835,6 +5910,16 @@ public class BatteryStatsImpl extends BatteryStats {
return (int)mMobileRadioActiveUnknownCount.getCountLocked(which);
}
+ @Override public long getWifiMulticastWakelockTime(
+ long elapsedRealtimeUs, int which) {
+ return mWifiMulticastWakelockTimer.getTotalTimeLocked(
+ elapsedRealtimeUs, which);
+ }
+
+ @Override public int getWifiMulticastWakelockCount(int which) {
+ return mWifiMulticastWakelockTimer.getCountLocked(which);
+ }
+
@Override public long getWifiOnTime(long elapsedRealtimeUs, int which) {
return mWifiOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@@ -9435,6 +9520,8 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
+ mWifiMulticastWakelockTimer = new StopwatchTimer(mClocks, null,
+ WIFI_AGGREGATE_MULTICAST_ENABLED, null, mOnBatteryTimeBase);
mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -10136,6 +10223,7 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].reset(false);
}
+ mWifiMulticastWakelockTimer.reset(false);
mWifiActivity.reset(false);
mBluetoothActivity.reset(false);
mModemActivity.reset(false);
@@ -12582,6 +12670,7 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in);
mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in);
+ mWifiMulticastWakelockTimer.readSummaryFromParcelLocked(in);
mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
mWifiOnTimer.readSummaryFromParcelLocked(in);
@@ -13022,6 +13111,7 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
+ mWifiMulticastWakelockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -13485,6 +13575,8 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mWifiMulticastWakelockTimer = new StopwatchTimer(mClocks, null, -4, null,
+ mOnBatteryTimeBase, in);
mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
@@ -13691,6 +13783,7 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime.writeToParcel(out);
mMobileRadioActiveUnknownTime.writeToParcel(out);
mMobileRadioActiveUnknownCount.writeToParcel(out);
+ mWifiMulticastWakelockTimer.writeToParcel(out, uSecRealtime);
mWifiOnTimer.writeToParcel(out, uSecRealtime);
mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -13877,6 +13970,8 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveTimer.logState(pr, " ");
pr.println("*** Mobile network active adjusted timer:");
mMobileRadioActiveAdjustedTime.logState(pr, " ");
+ pr.println("*** Wifi Multicast WakeLock Timer:");
+ mWifiMulticastWakelockTimer.logState(pr, " ");
pr.println("*** mWifiRadioPowerState=" + mWifiRadioPowerState);
pr.println("*** Wifi timer:");
mWifiOnTimer.logState(pr, " ");
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index 82affe2f86b1..ab8be33599fa 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -30,9 +30,6 @@ import com.android.internal.R;
* orientation when it can't fit its child views horizontally.
*/
public class ButtonBarLayout extends LinearLayout {
- /** Minimum screen height required for button stacking. */
- private static final int ALLOW_STACKING_MIN_HEIGHT_DP = 320;
-
/** Amount of the second button to "peek" above the fold when stacked. */
private static final int PEEK_BUTTON_DP = 16;
@@ -46,12 +43,8 @@ public class ButtonBarLayout extends LinearLayout {
public ButtonBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
- final boolean allowStackingDefault =
- context.getResources().getConfiguration().screenHeightDp
- >= ALLOW_STACKING_MIN_HEIGHT_DP;
final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ButtonBarLayout);
- mAllowStacking = ta.getBoolean(R.styleable.ButtonBarLayout_allowStacking,
- allowStackingDefault);
+ mAllowStacking = ta.getBoolean(R.styleable.ButtonBarLayout_allowStacking, true);
ta.recycle();
}
diff --git a/core/proto/android/graphics/pixelformat.proto b/core/proto/android/graphics/pixelformat.proto
new file mode 100644
index 000000000000..4e42c926a95f
--- /dev/null
+++ b/core/proto/android/graphics/pixelformat.proto
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.graphics;
+option java_multiple_files = true;
+
+message PixelFormatProto {
+ enum Format {
+ UNKNOWN = 0;
+ TRANSLUCENT = -3;
+ TRANSPARENT = -2;
+ OPAQUE = -1;
+ RGBA_8888 = 1;
+ RGBX_8888 = 2;
+ RGB_888 = 3;
+ RGB_565 = 4;
+ RGBA_F16 = 0x16;
+ RGBA_1010102 = 0x2B;
+ }
+}
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 0fa428e9c114..9999b4e26a68 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -537,7 +537,24 @@ message UidProto {
// Screen-off CPU time in milliseconds.
optional int64 screen_off_duration_ms = 3;
}
+ // CPU times accumulated across all process states.
repeated ByFrequency by_frequency = 3;
+
+ enum ProcessState {
+ TOP = 0;
+ FOREGROUND_SERVICE = 1;
+ FOREGROUND = 2;
+ BACKGROUND = 3;
+ TOP_SLEEPING = 4;
+ HEAVY_WEIGHT = 5;
+ CACHED = 6;
+ }
+ // CPU times at different process states.
+ message ByProcessState {
+ optional ProcessState process_state = 1;
+ repeated ByFrequency by_frequency = 2;
+ }
+ repeated ByProcessState by_process_state = 4;
}
optional Cpu cpu = 7;
@@ -655,7 +672,7 @@ message UidProto {
// In approximate order or priority (top being what the framework considers
// most important and is thus least likely to kill when resources are
// needed:
- // top > foreground service > top sleeping > foreground > background > cache
+ // top > foreground service > foreground > background > top sleeping > heavy weight > cache
enum State {
// Time this uid has any processes in the top state (or above such as
// persistent).
@@ -663,20 +680,26 @@ message UidProto {
// Time this uid has any process with a started out bound foreground
// service, but none in the "top" state.
PROCESS_STATE_FOREGROUND_SERVICE = 1;
- // Time this uid has any process that is top while the device is sleeping,
- // but none in the "foreground service" or better state. Sleeping is
- // mostly screen off, but also includes the time when the screen is on but
- // the device has not yet been unlocked.
- PROCESS_STATE_TOP_SLEEPING = 2;
// Time this uid has any process in an active foreground state, but none
// in the "top sleeping" or better state.
- PROCESS_STATE_FOREGROUND = 3;
+ PROCESS_STATE_FOREGROUND = 2;
// Time this uid has any process in an active background state, but none
// in the "foreground" or better state.
- PROCESS_STATE_BACKGROUND = 4;
+ PROCESS_STATE_BACKGROUND = 3;
+ // Time this uid has any process that is top while the device is sleeping,
+ // but not active for any other reason. We consider is a kind of cached
+ // process for execution restrictions. Sleeping is mostly screen off, but
+ // also includes the time when the screen is on but the device has not yet
+ // been unlocked.
+ PROCESS_STATE_TOP_SLEEPING = 4;
+ // Time this uid has any process that is in the background but it has an
+ // activity marked as "can't save state". This is essentially a cached
+ // process, though the system will try much harder than normal to avoid
+ // killing it.
+ PROCESS_STATE_HEAVY_WEIGHT = 5;
// Time this uid has any processes that are sitting around cached, not in
// one of the other active states.
- PROCESS_STATE_CACHED = 5;
+ PROCESS_STATE_CACHED = 6;
}
optional State state = 1;
optional int64 duration_ms = 2;
diff --git a/core/proto/android/os/batterytype.proto b/core/proto/android/os/batterytype.proto
new file mode 100644
index 000000000000..75d0dd3504e3
--- /dev/null
+++ b/core/proto/android/os/batterytype.proto
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message BatteryTypeProto {
+ optional string type = 1;
+}
diff --git a/core/proto/android/os/cpuinfo.proto b/core/proto/android/os/cpuinfo.proto
index 522ff24c1e60..cd151e253e7a 100644
--- a/core/proto/android/os/cpuinfo.proto
+++ b/core/proto/android/os/cpuinfo.proto
@@ -81,7 +81,9 @@ message CpuInfo {
optional string virt = 8; // virtual memory size, i.e. 14.0G, 13.5M
optional string res = 9; // Resident size, i.e. 0, 3.1G
- // How Android memory manager will treat the task
+ // How Android memory manager will treat the task.
+ // TODO: use PsDumpProto.Process.Policy instead once we extern variables
+ // and are able to include the same .h file in two files.
enum Policy {
POLICY_UNKNOWN = 0;
POLICY_fg = 1; // foreground, the name is lower case for parsing the value
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ac8f26d94ca2..a6db31f67b33 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -18,12 +18,14 @@ syntax = "proto2";
option java_multiple_files = true;
option java_outer_classname = "IncidentProtoMetadata";
+import "frameworks/base/core/proto/android/os/batterytype.proto";
import "frameworks/base/core/proto/android/os/cpufreq.proto";
import "frameworks/base/core/proto/android/os/cpuinfo.proto";
import "frameworks/base/core/proto/android/os/incidentheader.proto";
import "frameworks/base/core/proto/android/os/kernelwake.proto";
import "frameworks/base/core/proto/android/os/pagetypeinfo.proto";
import "frameworks/base/core/proto/android/os/procrank.proto";
+import "frameworks/base/core/proto/android/os/ps.proto";
import "frameworks/base/core/proto/android/os/system_properties.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
@@ -65,7 +67,7 @@ message IncidentProto {
// Device information
optional SystemPropertiesProto system_properties = 1000 [
(section).type = SECTION_COMMAND,
- (section).args = "/system/bin/getprop"
+ (section).args = "getprop"
];
// Linux services
@@ -86,7 +88,7 @@ message IncidentProto {
optional CpuInfo cpu_info = 2003 [
(section).type = SECTION_COMMAND,
- (section).args = "/system/bin/top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"
+ (section).args = "top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"
];
optional CpuFreq cpu_freq = 2004 [
@@ -94,6 +96,16 @@ message IncidentProto {
(section).args = "/sys/devices/system/cpu/cpufreq/all_time_in_state"
];
+ optional PsDumpProto processes_and_threads = 2005 [
+ (section).type = SECTION_COMMAND,
+ (section).args = "ps -A -T -Z -O pri,nice,rtprio,sched,pcy,time"
+ ];
+
+ optional BatteryTypeProto battery_type = 2006 [
+ (section).type = SECTION_FILE,
+ (section).args = "/sys/class/power_supply/bms/battery_type"
+ ];
+
// System Services
optional com.android.server.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
(section).type = SECTION_DUMPSYS,
diff --git a/core/proto/android/os/ps.proto b/core/proto/android/os/ps.proto
new file mode 100644
index 000000000000..88c6609a92b6
--- /dev/null
+++ b/core/proto/android/os/ps.proto
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message PsDumpProto {
+ message Process {
+ // Security label, most commonly used for SELinux context data.
+ optional string label = 1;
+ optional string user = 2;
+ // Process ID number.
+ optional int32 pid = 3;
+ // The unique number representing a dispatchable entity (alias lwp,
+ // spid). This value may also appear as: a process ID (pid); a process
+ // group ID (pgrp); a session ID for the session leader (sid); a thread
+ // group ID for the thread group leader (tgid); and a tty process group
+ // ID for the process group leader (tpgid).
+ optional int32 tid = 4;
+ // Parent process ID.
+ optional int32 ppid = 5;
+ // Virtual set size (memory size) of the process, in KiB.
+ optional int32 vsz = 6;
+ // Resident set size. How many physical pages are associated with the
+ // process; real memory usage, in KiB.
+ optional int32 rss = 7;
+ // Name of the kernel function in which the process is sleeping, a "-"
+ // if the process is running, or a "*" if the process is multi-threaded
+ // and ps is not displaying threads.
+ optional string wchan = 8;
+ // Memory address of the process.
+ optional string addr = 9;
+
+ enum ProcessStateCode {
+ STATE_UNKNOWN = 0;
+ // Uninterruptible sleep (usually IO).
+ STATE_D = 1;
+ // Running or runnable (on run queue).
+ STATE_R = 2;
+ // Interruptible sleep (waiting for an event to complete).
+ STATE_S = 3;
+ // Stopped by job control signal.
+ STATE_T = 4;
+ // Stopped by debugger during the tracing.
+ STATE_TRACING = 5;
+ // Dead (should never be seen).
+ STATE_X = 6;
+ // Defunct ("zombie") process. Terminated but not reaped by its
+ // parent.
+ STATE_Z = 7;
+ }
+ // Minimal state display
+ optional ProcessStateCode s = 10;
+ // Priority of the process. Higher number means lower priority.
+ optional int32 pri = 11;
+ // Nice value. This ranges from 19 (nicest) to -20 (not nice to others).
+ optional sint32 ni = 12;
+ // Realtime priority.
+ optional string rtprio = 13; // Number or -
+
+ enum SchedulingPolicy {
+ option allow_alias = true;
+
+ // Regular names conflict with macros defined in
+ // bionic/libc/kernel/uapi/linux/sched.h.
+ SCH_OTHER = 0;
+ SCH_NORMAL = 0;
+
+ SCH_FIFO = 1;
+ SCH_RR = 2;
+ SCH_BATCH = 3;
+ SCH_ISO = 4;
+ SCH_IDLE = 5;
+ }
+ // Scheduling policy of the process.
+ optional SchedulingPolicy sch = 14;
+
+ // How Android memory manager will treat the task
+ enum Policy {
+ POLICY_UNKNOWN = 0;
+ // Foreground.
+ POLICY_FG = 1;
+ // Background.
+ POLICY_BG = 2;
+ POLICY_TA = 3; // TODO: figure out what this value is
+ }
+ optional Policy pcy = 15;
+ // Total CPU time, "[DD-]HH:MM:SS" format.
+ optional string time = 16;
+ // Command with all its arguments as a string.
+ optional string cmd = 17;
+ }
+ repeated Process processes = 1;
+}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index ef7b6b0019f3..12aca787745e 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -18,6 +18,7 @@ syntax = "proto2";
import "frameworks/base/core/proto/android/content/configuration.proto";
import "frameworks/base/core/proto/android/graphics/rect.proto";
+import "frameworks/base/core/proto/android/view/displaycutout.proto";
import "frameworks/base/core/proto/android/view/displayinfo.proto";
import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
@@ -172,6 +173,27 @@ message WindowStateProto {
repeated WindowStateProto child_windows = 15;
optional .android.graphics.RectProto surface_position = 16;
optional .android.graphics.RectProto shown_position = 17;
+ optional int32 requested_width = 18;
+ optional int32 requested_height = 19;
+ optional int32 view_visibility = 20;
+ optional int32 system_ui_visibility = 21;
+ optional bool has_surface = 22;
+ optional bool is_ready_for_display = 23;
+ optional .android.graphics.RectProto display_frame = 24;
+ optional .android.graphics.RectProto overscan_frame = 25;
+ optional .android.graphics.RectProto visible_frame = 26;
+ optional .android.graphics.RectProto decor_frame = 27;
+ optional .android.graphics.RectProto outset_frame = 28;
+ optional .android.graphics.RectProto overscan_insets = 29;
+ optional .android.graphics.RectProto visible_insets = 30;
+ optional .android.graphics.RectProto stable_insets = 31;
+ optional .android.graphics.RectProto outsets = 32;
+ optional .android.view.DisplayCutoutProto cutout = 33;
+ optional bool remove_on_exit = 34;
+ optional bool destroying = 35;
+ optional bool removed = 36;
+ optional bool is_on_screen = 37;
+ optional bool is_visible = 38;
}
message IdentifierProto {
@@ -184,6 +206,15 @@ message IdentifierProto {
message WindowStateAnimatorProto {
optional .android.graphics.RectProto last_clip_rect = 1;
optional WindowSurfaceControllerProto surface = 2;
+ enum DrawState {
+ NO_SURFACE = 0;
+ DRAW_PENDING = 1;
+ COMMIT_DRAW_PENDING = 2;
+ READY_TO_SHOW = 3;
+ HAS_DRAWN = 4;
+ }
+ optional DrawState draw_state = 3;
+ optional .android.graphics.RectProto system_decor_rect = 4;
}
/* represents WindowSurfaceController */
diff --git a/core/proto/android/view/display.proto b/core/proto/android/view/display.proto
index 210c6d103faa..cac083075ec3 100644
--- a/core/proto/android/view/display.proto
+++ b/core/proto/android/view/display.proto
@@ -38,4 +38,16 @@ message DisplayProto {
// The display is on and optimized for VR mode.
DISPLAY_STATE_VR = 5;
}
+ enum ColorMode {
+ COLOR_MODE_INVALID = -1;
+ COLOR_MODE_BT601_625 = 1;
+ COLOR_MODE_BT601_625_UNADJUSTED = 2;
+ COLOR_MODE_BT601_525 = 3;
+ COLOR_MODE_BT601_525_UNADJUSTED = 4;
+ COLOR_MODE_BT709 = 5;
+ COLOR_MODE_DCI_P3 = 6;
+ COLOR_MODE_SRGB = 7;
+ COLOR_MODE_ADOBE_RGB = 8;
+ COLOR_MODE_DISPLAY_P3 = 9;
+ }
}
diff --git a/core/proto/android/view/displaycutout.proto b/core/proto/android/view/displaycutout.proto
new file mode 100644
index 000000000000..ff13fab35bf2
--- /dev/null
+++ b/core/proto/android/view/displaycutout.proto
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/graphics/rect.proto";
+
+package android.view;
+option java_multiple_files = true;
+
+message DisplayCutoutProto {
+ optional .android.graphics.RectProto insets = 1;
+ optional .android.graphics.RectProto bounds = 2;
+}
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 78212125c16d..b81cd1f50f91 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -15,11 +15,51 @@
*/
syntax = "proto2";
-package android.view;
+import "frameworks/base/core/proto/android/graphics/pixelformat.proto";
+import "frameworks/base/core/proto/android/view/display.proto";
+
+package android.view;
option java_multiple_files = true;
/* represents WindowManager.LayoutParams */
message WindowLayoutParamsProto {
optional int32 type = 1;
+ optional int32 x = 2;
+ optional int32 y = 3;
+ optional int32 width = 4;
+ optional int32 height = 5;
+ optional float horizontal_margin = 6;
+ optional float vertical_margin = 7;
+ optional int32 gravity = 8;
+ optional int32 soft_input_mode = 9;
+ optional .android.graphics.PixelFormatProto.Format format = 10;
+ optional int32 window_animations = 11;
+ optional float alpha = 12;
+ optional float screen_brightness = 13;
+ optional float button_brightness = 14;
+ enum RotationAnimation {
+ ROTATION_ANIMATION_UNSPECIFIED = -1;
+ ROTATION_ANIMATION_CROSSFADE = 1;
+ ROTATION_ANIMATION_JUMPCUT = 2;
+ ROTATION_ANIMATION_SEAMLESS = 3;
+ }
+ optional RotationAnimation rotation_animation = 15;
+ optional float preferred_refresh_rate = 16;
+ optional int32 preferred_display_mode_id = 17;
+ optional bool has_system_ui_listeners = 18;
+ optional uint32 input_feature_flags = 19;
+ optional int64 user_activity_timeout = 20;
+ enum NeedsMenuState {
+ NEEDS_MENU_UNSET = 0;
+ NEEDS_MENU_SET_TRUE = 1;
+ NEEDS_MENU_SET_FALSE = 2;
+ }
+ optional NeedsMenuState needs_menu_key = 22;
+ optional .android.view.DisplayProto.ColorMode color_mode = 23;
+ optional uint32 flags = 24;
+ optional uint64 flags_extra = 25;
+ optional uint32 private_flags = 26;
+ optional uint32 system_ui_visibility_flags = 27;
+ optional uint32 subtree_system_ui_visibility_flags = 28;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 272e3c73bf89..52bfcdebf436 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3870,6 +3870,14 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.updates.NetworkWatchlistInstallReceiver"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_NETWORK_WATCHLIST" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
<receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 64febf1f7ee4..1b3d6ce36247 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8699,8 +8699,11 @@
common values are 400 for regular weight and 700 for bold weight. If unspecified, the value
in the font's header tables will be used. -->
<attr name="fontWeight" format="integer" />
- <!-- The index of the font in the tcc font file. If the font file referenced is not in the
- tcc format, this attribute needs not be specified. -->
+ <!-- The index of the font in the ttc (TrueType Collection) font file. If the font file
+ referenced is not in the ttc format, this attribute needs not be specified.
+ {@see android.graphics.Typeface#Builder.setTtcIndex(int)}.
+ The default value is 0. More details about the TrueType Collection font format can be found
+ here: https://en.wikipedia.org/wiki/TrueType#TrueType_Collection. -->
<attr name="ttcIndex" format="integer" />
<!-- The variation settings to be applied to the font. The string should be in the following
format: "'tag1' value1, 'tag2' value2, ...". If the default variation settings should be
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index e2498df71e45..70485111d208 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -31,10 +31,8 @@
<color name="tertiary_device_default_settings">@color/tertiary_material_settings</color>
<color name="quaternary_device_default_settings">@color/quaternary_material_settings</color>
- <color name="accent_device_default_700">@color/accent_material_700</color>
<color name="accent_device_default_light">@color/accent_material_light</color>
<color name="accent_device_default_dark">@color/accent_material_dark</color>
- <color name="accent_device_default_50">@color/accent_material_50</color>
<color name="background_device_default_dark">@color/background_material_dark</color>
<color name="background_device_default_light">@color/background_material_light</color>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 8c37d4b053a1..04131009b141 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -39,10 +39,8 @@
<color name="tertiary_material_settings">@color/material_blue_grey_700</color>
<color name="quaternary_material_settings">@color/material_blue_grey_200</color>
- <color name="accent_material_700">@color/material_deep_teal_700</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>
<color name="accent_material_dark">@color/material_deep_teal_200</color>
- <color name="accent_material_50">@color/material_deep_teal_50</color>
<color name="button_material_dark">#ff5a595b</color>
<color name="button_material_light">#ffd6d7d7</color>
@@ -95,12 +93,10 @@
<color name="material_grey_100">#fff5f5f5</color>
<color name="material_grey_50">#fffafafa</color>
- <color name="material_deep_teal_50">#ffe0f2f1</color>
<color name="material_deep_teal_100">#ffb2dfdb</color>
<color name="material_deep_teal_200">#ff80cbc4</color>
<color name="material_deep_teal_300">#ff4db6ac</color>
<color name="material_deep_teal_500">#ff009688</color>
- <color name="material_deep_teal_700">#ff00796b</color>
<color name="material_blue_grey_200">#ffb0bec5</color>
<color name="material_blue_grey_700">#ff455a64</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dc791cf68b6b..fd05bb442247 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1302,8 +1302,8 @@
If this is defined then:
- config_autoBrightnessLcdBacklightValues should not be defined
- - config_screenBrightnessMinimumNits must be defined
- - config_screenBrightnessMaximumNits must be defined
+ - config_screenBrightnessNits must be defined
+ - config_screenBrightnessBacklight must be defined
This array should have size one greater than the size of the config_autoBrightnessLevels
array. The brightness values must be non-negative and non-decreasing. This must be
@@ -1347,28 +1347,23 @@
<item>200</item>
</integer-array>
- <!-- The minimum brightness of the display in nits. On OLED displays this should be measured
- with an all white image while the display is fully on and the backlight is set to
- config_screenBrightnessSettingMinimum or config_screenBrightnessSettingDark, whichever
- is darker.
-
- If this and config_screenBrightnessMinimumNits are set, then the display's brightness
- range is assumed to be linear between
- (config_screenBrightnessSettingMinimum, config_screenBrightnessMinimumNits) and
- (config_screenBrightnessSettingMaximum, config_screenBrightnessMaximumNits). -->
- <item name="config_screenBrightnessMinimumNits" format="float" type="dimen">-1.0</item>
-
- <!-- The maximum brightness of the display in nits. On OLED displays this should be measured
- with an all white image while the display is fully on and the "backlight" is set to
- config_screenBrightnessSettingMaximum. Note that this value should *not* reflect the
- maximum brightness value for any high brightness modes but only the maximum brightness
- value obtainable in a sustainable manner.
-
- If this and config_screenBrightnessMinimumNits are set to something non-negative, then the
- display's brightness range is assumed to be linear between
- (config_screenBrightnessSettingMinimum, config_screenBrightnessMaximumNits) and
- (config_screenBrightnessSettingMaximum, config_screenBrightnessMaximumNits). -->
- <item name="config_screenBrightnessMaximumNits" format="float" type="dimen">-1.0</item>
+ <!-- An array describing the screen's backlight values corresponding to the brightness
+ values in the config_screenBrightnessNits array.
+
+ This array should be equal in size to config_screenBrightnessBacklight. -->
+ <integer-array name="config_screenBrightnessBacklight">
+ </integer-array>
+
+ <!-- An array of floats describing the screen brightness in nits corresponding to the backlight
+ values in the config_screenBrightnessBacklight array. On OLED displays these values
+ should be measured with an all white image while the display is in the fully on state.
+ Note that this value should *not* reflect the maximum brightness value for any high
+ brightness modes but only the maximum brightness value obtainable in a sustainable manner.
+
+ This array should be equal in size to config_screenBrightnessBacklight -->
+ <array name="config_screenBrightnessNits">
+ </array>
+
<!-- Array of ambient lux threshold values. This is used for determining hysteresis constraint
values by calculating the index to use for lookup and then setting the constraint value
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5783435e13bd..c54f79983f02 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -20,13 +20,23 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Suffix added to a number to signify size in bytes. -->
<string name="byteShort">B</string>
+ <!-- Suffix added to a number to signify size in kilobytes (1000 bytes).
+ If you retain the Latin script for the localization, please use the lowercase
+ 'k', as it signifies 1000 bytes as opposed to 1024 bytes. -->
+ <string name="kilobyteShort">kB</string>
+ <!-- Suffix added to a number to signify size in megabytes. -->
+ <string name="megabyteShort">MB</string>
+ <!-- Suffix added to a number to signify size in gigabytes. -->
+ <string name="gigabyteShort">GB</string>
+ <!-- Suffix added to a number to signify size in terabytes. -->
+ <string name="terabyteShort">TB</string>
<!-- Suffix added to a number to signify size in petabytes. -->
<string name="petabyteShort">PB</string>
- <!-- Format string used to add a suffix like "B" or "PB" to a number
- to display a size in bytes or petabytes.
- Some languages may want to remove the space between the placeholders
- or replace it with a non-breaking space. -->
- <string name="fileSizeSuffix"><xliff:g id="number" example="123">%1$s</xliff:g> <xliff:g id="unit" example="B">%2$s</xliff:g></string>
+ <!-- Format string used to add a suffix like "kB" or "MB" to a number
+ to display a size in kilobytes, megabytes, or other size units.
+ Some languages (like French) will want to add a space between
+ the placeholders. -->
+ <string name="fileSizeSuffix"><xliff:g id="number" example="123">%1$s</xliff:g> <xliff:g id="unit" example="MB">%2$s</xliff:g></string>
<!-- Used in Contacts for a field that has no label and in Note Pad
for a note with no name. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8e391d3c0122..4343ba01702b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -705,6 +705,7 @@
<java-symbol type="string" name="fileSizeSuffix" />
<java-symbol type="string" name="force_close" />
<java-symbol type="string" name="gadget_host_error_inflating" />
+ <java-symbol type="string" name="gigabyteShort" />
<java-symbol type="string" name="gpsNotifMessage" />
<java-symbol type="string" name="gpsNotifTicker" />
<java-symbol type="string" name="gpsNotifTitle" />
@@ -760,6 +761,7 @@
<java-symbol type="string" name="keyboardview_keycode_enter" />
<java-symbol type="string" name="keyboardview_keycode_mode_change" />
<java-symbol type="string" name="keyboardview_keycode_shift" />
+ <java-symbol type="string" name="kilobyteShort" />
<java-symbol type="string" name="last_month" />
<java-symbol type="string" name="launchBrowserDefault" />
<java-symbol type="string" name="lock_to_app_toast" />
@@ -779,6 +781,7 @@
<java-symbol type="string" name="lockscreen_emergency_call" />
<java-symbol type="string" name="lockscreen_return_to_call" />
<java-symbol type="string" name="low_memory" />
+ <java-symbol type="string" name="megabyteShort" />
<java-symbol type="string" name="midnight" />
<java-symbol type="string" name="mismatchPin" />
<java-symbol type="string" name="mmiComplete" />
@@ -981,6 +984,7 @@
<java-symbol type="string" name="sync_really_delete" />
<java-symbol type="string" name="sync_too_many_deletes_desc" />
<java-symbol type="string" name="sync_undo_deletes" />
+ <java-symbol type="string" name="terabyteShort" />
<java-symbol type="string" name="text_copied" />
<java-symbol type="string" name="time_of_day" />
<java-symbol type="string" name="time_picker_decrement_hour_button" />
@@ -3193,7 +3197,7 @@
<java-symbol type="string" name="global_action_logout" />
<java-symbol type="drawable" name="ic_logout" />
- <java-symbol type="dimen" name="config_screenBrightnessMinimumNits" />
- <java-symbol type="dimen" name="config_screenBrightnessMaximumNits" />
<java-symbol type="array" name="config_autoBrightnessDisplayValuesNits" />
+ <java-symbol type="array" name="config_screenBrightnessBacklight" />
+ <java-symbol type="array" name="config_screenBrightnessNits" />
</resources>
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index aefc47e95512..c19a343957c0 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -42,7 +42,8 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
-@Presubmit
+// TODO: b/70616950
+//@Presubmit
public class ObjectPoolTests {
// 1. Check if two obtained objects from pool are not the same.
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index eef9866d7691..fc8650086cd8 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -525,7 +525,8 @@ public class SettingsBackupTest {
Settings.Secure.VOICE_INTERACTION_SERVICE,
Settings.Secure.VOICE_RECOGNITION_SERVICE,
Settings.Secure.INSTANT_APPS_ENABLED,
- Settings.Secure.BACKUP_MANAGER_CONSTANTS);
+ Settings.Secure.BACKUP_MANAGER_CONSTANTS,
+ Settings.Secure.KEYGUARD_SLICE_URI);
@Test
public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 9c544f47717c..04d2dad4e224 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -17,7 +17,6 @@
package android.text.format;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import android.content.Context;
import android.content.res.Configuration;
@@ -210,24 +209,4 @@ public class FormatterTest {
Locale.setDefault(locale);
}
-
- /**
- * Verifies that Formatter doesn't "leak" the locally defined petabyte unit into ICU via the
- * {@link MeasureUnit} registry. This test can fail for two reasons:
- * 1. we regressed and started leaking again. In this case the code needs to be fixed.
- * 2. ICU started supporting petabyte as a unit, in which case change one needs to revert this
- * change (I494fb59a3b3742f35cbdf6b8705817f404a2c6b0), remove Formatter.PETABYTE and replace any
- * usages of that field with just MeasureUnit.PETABYTE.
- */
- // http://b/65632959
- @Test
- public void doesNotLeakPetabyte() {
- // Ensure that the Formatter class is loaded when we call .getAvailable().
- Formatter.formatFileSize(mContext, Long.MAX_VALUE);
- Set<MeasureUnit> digitalUnits = MeasureUnit.getAvailable("digital");
- for (MeasureUnit unit : digitalUnits) {
- // This assert can fail if we don't leak PETABYTE, but ICU has added it, see #2 above.
- assertNotEquals("petabyte", unit.getSubtype());
- }
- }
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
new file mode 100644
index 000000000000..fed197ed2505
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 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.
+ */
+
+package android.view.accessibility;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * AccessibilityEvent is public, so CTS covers it pretty well. Verifying hidden methods here.
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityEventTest {
+ @Test
+ public void testImportantForAccessibiity_getSetWorkAcrossParceling() {
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setImportantForAccessibility(true);
+ assertTrue(copyEventViaParcel(event).isImportantForAccessibility());
+
+ event.setImportantForAccessibility(false);
+ assertFalse(copyEventViaParcel(event).isImportantForAccessibility());
+ }
+
+ @Test
+ public void testSouceNodeId_getSetWorkAcrossParceling() {
+ final long sourceNodeId = 0x1234567890ABCDEFL;
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setSourceNodeId(sourceNodeId);
+ assertEquals(sourceNodeId, copyEventViaParcel(event).getSourceNodeId());
+ }
+
+ @Test
+ public void testWindowChanges_getSetWorkAcrossParceling() {
+ final int windowChanges = AccessibilityEvent.WINDOWS_CHANGE_TITLE
+ | AccessibilityEvent.WINDOWS_CHANGE_ACTIVE
+ | AccessibilityEvent.WINDOWS_CHANGE_FOCUSED;
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setWindowChanges(windowChanges);
+ assertEquals(windowChanges, copyEventViaParcel(event).getWindowChanges());
+ }
+
+ private AccessibilityEvent copyEventViaParcel(AccessibilityEvent event) {
+ Parcel parcel = Parcel.obtain();
+ event.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return AccessibilityEvent.CREATOR.createFromParcel(parcel);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 0afec34da958..a55563afbcc9 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -15,16 +15,19 @@
*/
package com.android.internal.os;
+import static android.os.BatteryStats.STATS_CURRENT;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
import android.app.ActivityManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
+import android.os.BatteryStats.HistoryItem;
import android.os.WorkSource;
import android.support.test.filters.SmallTest;
import android.view.Display;
+import com.android.internal.os.BatteryStatsImpl.Uid;
import junit.framework.TestCase;
import java.util.ArrayList;
@@ -44,11 +47,14 @@ import java.util.Map;
* Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsNoteTest -w \
* com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
*/
-public class BatteryStatsNoteTest extends TestCase{
+public class BatteryStatsNoteTest extends TestCase {
+
private static final int UID = 10500;
private static final WorkSource WS = new WorkSource(UID);
- /** Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked. */
+ /**
+ * Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked.
+ */
@SmallTest
public void testNoteBluetoothScanResultLocked() throws Exception {
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks());
@@ -75,7 +81,9 @@ public class BatteryStatsNoteTest extends TestCase{
.getCountLocked(STATS_SINCE_CHARGED));
}
- /** Test BatteryStatsImpl.Uid.noteStartWakeLocked. */
+ /**
+ * Test BatteryStatsImpl.Uid.noteStartWakeLocked.
+ */
@SmallTest
public void testNoteStartWakeLocked() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
@@ -86,7 +94,8 @@ public class BatteryStatsNoteTest extends TestCase{
bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
- bi.getUidStatsLocked(UID).noteStartWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime);
+ bi.getUidStatsLocked(UID)
+ .noteStartWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime);
clocks.realtime = clocks.uptime = 100;
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
@@ -94,7 +103,8 @@ public class BatteryStatsNoteTest extends TestCase{
clocks.realtime = clocks.uptime = 220;
bi.getUidStatsLocked(UID).noteStopWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime);
- BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID).getAggregatedPartialWakelockTimer();
+ BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID)
+ .getAggregatedPartialWakelockTimer();
long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
assertEquals(220_000, actualTime);
@@ -102,7 +112,9 @@ public class BatteryStatsNoteTest extends TestCase{
}
- /** Test BatteryStatsImpl.noteUidProcessStateLocked. */
+ /**
+ * Test BatteryStatsImpl.noteUidProcessStateLocked.
+ */
@SmallTest
public void testNoteUidProcessStateLocked() throws Exception {
final MockClocks clocks = new MockClocks();
@@ -145,7 +157,6 @@ public class BatteryStatsNoteTest extends TestCase{
expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TOP);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
-
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE,
elapsedTimeUs, STATS_SINCE_CHARGED);
expectedRunTimeMs = stateRuntimeMap.get(
@@ -153,19 +164,16 @@ public class BatteryStatsNoteTest extends TestCase{
+ stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
-
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING,
elapsedTimeUs, STATS_SINCE_CHARGED);
expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
-
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND,
elapsedTimeUs, STATS_SINCE_CHARGED);
expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
-
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND,
elapsedTimeUs, STATS_SINCE_CHARGED);
expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND)
@@ -174,7 +182,6 @@ public class BatteryStatsNoteTest extends TestCase{
+ stateRuntimeMap.get(ActivityManager.PROCESS_STATE_RECEIVER);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
-
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_CACHED,
elapsedTimeUs, STATS_SINCE_CHARGED);
expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_HOME)
@@ -191,7 +198,9 @@ public class BatteryStatsNoteTest extends TestCase{
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
}
- /** Test BatteryStatsImpl.updateTimeBasesLocked. */
+ /**
+ * Test BatteryStatsImpl.updateTimeBasesLocked.
+ */
@SmallTest
public void testUpdateTimeBasesLocked() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
@@ -213,7 +222,9 @@ public class BatteryStatsNoteTest extends TestCase{
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
}
- /** Test BatteryStatsImpl.noteScreenStateLocked sets timebases and screen states correctly. */
+ /**
+ * Test BatteryStatsImpl.noteScreenStateLocked sets timebases and screen states correctly.
+ */
@SmallTest
public void testNoteScreenStateLocked() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
@@ -232,15 +243,13 @@ public class BatteryStatsNoteTest extends TestCase{
assertEquals(bi.getScreenState(), Display.STATE_OFF);
}
- /** Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly.
+ /**
+ * Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly.
*
- * Unknown and doze should both be subset of off state
+ * Unknown and doze should both be subset of off state
*
- * Timeline 0----100----200----310----400------------1000
- * Unknown -------
- * On -------
- * Off ------- ----------------------
- * Doze ----------------
+ * Timeline 0----100----200----310----400------------1000 Unknown ------- On ------- Off
+ * ------- ---------------------- Doze ----------------
*/
@SmallTest
public void testNoteScreenStateTimersLocked() throws Exception {
@@ -280,4 +289,161 @@ public class BatteryStatsNoteTest extends TestCase{
assertEquals(600_000, bi.getScreenDozeTime(1500_000, STATS_SINCE_CHARGED));
}
+ @SmallTest
+ public void testAlarmStartAndFinishLocked() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.setRecordAllHistoryLocked(true);
+ bi.forceRecordAllHistory();
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+ clocks.realtime = clocks.uptime = 100;
+ bi.noteAlarmStartLocked("foo", null, UID);
+ clocks.realtime = clocks.uptime = 5000;
+ bi.noteAlarmFinishLocked("foo", null, UID);
+
+ HistoryItem item = new HistoryItem();
+ assertTrue(bi.startIteratingHistoryLocked());
+
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_ALARM_START, item.eventCode);
+ assertEquals("foo", item.eventTag.string);
+ assertEquals(UID, item.eventTag.uid);
+
+ // TODO(narayan): Figure out why this event is written to the history buffer. See
+ // test below where it is being interspersed between multiple START events too.
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_NONE, item.eventCode);
+
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_ALARM_FINISH, item.eventCode);
+ assertTrue(item.isDeltaData());
+ assertEquals("foo", item.eventTag.string);
+ assertEquals(UID, item.eventTag.uid);
+
+ assertFalse(bi.getNextHistoryLocked(item));
+ }
+
+ @SmallTest
+ public void testAlarmStartAndFinishLocked_workSource() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.setRecordAllHistoryLocked(true);
+ bi.forceRecordAllHistory();
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+ WorkSource ws = new WorkSource();
+ ws.add(100);
+ ws.createWorkChain().addNode(500, "tag");
+ bi.noteAlarmStartLocked("foo", ws, UID);
+ clocks.realtime = clocks.uptime = 5000;
+ bi.noteAlarmFinishLocked("foo", ws, UID);
+
+ HistoryItem item = new HistoryItem();
+ assertTrue(bi.startIteratingHistoryLocked());
+
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_ALARM_START, item.eventCode);
+ assertEquals("foo", item.eventTag.string);
+ assertEquals(100, item.eventTag.uid);
+
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_NONE, item.eventCode);
+
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_ALARM_START, item.eventCode);
+ assertEquals("foo", item.eventTag.string);
+ assertEquals(500, item.eventTag.uid);
+
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_ALARM_FINISH, item.eventCode);
+ assertEquals("foo", item.eventTag.string);
+ assertEquals(100, item.eventTag.uid);
+
+ assertTrue(bi.getNextHistoryLocked(item));
+ assertEquals(HistoryItem.EVENT_ALARM_FINISH, item.eventCode);
+ assertEquals("foo", item.eventTag.string);
+ assertEquals(500, item.eventTag.uid);
+ }
+
+ @SmallTest
+ public void testNoteWakupAlarmLocked() {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.setRecordAllHistoryLocked(true);
+ bi.forceRecordAllHistory();
+ bi.mForceOnBattery = true;
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+ bi.noteWakupAlarmLocked("com.foo.bar", UID, null, "tag");
+
+ Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
+ assertEquals(1, pkg.getWakeupAlarmStats().get("tag").getCountLocked(STATS_CURRENT));
+ assertEquals(1, pkg.getWakeupAlarmStats().size());
+ }
+
+ @SmallTest
+ public void testNoteWakupAlarmLocked_workSource_uid() {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.setRecordAllHistoryLocked(true);
+ bi.forceRecordAllHistory();
+ bi.mForceOnBattery = true;
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+ WorkSource ws = new WorkSource();
+ ws.add(100);
+
+ // When a WorkSource is present, "UID" should not be used - only the uids present in the
+ // WorkSource should be reported.
+ bi.noteWakupAlarmLocked("com.foo.bar", UID, ws, "tag");
+ Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
+ assertEquals(0, pkg.getWakeupAlarmStats().size());
+ pkg = bi.getPackageStatsLocked(100, "com.foo.bar");
+ assertEquals(1, pkg.getWakeupAlarmStats().size());
+
+ // If the WorkSource contains a "name", it should be interpreted as a package name and
+ // the packageName supplied as an argument must be ignored.
+ ws = new WorkSource();
+ ws.add(100, "com.foo.baz_alternate");
+ bi.noteWakupAlarmLocked("com.foo.baz", UID, ws, "tag");
+ pkg = bi.getPackageStatsLocked(100, "com.foo.baz");
+ assertEquals(0, pkg.getWakeupAlarmStats().size());
+ pkg = bi.getPackageStatsLocked(100, "com.foo.baz_alternate");
+ assertEquals(1, pkg.getWakeupAlarmStats().size());
+ }
+
+ @SmallTest
+ public void testNoteWakupAlarmLocked_workSource_workChain() {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.setRecordAllHistoryLocked(true);
+ bi.forceRecordAllHistory();
+ bi.mForceOnBattery = true;
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+ WorkSource ws = new WorkSource();
+ ws.createWorkChain().addNode(100, "com.foo.baz_alternate");
+ bi.noteWakupAlarmLocked("com.foo.bar", UID, ws, "tag");
+
+ // For WorkChains, again we must only attribute to the uids present in the WorkSource
+ // (and not to "UID"). However, unlike the older "tags" we do not change the packagename
+ // supplied as an argument, given that we're logging the entire attribution chain.
+ Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
+ assertEquals(0, pkg.getWakeupAlarmStats().size());
+ pkg = bi.getPackageStatsLocked(100, "com.foo.bar");
+ assertEquals(1, pkg.getWakeupAlarmStats().size());
+ pkg = bi.getPackageStatsLocked(100, "com.foo.baz_alternate");
+ assertEquals(0, pkg.getWakeupAlarmStats().size());
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index de2fd12267d5..f19ff6708c69 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -16,6 +16,8 @@
package com.android.internal.os;
+import android.os.Handler;
+import android.os.Looper;
import android.util.SparseIntArray;
import java.util.ArrayList;
@@ -37,6 +39,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
mOnBatteryTimeBase);
mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
setExternalStatsSyncLocked(new DummyExternalStatsSync());
+
+ // A no-op handler.
+ mHandler = new Handler(Looper.getMainLooper()) {};
}
MockBatteryStatsImpl() {
@@ -59,6 +64,12 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return mForceOnBattery ? true : super.isOnBattery();
}
+ public void forceRecordAllHistory() {
+ mHaveBatteryLevel = true;
+ mRecordingHistory = true;
+ mRecordAllHistory = true;
+ }
+
public TimeBase getOnBatteryBackgroundTimeBase(int uid) {
return getUidStatsLocked(uid).mOnBatteryBackgroundTimeBase;
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 3d65bd226faf..68b7ac287e98 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -429,7 +429,7 @@ public class Typeface {
}
/**
- * Sets an index of the font collection.
+ * Sets an index of the font collection. See {@link android.R.attr#ttcIndex}.
*
* Can not be used for Typeface source. build() method will return null for invalid index.
* @param ttcIndex An index of the font collection. If the font source is not font
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 7c7417dfaaac..5a8fa0700328 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -34,7 +34,8 @@ interface IKeyChainService {
void setUserSelectable(String alias, boolean isUserSelectable);
boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec);
- boolean attestKey(in String alias, in byte[] challenge, out KeymasterCertificateChain chain);
+ boolean attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags,
+ out KeymasterCertificateChain chain);
boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain);
// APIs used by CertInstaller and DevicePolicyManager
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 0811100f74c7..efee8b497ab8 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -99,48 +99,35 @@ public abstract class AttestationUtils {
}
}
+ @NonNull private static KeymasterArguments prepareAttestationArgumentsForDeviceId(
+ Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
+ DeviceIdAttestationException {
+ // Verify that device ID attestation types are provided.
+ if (idTypes == null) {
+ throw new NullPointerException("Missing id types");
+ }
+
+ return prepareAttestationArguments(context, idTypes, attestationChallenge);
+ }
+
/**
- * Performs attestation of the device's identifiers. This method returns a certificate chain
- * whose first element contains the requested device identifiers in an extension. The device's
- * manufacturer, model, brand, device and product are always also included in the attestation.
- * If the device supports attestation in secure hardware, the chain will be rooted at a
- * trustworthy CA key. Otherwise, the chain will be rooted at an untrusted certificate. See
- * <a href="https://developer.android.com/training/articles/security-key-attestation.html">
- * Key Attestation</a> for the format of the certificate extension.
- * <p>
- * Attestation will only be successful when all of the following are true:
- * 1) The device has been set up to support device identifier attestation at the factory.
- * 2) The user has not permanently disabled device identifier attestation.
- * 3) You have permission to access the device identifiers you are requesting attestation for.
- * <p>
- * For privacy reasons, you cannot distinguish between (1) and (2). If attestation is
- * unsuccessful, the device may not support it in general or the user may have permanently
- * disabled it.
- *
- * @param context the context to use for retrieving device identifiers.
- * @param idTypes the types of device identifiers to attest.
- * @param attestationChallenge a blob to include in the certificate alongside the device
- * identifiers.
- *
- * @return a certificate chain containing the requested device identifiers in the first element
- *
- * @exception SecurityException if you are not permitted to obtain an attestation of the
- * device's identifiers.
- * @exception DeviceIdAttestationException if the attestation operation fails.
+ * Prepares Keymaster Arguments with attestation data.
+ * @hide should only be used by KeyChain.
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- @NonNull public static X509Certificate[] attestDeviceIds(Context context,
+ @NonNull public static KeymasterArguments prepareAttestationArguments(Context context,
@NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
DeviceIdAttestationException {
// Check method arguments, retrieve requested device IDs and prepare attestation arguments.
- if (idTypes == null) {
- throw new NullPointerException("Missing id types");
- }
if (attestationChallenge == null) {
throw new NullPointerException("Missing attestation challenge");
}
final KeymasterArguments attestArgs = new KeymasterArguments();
attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, attestationChallenge);
+ // Return early if the caller did not request any device identifiers to be included in the
+ // attestation record.
+ if (idTypes == null) {
+ return attestArgs;
+ }
final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
for (int idType : idTypes) {
idTypesSet.add(idType);
@@ -191,6 +178,44 @@ public abstract class AttestationUtils {
Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
Build.MODEL.getBytes(StandardCharsets.UTF_8));
+ return attestArgs;
+ }
+
+ /**
+ * Performs attestation of the device's identifiers. This method returns a certificate chain
+ * whose first element contains the requested device identifiers in an extension. The device's
+ * manufacturer, model, brand, device and product are always also included in the attestation.
+ * If the device supports attestation in secure hardware, the chain will be rooted at a
+ * trustworthy CA key. Otherwise, the chain will be rooted at an untrusted certificate. See
+ * <a href="https://developer.android.com/training/articles/security-key-attestation.html">
+ * Key Attestation</a> for the format of the certificate extension.
+ * <p>
+ * Attestation will only be successful when all of the following are true:
+ * 1) The device has been set up to support device identifier attestation at the factory.
+ * 2) The user has not permanently disabled device identifier attestation.
+ * 3) You have permission to access the device identifiers you are requesting attestation for.
+ * <p>
+ * For privacy reasons, you cannot distinguish between (1) and (2). If attestation is
+ * unsuccessful, the device may not support it in general or the user may have permanently
+ * disabled it.
+ *
+ * @param context the context to use for retrieving device identifiers.
+ * @param idTypes the types of device identifiers to attest.
+ * @param attestationChallenge a blob to include in the certificate alongside the device
+ * identifiers.
+ *
+ * @return a certificate chain containing the requested device identifiers in the first element
+ *
+ * @exception SecurityException if you are not permitted to obtain an attestation of the
+ * device's identifiers.
+ * @exception DeviceIdAttestationException if the attestation operation fails.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @NonNull public static X509Certificate[] attestDeviceIds(Context context,
+ @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
+ DeviceIdAttestationException {
+ final KeymasterArguments attestArgs = prepareAttestationArgumentsForDeviceId(
+ context, idTypes, attestationChallenge);
// Perform attestation.
final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 1e424258b016..4a0d6ee19978 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -122,15 +122,19 @@ void TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text,
void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, float x,
float y) {
auto utf16 = asciiToUtf16(text);
- canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR, paint,
- nullptr);
+ SkPaint glyphPaint(paint);
+ glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR,
+ glyphPaint, nullptr);
}
void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
const SkPath& path) {
auto utf16 = asciiToUtf16(text);
- canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, paint,
- nullptr);
+ SkPaint glyphPaint(paint);
+ glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint,
+ nullptr);
}
void TestUtils::TestTask::run() {
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index bf0aed98cd70..38999cb1d2ec 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -40,22 +40,18 @@ public:
}
void doFrame(int frameNr) override {
- std::unique_ptr<uint16_t[]> text =
- TestUtils::asciiToUtf16("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
- ssize_t textLength = 26 * 2;
+ const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::unique_ptr<Canvas> canvas(
Canvas::create_recording_canvas(container->stagingProperties().getWidth(),
container->stagingProperties().getHeight()));
Paint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setColor(Color::Black);
for (int i = 0; i < 5; i++) {
paint.setTextSize(10 + (frameNr % 20) + i * 20);
- canvas->drawText(text.get(), 0, textLength, textLength, 0, 100 * (i + 2),
- minikin::Bidi::FORCE_LTR, paint, nullptr);
+ TestUtils::drawUtf8ToCanvas(canvas.get(), text, paint, 0, 100 * (i + 2));
}
container->setStagingDisplayList(canvas->finishRecording());
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index 6bae80c120ab..58c99800875b 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -36,7 +36,6 @@ class ListOfFadedTextAnimation : public TestListViewSceneBase {
SkPaint textPaint;
textPaint.setTextSize(dp(20));
textPaint.setAntiAlias(true);
- textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
TestUtils::drawUtf8ToCanvas(&canvas, "not that long long text", textPaint, dp(10), dp(30));
SkPoint pts[2];
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index d7ec288a8a7b..fd8c252ff318 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -83,7 +83,6 @@ class ListViewAnimation : public TestListViewSceneBase {
canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
SkPaint textPaint;
- textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
textPaint.setTextSize(dp(20));
textPaint.setAntiAlias(true);
diff --git a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
index 9eddc209a9a9..aa537b4f329c 100644
--- a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
@@ -38,7 +38,6 @@ public:
card = TestUtils::createNode(
0, 0, width, height, [&](RenderProperties& props, Canvas& canvas) {
SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(50);
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
index fee0659fa81d..3befce4a395f 100644
--- a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -42,10 +42,8 @@ public:
mBluePaint.setColor(SkColorSetARGB(255, 0, 0, 255));
mBluePaint.setTextSize(padding);
- mBluePaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0));
mGreenPaint.setTextSize(padding);
- mGreenPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
// interleave drawText and drawRect with saveLayer ops
for (int i = 0; i < regions; i++, top += smallRectHeight) {
@@ -54,18 +52,15 @@ public:
canvas.drawColor(SkColorSetARGB(255, 255, 255, 0), SkBlendMode::kSrcOver);
std::string stri = std::to_string(i);
std::string offscreen = "offscreen line " + stri;
- std::unique_ptr<uint16_t[]> offtext = TestUtils::asciiToUtf16(offscreen.c_str());
- canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(), bounds.fLeft,
- top + padding, minikin::Bidi::FORCE_LTR, mBluePaint, nullptr);
+ TestUtils::drawUtf8ToCanvas(&canvas, offscreen.c_str(), mBluePaint, bounds.fLeft,
+ top + padding);
canvas.restore();
canvas.drawRect(bounds.fLeft, top + padding, bounds.fRight,
top + smallRectHeight - padding, mBluePaint);
std::string onscreen = "onscreen line " + stri;
- std::unique_ptr<uint16_t[]> ontext = TestUtils::asciiToUtf16(onscreen.c_str());
- canvas.drawText(ontext.get(), 0, onscreen.length(), onscreen.length(), bounds.fLeft,
- top + smallRectHeight - padding, minikin::Bidi::FORCE_LTR, mGreenPaint,
- nullptr);
+ TestUtils::drawUtf8ToCanvas(&canvas, onscreen.c_str(), mGreenPaint, bounds.fLeft,
+ top + smallRectHeight - padding);
}
}
void doFrame(int frameNr) override {}
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
index a502116c30a0..a16b17849fc6 100644
--- a/libs/hwui/tests/common/scenes/TextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -29,7 +29,6 @@ public:
card = TestUtils::createNode(0, 0, width, height, [](RenderProperties& props,
Canvas& canvas) {
SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(50);
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index c845e6c89747..003d8e92fd9f 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -117,7 +117,6 @@ private:
canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(24);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index e56d2f864f77..4eb77514f4ae 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -537,7 +537,6 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, regionClipStopsMerge) {
canvas.save(SaveFlags::MatrixClip);
canvas.clipPath(&path, SkClipOp::kIntersect);
SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(50);
TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
@@ -569,7 +568,6 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textMerging) {
auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400, [](RenderProperties& props,
RecordingCanvas& canvas) {
SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(50);
TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
@@ -603,7 +601,6 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStrikethrough) {
textPaint.setAntiAlias(true);
textPaint.setTextSize(20);
textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
- textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
for (int i = 0; i < LOOPS; i++) {
TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
}
@@ -654,7 +651,6 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) {
auto node = TestUtils::createNode<RecordingCanvas>(
0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) {
SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(50);
paint.setStrokeWidth(10);
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 5aae15f478b8..8a9e34f81c6d 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -175,7 +175,6 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setTextSize(20);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
});
@@ -196,7 +195,6 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setTextSize(20);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
uint32_t flags = paint.getFlags();
@@ -238,7 +236,6 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setTextSize(20);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setTextAlign(SkPaint::kLeft_Align);
TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
paint.setTextAlign(SkPaint::kCenter_Align);
@@ -805,9 +802,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawText) {
Paint paint;
paint.setAntiAlias(true);
paint.setTextSize(20);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
- canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::Bidi::FORCE_LTR, paint, NULL);
+ TestUtils::drawUtf8ToCanvas(&canvas, "HELLO", paint, 25, 25);
});
int count = 0;
@@ -829,9 +824,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) {
paint.setColor(SK_ColorWHITE);
paint.setAntiAlias(true);
paint.setTextSize(20);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
- canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::Bidi::FORCE_LTR, paint, NULL);
+ TestUtils::drawUtf8ToCanvas(&canvas, "HELLO", paint, 25, 25);
});
Properties::enableHighContrastText = false;
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 4138f595b091..1d7dc3d06ee4 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -36,7 +36,6 @@ OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setTextSize(20);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
static const char* text = "testing text bounds";
// draw text directly into Recording canvas
diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
index 78d75d65837c..92d05e44c6ca 100644
--- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
+++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
@@ -29,6 +29,7 @@ using namespace android::uirenderer;
RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) {
SkPaint paint;
paint.setTextSize(20);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
GammaFontRenderer gammaFontRenderer;
FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index 6d9c5e2ad5fc..5d0c8e234d40 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -130,13 +130,11 @@ public final class AudioFocusInfo implements Parcelable {
dest.writeInt(mSdkTarget);
}
- @SystemApi
@Override
public int hashCode() {
return Objects.hash(mAttributes, mClientUid, mClientId, mPackageName, mGainRequest, mFlags);
}
- @SystemApi
@Override
public boolean equals(Object obj) {
if (this == obj)
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
index 7a80a8bd426e..24cf218fd0d8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
@@ -21,6 +21,7 @@ import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.printspooler.R;
/**
@@ -126,6 +127,7 @@ public final class PrintOptionsLayout extends ViewGroup {
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int childCount = getChildCount();
final int rowCount = childCount / mColumnCount + childCount % mColumnCount;
+ final boolean isLayoutRtl = isLayoutRtl();
int cellStart = getPaddingStart();
int cellTop = getPaddingTop();
@@ -134,7 +136,13 @@ public final class PrintOptionsLayout extends ViewGroup {
int rowHeight = 0;
for (int col = 0; col < mColumnCount; col++) {
- final int childIndex = row * mColumnCount + col;
+ final int childIndex;
+ if (isLayoutRtl) {
+ // if RTL, layout the right most child first
+ childIndex = row * mColumnCount + (mColumnCount - col - 1);
+ } else {
+ childIndex = row * mColumnCount + col;
+ }
if (childIndex >= childCount) {
break;
@@ -148,14 +156,14 @@ public final class PrintOptionsLayout extends ViewGroup {
MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
- final int childLeft = cellStart + childParams.getMarginStart();
+ final int childStart = cellStart + childParams.getMarginStart();
final int childTop = cellTop + childParams.topMargin;
- final int childRight = childLeft + child.getMeasuredWidth();
+ final int childEnd = childStart + child.getMeasuredWidth();
final int childBottom = childTop + child.getMeasuredHeight();
- child.layout(childLeft, childTop, childRight, childBottom);
+ child.layout(childStart, childTop, childEnd, childBottom);
- cellStart = childRight + childParams.getMarginEnd();
+ cellStart = childEnd + childParams.getMarginEnd();
rowHeight = Math.max(rowHeight, child.getMeasuredHeight()
+ childParams.topMargin + childParams.bottomMargin);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f4ec93666490..bef2bcbd80f1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1710,18 +1710,9 @@ public class SettingsProvider extends ContentProvider {
}
private List<String> getSettingsNamesLocked(int settingsType, int userId) {
- boolean instantApp;
- if (UserHandle.getAppId(Binder.getCallingUid()) < Process.FIRST_APPLICATION_UID) {
- instantApp = false;
- } else {
- ApplicationInfo ai = getCallingApplicationInfoOrThrow();
- instantApp = ai.isInstantApp();
- }
- if (instantApp) {
- return new ArrayList<String>(getInstantAppAccessibleSettings(settingsType));
- } else {
- return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
- }
+ // Don't enforce the instant app whitelist for now -- its too prone to unintended breakage
+ // in the current form.
+ return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
}
private void enforceSettingReadable(String settingName, int settingsType, int userId) {
@@ -1734,8 +1725,10 @@ public class SettingsProvider extends ContentProvider {
}
if (!getInstantAppAccessibleSettings(settingsType).contains(settingName)
&& !getOverlayInstantAppAccessibleSettings(settingsType).contains(settingName)) {
- throw new SecurityException("Setting " + settingName + " is not accessible from"
- + " ephemeral package " + getCallingPackage());
+ // Don't enforce the instant app whitelist for now -- its too prone to unintended
+ // breakage in the current form.
+ Slog.w(LOG_TAG, "Instant App " + ai.packageName
+ + " trying to access unexposed setting, this will be an error in the future.");
}
}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 2c5eb27abe3d..73fcdd7aa90d 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -39,7 +39,12 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-v7-mediarouter \
android-support-v7-palette \
android-support-v14-preference \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ android-slices-core \
+ android-slices-view \
+ android-slices-builders \
+ apptoolkit-arch-core-runtime \
+ apptoolkit-lifecycle-extensions \
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUI-tags \
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 020cfeeaa194..b154d46f162c 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -24,31 +24,20 @@
android:layout_marginEnd="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/date_owner_info_margin"
android:layout_gravity="center_horizontal"
- android:paddingTop="4dp"
android:clipToPadding="false"
android:orientation="vertical"
android:layout_centerHorizontal="true">
<TextView android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="end"
- android:fadingEdge="horizontal"
- android:gravity="center"
- android:textSize="22sp"
- android:textColor="?attr/wallpaperTextColor"
+ android:layout_marginBottom="@dimen/widget_vertical_padding"
+ android:theme="@style/TextAppearance.Keyguard"
/>
- <TextView android:id="@+id/text"
+ <LinearLayout android:id="@+id/row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:orientation="horizontal"
android:gravity="center"
- android:visibility="gone"
- android:textSize="16sp"
- android:textColor="?attr/wallpaperTextColor"
- android:layout_marginTop="4dp"
- android:ellipsize="end"
/>
</com.android.keyguard.KeyguardSliceView> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 138733e646ce..c97cfc4bb835 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -34,6 +34,7 @@
android:orientation="vertical">
<RelativeLayout
android:id="@+id/keyguard_clock_container"
+ android:animateLayoutChanges="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top">
@@ -59,14 +60,23 @@
android:layout_toEndOf="@id/clock_view"
android:visibility="invisible"
android:src="@drawable/ic_aod_charging_24dp"
- android:contentDescription="@string/accessibility_ambient_display_charging"
- />
+ android:contentDescription="@string/accessibility_ambient_display_charging" />
+ <View
+ android:id="@+id/clock_separator"
+ android:layout_width="16dp"
+ android:layout_height="1dp"
+ android:layout_marginTop="10dp"
+ android:layout_below="@id/clock_view"
+ android:background="#f00"
+ android:layout_centerHorizontal="true" />
<include layout="@layout/keyguard_status_area"
android:id="@+id/keyguard_status_area"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="@dimen/widget_vertical_padding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/clock_view" />
+ android:layout_below="@id/clock_separator" />
</RelativeLayout>
<TextView
@@ -83,6 +93,5 @@
android:letterSpacing="0.05"
android:ellipsize="marquee"
android:singleLine="true" />
-
</LinearLayout>
</com.android.keyguard.KeyguardStatusView>
diff --git a/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml b/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml
index 1b6fa4cf4892..3fb86d03a167 100644
--- a/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">72dp</dimen>
+ <dimen name="widget_big_font_size">64dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml b/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
index 1b6fa4cf4892..3fb86d03a167 100644
--- a/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">72dp</dimen>
+ <dimen name="widget_big_font_size">64dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index bcac07295cce..463af61c16f1 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -42,9 +42,22 @@
<dimen name="eca_overlap">-10dip</dimen>
<!-- Default clock parameters -->
- <dimen name="bottom_text_spacing_digital">-1dp</dimen>
- <dimen name="widget_label_font_size">14sp</dimen>
- <dimen name="widget_big_font_size">72dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-10dp</dimen>
+ <!-- Slice header -->
+ <dimen name="widget_title_font_size">28sp</dimen>
+ <!-- Slice subtitle -->
+ <dimen name="widget_label_font_size">16sp</dimen>
+ <!-- Clock without header -->
+ <dimen name="widget_big_font_size">64dp</dimen>
+ <!-- Clock with header -->
+ <dimen name="widget_small_font_size">22dp</dimen>
+ <!-- Dash between clock and header -->
+ <dimen name="widget_vertical_padding">16dp</dimen>
+ <!-- Subtitle paddings -->
+ <dimen name="widget_separator_thickness">2dp</dimen>
+ <dimen name="widget_horizontal_padding">8dp</dimen>
+ <dimen name="widget_icon_size">16dp</dimen>
+ <dimen name="widget_icon_padding">4dp</dimen>
<!-- The y translation to apply at the start in appear animations. -->
<dimen name="appear_y_translation_start">32dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 826e3ea1f7e5..d50bab533856 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -78,4 +78,18 @@
<item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
</style>
+ <style name="TextAppearance.Keyguard" parent="Theme.SystemUI">
+ <item name="android:textSize">@dimen/widget_title_font_size</item>
+ <item name="android:gravity">center</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:maxLines">2</item>
+ </style>
+
+ <style name="TextAppearance.Keyguard.Secondary">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textSize">@dimen/widget_label_font_size</item>
+ <item name="android:singleLine">true</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index 8b7f6926c9f7..03d587bd447c 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -60,14 +60,24 @@
</FrameLayout>
</FrameLayout>
- <ImageView
- android:id="@+id/dismiss"
- android:layout_width="@dimen/pip_action_size"
- android:layout_height="@dimen/pip_action_size"
- android:layout_gravity="top|end"
- android:padding="@dimen/pip_action_padding"
- android:contentDescription="@string/pip_phone_close"
- android:src="@drawable/ic_close_white"
- android:background="?android:selectableItemBackgroundBorderless" />
+ <ImageView
+ android:id="@+id/settings"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:layout_gravity="top|start"
+ android:padding="@dimen/pip_action_padding"
+ android:contentDescription="@string/pip_phone_settings"
+ android:src="@drawable/ic_settings"
+ android:background="?android:selectableItemBackgroundBorderless" />
+
+ <ImageView
+ android:id="@+id/dismiss"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:layout_gravity="top|end"
+ android:padding="@dimen/pip_action_padding"
+ android:contentDescription="@string/pip_phone_close"
+ android:src="@drawable/ic_close_white"
+ android:background="?android:selectableItemBackgroundBorderless" />
</FrameLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fd205dd55662..98537a102e1a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1895,6 +1895,9 @@
<!-- Label for PIP close button [CHAR LIMIT=NONE]-->
<string name="pip_phone_close">Close</string>
+ <!-- Label for PIP settings button [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_settings">Settings</string>
+
<!-- Label for PIP the drag to dismiss hint [CHAR LIMIT=NONE]-->
<string name="pip_phone_dismiss_hint">Drag down to dismiss</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index cb3d59c4dff6..b9bf80de304b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -17,38 +17,56 @@
package com.android.keyguard;
import android.app.PendingIntent;
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
-import android.app.slice.SliceQuery;
+import android.arch.lifecycle.LiveData;
+import android.arch.lifecycle.Observer;
import android.content.Context;
-import android.database.ContentObserver;
+import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Handler;
+import android.provider.Settings;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.graphics.ColorUtils;
+import com.android.settingslib.Utils;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.keyguard.KeyguardSliceProvider;
+import com.android.systemui.tuner.TunerService;
-import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.function.Consumer;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.widget.SliceLiveData;
/**
* View visible under the clock on the lock screen and AoD.
*/
-public class KeyguardSliceView extends LinearLayout {
+public class KeyguardSliceView extends LinearLayout implements View.OnClickListener,
+ Observer<Slice>, TunerService.Tunable {
- private final Uri mKeyguardSliceUri;
+ private static final String TAG = "KeyguardSliceView";
+ private final HashMap<View, PendingIntent> mClickActions;
+ private Uri mKeyguardSliceUri;
private TextView mTitle;
- private TextView mText;
- private Slice mSlice;
- private PendingIntent mSliceAction;
+ private LinearLayout mRow;
private int mTextColor;
private float mDarkAmount = 0;
- private final ContentObserver mObserver;
+ private LiveData<Slice> mLiveData;
+ private int mIconSize;
+ private Consumer<Boolean> mListener;
+ private boolean mHasHeader;
public KeyguardSliceView(Context context) {
this(context, null, 0);
@@ -60,16 +78,20 @@ public class KeyguardSliceView extends LinearLayout {
public KeyguardSliceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mObserver = new KeyguardSliceObserver(new Handler());
- mKeyguardSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);;
+
+ TunerService tunerService = Dependency.get(TunerService.class);
+ tunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI);
+
+ mClickActions = new HashMap<>();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTitle = findViewById(R.id.title);
- mText = findViewById(R.id.text);
- mTextColor = mTitle.getCurrentTextColor();
+ mRow = findViewById(R.id.row);
+ mTextColor = Utils.getColorAttr(mContext, R.attr.wallpaperTextColor);
+ mIconSize = (int) mContext.getResources().getDimension(R.dimen.widget_icon_size);
}
@Override
@@ -77,57 +99,103 @@ public class KeyguardSliceView extends LinearLayout {
super.onAttachedToWindow();
// Set initial content
- showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri,
- Collections.emptyList()));
+ showSlice(Slice.bindSlice(getContext(), mKeyguardSliceUri));
// Make sure we always have the most current slice
- getContext().getContentResolver().registerContentObserver(mKeyguardSliceUri,
- false /* notifyDescendants */, mObserver);
+ mLiveData.observeForever(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- getContext().getContentResolver().unregisterContentObserver(mObserver);
+ mLiveData.removeObserver(this);
}
private void showSlice(Slice slice) {
- // Items will be wrapped into an action when they have tap targets.
- SliceItem actionSlice = SliceQuery.find(slice, SliceItem.FORMAT_ACTION);
- if (actionSlice != null) {
- mSlice = actionSlice.getSlice();
- mSliceAction = actionSlice.getAction();
- } else {
- mSlice = slice;
- mSliceAction = null;
- }
- if (mSlice == null) {
- setVisibility(GONE);
- return;
- }
+ // Main area
+ SliceItem mainItem = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_SLICE,
+ null /* hints */, new String[]{android.app.slice.Slice.HINT_LIST_ITEM});
+ mHasHeader = mainItem != null;
- SliceItem title = SliceQuery.find(mSlice, SliceItem.FORMAT_TEXT, Slice.HINT_TITLE, null);
- if (title == null) {
+ List<SliceItem> subItems = SliceQuery.findAll(slice,
+ android.app.slice.SliceItem.FORMAT_SLICE,
+ new String[]{android.app.slice.Slice.HINT_LIST_ITEM},
+ null /* nonHints */);
+
+ if (!mHasHeader) {
mTitle.setVisibility(GONE);
} else {
mTitle.setVisibility(VISIBLE);
- mTitle.setText(title.getText());
+ SliceItem mainTitle = SliceQuery.find(mainItem.getSlice(),
+ android.app.slice.SliceItem.FORMAT_TEXT,
+ new String[]{android.app.slice.Slice.HINT_TITLE},
+ null /* nonHints */);
+ mTitle.setText(mainTitle.getText());
}
- SliceItem text = SliceQuery.find(mSlice, SliceItem.FORMAT_TEXT, null, Slice.HINT_TITLE);
- if (text == null) {
- mText.setVisibility(GONE);
- } else {
- mText.setVisibility(VISIBLE);
- mText.setText(text.getText());
+ mClickActions.clear();
+ final int subItemsCount = subItems.size();
+
+ for (int i = 0; i < subItemsCount; i++) {
+ SliceItem item = subItems.get(i);
+ final Uri itemTag = item.getSlice().getUri();
+ // Try to reuse the view if already exists in the layout
+ KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
+ if (button == null) {
+ button = new KeyguardSliceButton(mContext);
+ button.setTextColor(mTextColor);
+ button.setTag(itemTag);
+ } else {
+ mRow.removeView(button);
+ }
+ button.setHasDivider(i < subItemsCount - 1);
+ mRow.addView(button, i);
+
+ PendingIntent pendingIntent;
+ try {
+ pendingIntent = item.getAction();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Cannot retrieve action from keyguard slice", e);
+ pendingIntent = null;
+ }
+ mClickActions.put(button, pendingIntent);
+
+ SliceItem title = SliceQuery.find(item.getSlice(),
+ android.app.slice.SliceItem.FORMAT_TEXT,
+ new String[]{android.app.slice.Slice.HINT_TITLE},
+ null /* nonHints */);
+ button.setText(title.getText());
+
+ Drawable iconDrawable = null;
+ SliceItem icon = SliceQuery.find(item.getSlice(),
+ android.app.slice.SliceItem.FORMAT_IMAGE);
+ if (icon != null) {
+ iconDrawable = icon.getIcon().loadDrawable(mContext);
+ final int width = (int) (iconDrawable.getIntrinsicWidth()
+ / (float) iconDrawable.getIntrinsicHeight() * mIconSize);
+ iconDrawable.setBounds(0, 0, Math.max(width, 1), mIconSize);
+ }
+ button.setCompoundDrawablesRelative(iconDrawable, null, null, null);
+ button.setOnClickListener(this);
+ }
+
+ // Removing old views
+ for (int i = 0; i < mRow.getChildCount(); i++) {
+ View child = mRow.getChildAt(i);
+ if (!mClickActions.containsKey(child)) {
+ mRow.removeView(child);
+ i--;
+ }
}
- final int visibility = title == null && text == null ? GONE : VISIBLE;
+ final int visibility = mHasHeader || subItemsCount > 0 ? VISIBLE : GONE;
if (visibility != getVisibility()) {
setVisibility(visibility);
}
+
+ mListener.accept(mHasHeader);
}
public void setDark(float darkAmount) {
@@ -135,30 +203,113 @@ public class KeyguardSliceView extends LinearLayout {
updateTextColors();
}
- public void setTextColor(int textColor) {
- mTextColor = textColor;
- }
-
private void updateTextColors() {
final int blendedColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
mTitle.setTextColor(blendedColor);
- mText.setTextColor(blendedColor);
+ int childCount = mRow.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View v = mRow.getChildAt(i);
+ if (v instanceof Button) {
+ ((Button) v).setTextColor(blendedColor);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ final PendingIntent action = mClickActions.get(v);
+ if (action != null) {
+ try {
+ action.send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.i(TAG, "Pending intent cancelled, nothing to launch", e);
+ }
+ }
}
- private class KeyguardSliceObserver extends ContentObserver {
- KeyguardSliceObserver(Handler handler) {
- super(handler);
+ public void setListener(Consumer<Boolean> listener) {
+ mListener = listener;
+ }
+
+ public boolean hasHeader() {
+ return mHasHeader;
+ }
+
+ /**
+ * LiveData observer lifecycle.
+ * @param slice the new slice content.
+ */
+ @Override
+ public void onChanged(Slice slice) {
+ showSlice(slice);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ setupUri(newValue);
+ }
+
+ public void setupUri(String uriString) {
+ if (uriString == null) {
+ uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
+ }
+
+ boolean wasObserving = false;
+ if (mLiveData != null && mLiveData.hasActiveObservers()) {
+ wasObserving = true;
+ mLiveData.removeObserver(this);
+ }
+
+ mKeyguardSliceUri = Uri.parse(uriString);
+ mLiveData = SliceLiveData.fromUri(mContext, mKeyguardSliceUri);
+
+ if (wasObserving) {
+ mLiveData.observeForever(this);
+ showSlice(Slice.bindSlice(getContext(), mKeyguardSliceUri));
+ }
+ }
+
+ /**
+ * Representation of an item that appears under the clock on main keyguard message.
+ * Shows optional separator.
+ */
+ private class KeyguardSliceButton extends Button {
+
+ private final Paint mPaint;
+ private boolean mHasDivider;
+
+ public KeyguardSliceButton(Context context) {
+ super(context, null /* attrs */,
+ com.android.keyguard.R.style.TextAppearance_Keyguard_Secondary);
+ mPaint = new Paint();
+ mPaint.setStyle(Paint.Style.STROKE);
+ float dividerWidth = context.getResources()
+ .getDimension(R.dimen.widget_separator_thickness);
+ mPaint.setStrokeWidth(dividerWidth);
+ int horizontalPadding = (int) context.getResources()
+ .getDimension(R.dimen.widget_horizontal_padding);
+ setPadding(horizontalPadding, 0, horizontalPadding, 0);
+ setCompoundDrawablePadding((int) context.getResources()
+ .getDimension(R.dimen.widget_icon_padding));
+ }
+
+ public void setHasDivider(boolean hasDivider) {
+ mHasDivider = hasDivider;
}
@Override
- public void onChange(boolean selfChange) {
- this.onChange(selfChange, null);
+ public void setTextColor(int color) {
+ super.setTextColor(color);
+ mPaint.setColor(color);
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
- showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri,
- Collections.emptyList()));
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mHasDivider) {
+ final int lineX = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : getWidth();
+ canvas.drawLine(lineX, 0, lineX, getHeight(), mPaint);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 78cf2b9bf1ed..4b9a8744900d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -28,6 +28,7 @@ import android.os.UserHandle;
import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils;
import android.text.format.DateFormat;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
@@ -38,11 +39,11 @@ import android.widget.GridLayout;
import android.widget.TextClock;
import android.widget.TextView;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
-import com.android.settingslib.Utils;
import com.android.systemui.ChargingView;
+import com.google.android.collect.Sets;
+
import java.util.Locale;
public class KeyguardStatusView extends GridLayout {
@@ -52,8 +53,11 @@ public class KeyguardStatusView extends GridLayout {
private final LockPatternUtils mLockPatternUtils;
private final AlarmManager mAlarmManager;
+ private final float mSmallClockScale;
+ private final float mWidgetPadding;
private TextClock mClockView;
+ private View mClockSeparator;
private TextView mOwnerInfo;
private ViewGroup mClockContainer;
private ChargingView mBatteryDoze;
@@ -61,7 +65,7 @@ public class KeyguardStatusView extends GridLayout {
private Runnable mPendingMarqueeStart;
private Handler mHandler;
- private View[] mVisibleInDoze;
+ private ArraySet<View> mVisibleInDoze;
private boolean mPulsing;
private float mDarkAmount = 0;
private int mTextColor;
@@ -112,6 +116,9 @@ public class KeyguardStatusView extends GridLayout {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mLockPatternUtils = new LockPatternUtils(getContext());
mHandler = new Handler(Looper.myLooper());
+ mSmallClockScale = getResources().getDimension(R.dimen.widget_small_font_size)
+ / getResources().getDimension(R.dimen.widget_big_font_size);
+ mWidgetPadding = getResources().getDimension(R.dimen.widget_vertical_padding);
}
private void setEnableMarquee(boolean enabled) {
@@ -150,9 +157,14 @@ public class KeyguardStatusView extends GridLayout {
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
mKeyguardSlice = findViewById(R.id.keyguard_status_area);
- mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardSlice};
+ mClockSeparator = findViewById(R.id.clock_separator);
+ mVisibleInDoze = Sets.newArraySet(mBatteryDoze, mClockView, mKeyguardSlice,
+ mClockSeparator);
mTextColor = mClockView.getCurrentTextColor();
+ mKeyguardSlice.setListener(this::onSliceContentChanged);
+ onSliceContentChanged(mKeyguardSlice.hasHeader());
+
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
refresh();
@@ -163,6 +175,22 @@ public class KeyguardStatusView extends GridLayout {
mClockView.setElegantTextHeight(false);
}
+ private void onSliceContentChanged(boolean hasHeader) {
+ final float clockScale = hasHeader ? mSmallClockScale : 1;
+ float translation = (mClockView.getHeight() - (mClockView.getHeight() * clockScale)) / 2f;
+ if (hasHeader) {
+ translation -= mWidgetPadding;
+ }
+ mClockView.setTranslationY(translation);
+ mClockView.setScaleX(clockScale);
+ mClockView.setScaleY(clockScale);
+ final float batteryTranslation =
+ -(mClockView.getWidth() - (mClockView.getWidth() * clockScale)) / 2;
+ mBatteryDoze.setTranslationX(batteryTranslation);
+ mBatteryDoze.setTranslationY(translation);
+ mClockSeparator.setVisibility(hasHeader ? VISIBLE : GONE);
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -201,17 +229,6 @@ public class KeyguardStatusView extends GridLayout {
return mClockView.getTextSize();
}
- public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
- if (info == null) {
- return "";
- }
- String skeleton = DateFormat.is24HourFormat(context, ActivityManager.getCurrentUser())
- ? "EHm"
- : "Ehma";
- String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
- return DateFormat.format(pattern, info.getTriggerTime()).toString();
- }
-
private void updateOwnerInfo() {
if (mOwnerInfo == null) return;
String ownerInfo = getOwnerInfo();
@@ -303,7 +320,7 @@ public class KeyguardStatusView extends GridLayout {
final int N = mClockContainer.getChildCount();
for (int i = 0; i < N; i++) {
View child = mClockContainer.getChildAt(i);
- if (ArrayUtils.contains(mVisibleInDoze, child)) {
+ if (mVisibleInDoze.contains(child)) {
continue;
}
child.setAlpha(dark ? 0 : 1);
@@ -312,10 +329,12 @@ public class KeyguardStatusView extends GridLayout {
mOwnerInfo.setAlpha(dark ? 0 : 1);
}
+ final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount);
updateDozeVisibleViews();
mBatteryDoze.setDark(dark);
mKeyguardSlice.setDark(darkAmount);
- mClockView.setTextColor(ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount));
+ mClockView.setTextColor(blendedTextColor);
+ mClockSeparator.setBackgroundColor(blendedTextColor);
}
public void setPulsing(boolean pulsing) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 6ddc76b595b2..bd46c5f8ad0b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -16,38 +16,55 @@
package com.android.systemui.keyguard;
+import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
import android.icu.text.DateFormat;
import android.icu.text.DisplayContext;
import android.net.Uri;
import android.os.Handler;
-import android.app.slice.Slice;
-import android.app.slice.SliceProvider;
+import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
import java.util.Date;
import java.util.Locale;
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.builders.ListBuilder;
+import androidx.app.slice.builders.ListBuilder.RowBuilder;
+
/**
* Simple Slice provider that shows the current date.
*/
-public class KeyguardSliceProvider extends SliceProvider {
+public class KeyguardSliceProvider extends SliceProvider implements
+ NextAlarmController.NextAlarmChangeCallback {
public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
+ public static final String KEYGUARD_DATE_URI = "content://com.android.systemui.keyguard/date";
+ public static final String KEYGUARD_NEXT_ALARM_URI =
+ "content://com.android.systemui.keyguard/alarm";
private final Date mCurrentTime = new Date();
protected final Uri mSliceUri;
+ protected final Uri mDateUri;
+ protected final Uri mAlarmUri;
private final Handler mHandler;
private String mDatePattern;
private DateFormat mDateFormat;
private String mLastText;
private boolean mRegistered;
private boolean mRegisteredEveryMinute;
+ private String mNextAlarm;
+ private NextAlarmController mNextAlarmController;
/**
* Receiver responsible for time ticking and updating the date format.
@@ -80,23 +97,49 @@ public class KeyguardSliceProvider extends SliceProvider {
KeyguardSliceProvider(Handler handler) {
mHandler = handler;
mSliceUri = Uri.parse(KEYGUARD_SLICE_URI);
+ mDateUri = Uri.parse(KEYGUARD_DATE_URI);
+ mAlarmUri = Uri.parse(KEYGUARD_NEXT_ALARM_URI);
}
@Override
public Slice onBindSlice(Uri sliceUri) {
- return new Slice.Builder(sliceUri).addText(mLastText, null, Slice.HINT_TITLE).build();
+ ListBuilder builder = new ListBuilder(mSliceUri)
+ .addRow(new RowBuilder(mDateUri).setTitle(mLastText));
+ if (!TextUtils.isEmpty(mNextAlarm)) {
+ Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
+ builder.addRow(new RowBuilder(mAlarmUri).setTitle(mNextAlarm).addEndItem(icon));
+ }
+
+ return builder.build();
}
@Override
- public boolean onCreate() {
-
+ public boolean onCreateSliceProvider() {
+ mNextAlarmController = new NextAlarmControllerImpl(getContext());
+ mNextAlarmController.addCallback(this);
mDatePattern = getContext().getString(R.string.system_ui_date_pattern);
-
registerClockUpdate(false /* everyMinute */);
updateClock();
return true;
}
+ public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
+ if (info == null) {
+ return "";
+ }
+ String skeleton = android.text.format.DateFormat
+ .is24HourFormat(context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
+ String pattern = android.text.format.DateFormat
+ .getBestDateTimePattern(Locale.getDefault(), skeleton);
+ return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
+ }
+
+ /**
+ * Registers a broadcast receiver for clock updates, include date, time zone and manually
+ * changing the date/time via the settings app.
+ *
+ * @param everyMinute {@code true} if you also want updates every minute.
+ */
protected void registerClockUpdate(boolean everyMinute) {
if (mRegistered) {
if (mRegisteredEveryMinute == everyMinute) {
@@ -156,4 +199,10 @@ public class KeyguardSliceProvider extends SliceProvider {
void cleanDateFormat() {
mDateFormat = null;
}
+
+ @Override
+ public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
+ mNextAlarm = formatNextAlarm(getContext(), nextAlarm);
+ getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
new file mode 100644
index 000000000000..f0e4ccc139ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.pip.phone;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
+
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OnOpChangedListener;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Pair;
+
+public class PipAppOpsListener {
+ private static final String TAG = PipAppOpsListener.class.getSimpleName();
+
+ private Context mContext;
+ private IActivityManager mActivityManager;
+ private AppOpsManager mAppOpsManager;
+
+ private PipMotionHelper mMotionHelper;
+
+ private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
+ @Override
+ public void onOpChanged(String op, String packageName) {
+ try {
+ // Dismiss the PiP once the user disables the app ops setting for that package
+ final Pair<ComponentName, Integer> topPipActivityInfo =
+ PipUtils.getTopPinnedActivity(mContext, mActivityManager);
+ if (topPipActivityInfo.first != null) {
+ final ApplicationInfo appInfo = mContext.getPackageManager()
+ .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second);
+ if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) &&
+ mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid,
+ packageName) != MODE_ALLOWED) {
+ mMotionHelper.dismissPip();
+ }
+ }
+ } catch (NameNotFoundException e) {
+ // Unregister the listener if the package can't be found
+ unregisterAppOpsListener();
+ }
+ }
+ };
+
+ public PipAppOpsListener(Context context, IActivityManager activityManager,
+ PipMotionHelper motionHelper) {
+ mContext = context;
+ mActivityManager = activityManager;
+ mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mMotionHelper = motionHelper;
+ }
+
+ public void onActivityPinned(String packageName) {
+ // Register for changes to the app ops setting for this package while it is in PiP
+ registerAppOpsListener(packageName);
+ }
+
+ public void onActivityUnpinned() {
+ // Unregister for changes to the previously PiP'ed package
+ unregisterAppOpsListener();
+ }
+
+ private void registerAppOpsListener(String packageName) {
+ mAppOpsManager.startWatchingMode(OP_PICTURE_IN_PICTURE, packageName,
+ mAppOpsChangedListener);
+ }
+
+ private void unregisterAppOpsListener() {
+ mAppOpsManager.stopWatchingMode(mAppOpsChangedListener);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index db999c45dbde..36531bb727a4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -64,8 +64,8 @@ public class PipManager implements BasePipManager {
private InputConsumerController mInputConsumerController;
private PipMenuActivityController mMenuController;
private PipMediaController mMediaController;
- private PipNotificationController mNotificationController;
private PipTouchHandler mTouchHandler;
+ private PipAppOpsListener mAppOpsListener;
/**
* Handler for system task stack changes.
@@ -76,8 +76,7 @@ public class PipManager implements BasePipManager {
mTouchHandler.onActivityPinned();
mMediaController.onActivityPinned();
mMenuController.onActivityPinned();
- mNotificationController.onActivityPinned(packageName, userId,
- true /* deferUntilAnimationEnds */);
+ mAppOpsListener.onActivityPinned(packageName);
SystemServicesProxy.getInstance(mContext).setPipVisibility(true);
}
@@ -90,7 +89,7 @@ public class PipManager implements BasePipManager {
final int userId = topActivity != null ? topPipActivityInfo.second : 0;
mMenuController.onActivityUnpinned();
mTouchHandler.onActivityUnpinned(topActivity);
- mNotificationController.onActivityUnpinned(topActivity, userId);
+ mAppOpsListener.onActivityUnpinned();
SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null);
}
@@ -107,7 +106,6 @@ public class PipManager implements BasePipManager {
mTouchHandler.setTouchEnabled(true);
mTouchHandler.onPinnedStackAnimationEnded();
mMenuController.onPinnedStackAnimationEnded();
- mNotificationController.onPinnedStackAnimationEnded();
}
@Override
@@ -182,7 +180,7 @@ public class PipManager implements BasePipManager {
mInputConsumerController);
mTouchHandler = new PipTouchHandler(context, mActivityManager, mMenuController,
mInputConsumerController);
- mNotificationController = new PipNotificationController(context, mActivityManager,
+ mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
mTouchHandler.getMotionHelper());
EventBus.getDefault().register(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 90f7b8db1c59..bfe07a980ce7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -16,6 +16,10 @@
package com.android.systemui.pip.phone;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.provider.Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS;
+
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ALLOW_TIMEOUT;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
@@ -39,6 +43,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.PendingIntent.CanceledException;
import android.app.RemoteAction;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.graphics.Color;
@@ -46,12 +51,15 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -105,6 +113,7 @@ public class PipMenuActivity extends Activity {
private Drawable mBackgroundDrawable;
private View mMenuContainer;
private LinearLayout mActionsGroup;
+ private View mSettingsButton;
private View mDismissButton;
private ImageView mExpandButton;
private int mBetweenActionPaddingLand;
@@ -218,6 +227,11 @@ public class PipMenuActivity extends Activity {
}
return true;
});
+ mSettingsButton = findViewById(R.id.settings);
+ mSettingsButton.setAlpha(0);
+ mSettingsButton.setOnClickListener((v) -> {
+ showSettings();
+ });
mDismissButton = findViewById(R.id.dismiss);
mDismissButton.setAlpha(0);
mDismissButton.setOnClickListener((v) -> {
@@ -352,12 +366,14 @@ public class PipMenuActivity extends Activity {
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 1f);
menuAnim.addUpdateListener(mMenuBgUpdateListener);
+ ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+ mSettingsButton.getAlpha(), 1f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 1f);
if (menuState == MENU_STATE_FULL) {
- mMenuContainerAnimator.playTogether(menuAnim, dismissAnim);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim);
} else {
- mMenuContainerAnimator.play(dismissAnim);
+ mMenuContainerAnimator.playTogether(settingsAnim, dismissAnim);
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(MENU_FADE_DURATION);
@@ -394,9 +410,11 @@ public class PipMenuActivity extends Activity {
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 0f);
menuAnim.addUpdateListener(mMenuBgUpdateListener);
+ ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+ mSettingsButton.getAlpha(), 0f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 0f);
- mMenuContainerAnimator.playTogether(menuAnim, dismissAnim);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
mMenuContainerAnimator.setDuration(MENU_FADE_DURATION);
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@@ -526,12 +544,14 @@ public class PipMenuActivity extends Activity {
final float menuAlpha = 1 - fraction;
if (mMenuState == MENU_STATE_FULL) {
mMenuContainer.setAlpha(menuAlpha);
+ mSettingsButton.setAlpha(menuAlpha);
mDismissButton.setAlpha(menuAlpha);
final float interpolatedAlpha =
MENU_BACKGROUND_ALPHA * menuAlpha + DISMISS_BACKGROUND_ALPHA * fraction;
alpha = (int) (interpolatedAlpha * 255);
} else {
if (mMenuState == MENU_STATE_CLOSE) {
+ mSettingsButton.setAlpha(menuAlpha);
mDismissButton.setAlpha(menuAlpha);
}
alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
@@ -588,6 +608,19 @@ public class PipMenuActivity extends Activity {
sendMessage(m, "Could not notify controller to show PIP menu");
}
+ private void showSettings() {
+ final Pair<ComponentName, Integer> topPipActivityInfo =
+ PipUtils.getTopPinnedActivity(this, ActivityManager.getService());
+ if (topPipActivityInfo.first != null) {
+ final UserHandle user = UserHandle.of(topPipActivityInfo.second);
+ final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
+ Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
+ settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
+ settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(settingsIntent);
+ }
+ }
+
private void notifyActivityCallback(Messenger callback) {
Message m = Message.obtain();
m.what = PipMenuActivityController.MESSAGE_UPDATE_ACTIVITY_CALLBACK;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
deleted file mode 100644
index 6d083e9d601d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
+++ /dev/null
@@ -1,231 +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.
- */
-
-package com.android.systemui.pip.phone;
-
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
-import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.provider.Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS;
-
-import android.app.AppOpsManager;
-import android.app.AppOpsManager.OnOpChangedListener;
-import android.app.IActivityManager;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.util.IconDrawableFactory;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.util.NotificationChannels;
-
-/**
- * Manages the BTW notification that shows whenever an activity enters or leaves picture-in-picture.
- */
-public class PipNotificationController {
- private static final String TAG = PipNotificationController.class.getSimpleName();
-
- private static final String NOTIFICATION_TAG = PipNotificationController.class.getName();
- private static final int NOTIFICATION_ID = 0;
-
- private Context mContext;
- private IActivityManager mActivityManager;
- private AppOpsManager mAppOpsManager;
- private NotificationManager mNotificationManager;
- private IconDrawableFactory mIconDrawableFactory;
-
- private PipMotionHelper mMotionHelper;
-
- // Used when building a deferred notification
- private String mDeferredNotificationPackageName;
- private int mDeferredNotificationUserId;
-
- private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
- @Override
- public void onOpChanged(String op, String packageName) {
- try {
- // Dismiss the PiP once the user disables the app ops setting for that package
- final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPinnedActivity(mContext, mActivityManager);
- if (topPipActivityInfo.first != null) {
- final ApplicationInfo appInfo = mContext.getPackageManager()
- .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second);
- if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) &&
- mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid,
- packageName) != MODE_ALLOWED) {
- mMotionHelper.dismissPip();
- }
- }
- } catch (NameNotFoundException e) {
- // Unregister the listener if the package can't be found
- unregisterAppOpsListener();
- }
- }
- };
-
- public PipNotificationController(Context context, IActivityManager activityManager,
- PipMotionHelper motionHelper) {
- mContext = context;
- mActivityManager = activityManager;
- mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- mNotificationManager = NotificationManager.from(context);
- mMotionHelper = motionHelper;
- mIconDrawableFactory = IconDrawableFactory.newInstance(context);
- }
-
- public void onActivityPinned(String packageName, int userId, boolean deferUntilAnimationEnds) {
- // Clear any existing notification
- mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
-
- if (deferUntilAnimationEnds) {
- mDeferredNotificationPackageName = packageName;
- mDeferredNotificationUserId = userId;
- } else {
- showNotificationForApp(packageName, userId);
- }
-
- // Register for changes to the app ops setting for this package while it is in PiP
- registerAppOpsListener(packageName);
- }
-
- public void onPinnedStackAnimationEnded() {
- if (mDeferredNotificationPackageName != null) {
- showNotificationForApp(mDeferredNotificationPackageName, mDeferredNotificationUserId);
- mDeferredNotificationPackageName = null;
- mDeferredNotificationUserId = 0;
- }
- }
-
- public void onActivityUnpinned(ComponentName topPipActivity, int userId) {
- // Unregister for changes to the previously PiP'ed package
- unregisterAppOpsListener();
-
- // Reset the deferred notification package
- mDeferredNotificationPackageName = null;
- mDeferredNotificationUserId = 0;
-
- if (topPipActivity != null) {
- // onActivityUnpinned() is only called after the transition is complete, so we don't
- // need to defer until the animation ends to update the notification
- onActivityPinned(topPipActivity.getPackageName(), userId,
- false /* deferUntilAnimationEnds */);
- } else {
- mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
- }
- }
-
- /**
- * Builds and shows the notification for the given app.
- */
- private void showNotificationForApp(String packageName, int userId) {
- // Build a new notification
- try {
- final UserHandle user = UserHandle.of(userId);
- final Context userContext = mContext.createPackageContextAsUser(
- mContext.getPackageName(), 0, user);
- final Notification.Builder builder =
- new Notification.Builder(userContext, NotificationChannels.GENERAL)
- .setLocalOnly(true)
- .setOngoing(true)
- .setSmallIcon(R.drawable.pip_notification_icon)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
- if (updateNotificationForApp(builder, packageName, user)) {
- SystemUI.overrideNotificationAppName(mContext, builder);
-
- // Show the new notification
- mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
- }
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Could not show notification for application", e);
- }
- }
-
- /**
- * Updates the notification builder with app-specific information, returning whether it was
- * successful.
- */
- private boolean updateNotificationForApp(Notification.Builder builder, String packageName,
- UserHandle user) throws NameNotFoundException {
- final PackageManager pm = mContext.getPackageManager();
- final ApplicationInfo appInfo;
- try {
- appInfo = pm.getApplicationInfoAsUser(packageName, 0, user.getIdentifier());
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Could not update notification for application", e);
- return false;
- }
-
- if (appInfo != null) {
- final String appName = pm.getUserBadgedLabel(pm.getApplicationLabel(appInfo), user)
- .toString();
- final String message = mContext.getString(R.string.pip_notification_message, appName);
- final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
- Uri.fromParts("package", packageName, null));
- settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
- settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
-
- final Drawable iconDrawable = mIconDrawableFactory.getBadgedIcon(appInfo);
- builder.setContentTitle(mContext.getString(R.string.pip_notification_title, appName))
- .setContentText(message)
- .setContentIntent(PendingIntent.getActivityAsUser(mContext, packageName.hashCode(),
- settingsIntent, FLAG_CANCEL_CURRENT, null, user))
- .setStyle(new Notification.BigTextStyle().bigText(message))
- .setLargeIcon(createBitmap(iconDrawable).createAshmemBitmap());
- return true;
- }
- return false;
- }
-
- private void registerAppOpsListener(String packageName) {
- mAppOpsManager.startWatchingMode(OP_PICTURE_IN_PICTURE, packageName,
- mAppOpsChangedListener);
- }
-
- private void unregisterAppOpsListener() {
- mAppOpsManager.stopWatchingMode(mAppOpsChangedListener);
- }
-
- /**
- * Bakes a drawable into a bitmap.
- */
- private Bitmap createBitmap(Drawable d) {
- Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
- Config.ARGB_8888);
- Canvas c = new Canvas(bitmap);
- d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
- d.draw(c);
- c.setBitmap(null);
- return bitmap;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 0b7b6d555fdf..927a49cb60f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -18,11 +18,6 @@ package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE;
-
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -31,7 +26,6 @@ import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.UserManager;
-import android.provider.AlarmClock;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.util.AttributeSet;
@@ -39,24 +33,19 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.Dependency;
-import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.R.dimen;
-import com.android.systemui.R.id;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.qs.TouchAnimator.ListenerAdapter;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.ExpandableIndicator;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
@@ -65,8 +54,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 9d44895dbe8d..066cfe5862ef 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -46,7 +46,12 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-v7-mediarouter \
android-support-v7-palette \
android-support-v14-preference \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ android-slices-core \
+ android-slices-view \
+ android-slices-builders \
+ apptoolkit-arch-core-runtime \
+ apptoolkit-lifecycle-extensions \
LOCAL_STATIC_JAVA_LIBRARIES := \
metrics-helper-lib \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 4eae3426f815..be28569ef629 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -16,11 +16,10 @@
package com.android.systemui.keyguard;
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
-import android.app.slice.SliceQuery;
+import androidx.app.slice.Slice;
import android.content.Intent;
import android.net.Uri;
+import android.os.Debug;
import android.os.Handler;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -34,6 +33,9 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@@ -63,7 +65,8 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
@Test
public void returnsValidSlice() {
Slice slice = mProvider.onBindSlice(Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI));
- SliceItem text = SliceQuery.find(slice, SliceItem.FORMAT_TEXT, Slice.HINT_TITLE,
+ SliceItem text = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_TEXT,
+ android.app.slice.Slice.HINT_TITLE,
null /* nonHints */);
Assert.assertNotNull("Slice must provide a title.", text);
}
@@ -78,9 +81,10 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
@Test
public void updatesClock() {
+ mProvider.mUpdateClockInvokations = 0;
mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIME_TICK));
TestableLooper.get(this).processAllMessages();
- Assert.assertEquals("Clock should have been updated.", 2 /* expected */,
+ Assert.assertEquals("Clock should have been updated.", 1 /* expected */,
mProvider.mUpdateClockInvokations);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
index f1965a223dbc..56de32d3a401 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
@@ -33,6 +33,8 @@ import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -40,6 +42,30 @@ public class LeakDetectorTest extends SysuiTestCase {
private LeakDetector mLeakDetector;
+ // The references for which collection is observed are stored in fields. The allocation and
+ // of these references happens in separate methods (trackObjectWith/trackCollectionWith)
+ // from where they are set to null. The generated code might keep the allocated reference
+ // alive in a dex register when compiling in release mode. As R8 is used to compile this
+ // test the --dontoptimize flag is also required to ensure that these methods are not
+ // inlined, as that would defeat the purpose of having the mutation in methods.
+ private Object mObject;
+ private Collection<?> mCollection;
+
+ private CollectionWaiter trackObjectWith(Consumer<Object> tracker) {
+ mObject = new Object();
+ CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(mObject);
+ tracker.accept(mObject);
+ return collectionWaiter;
+ }
+
+ private CollectionWaiter trackCollectionWith(
+ BiConsumer<? super Collection<?>, String> tracker) {
+ mCollection = new ArrayList<>();
+ CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(mCollection);
+ tracker.accept(mCollection, "tag");
+ return collectionWaiter;
+ }
+
@Before
public void setup() {
mLeakDetector = LeakDetector.create();
@@ -51,31 +77,22 @@ public class LeakDetectorTest extends SysuiTestCase {
@Test
public void trackInstance_doesNotLeakTrackedObject() {
- Object object = new Object();
- CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
-
- mLeakDetector.trackInstance(object);
- object = null;
+ CollectionWaiter collectionWaiter = trackObjectWith(mLeakDetector::trackInstance);
+ mObject = null;
collectionWaiter.waitForCollection();
}
@Test
public void trackCollection_doesNotLeakTrackedObject() {
- Collection<?> object = new ArrayList<>();
- CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
-
- mLeakDetector.trackCollection(object, "tag");
- object = null;
+ CollectionWaiter collectionWaiter = trackCollectionWith(mLeakDetector::trackCollection);
+ mCollection = null;
collectionWaiter.waitForCollection();
}
@Test
public void trackGarbage_doesNotLeakTrackedObject() {
- Object object = new Object();
- CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
-
- mLeakDetector.trackGarbage(object);
- object = null;
+ CollectionWaiter collectionWaiter = trackObjectWith(mLeakDetector::trackGarbage);
+ mObject = null;
collectionWaiter.waitForCollection();
}
@@ -108,4 +125,4 @@ public class LeakDetectorTest extends SysuiTestCase {
FileOutputStream fos = new FileOutputStream("/dev/null");
mLeakDetector.dump(fos.getFD(), new PrintWriter(fos), new String[0]);
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
index 9787df91f5de..ce6212ef5aae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
@@ -41,6 +41,13 @@ public class WeakIdentityHashMapTest extends SysuiTestCase {
mMap = new WeakIdentityHashMap<>();
}
+ private CollectionWaiter addObjectToMap(WeakIdentityHashMap<Object, Object> map) {
+ Object object = new Object();
+ CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
+ map.put(object, "value");
+ return collectionWaiter;
+ }
+
@Test
public void testUsesIdentity() {
String a1 = new String("a");
@@ -56,11 +63,12 @@ public class WeakIdentityHashMapTest extends SysuiTestCase {
@Test
public void testWeaklyReferences() {
- Object object = new Object();
- CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
-
- mMap.put(object, "value");
- object = null;
+ // Allocate and add an object to the weak map in a separate method to avoid a live
+ // reference to the allocated object in a dex register. As R8 is used to compile this
+ // test the --dontoptimize flag is also required to ensure that the method is not
+ // inlined, as that would defeat the purpose of having the allocation in a separate
+ // method.
+ CollectionWaiter collectionWaiter = addObjectToMap(mMap);
// Wait until object has been collected. We'll also need to wait for mMap to become empty,
// because our collection waiter may be told about the collection earlier than mMap.
@@ -70,4 +78,4 @@ public class WeakIdentityHashMapTest extends SysuiTestCase {
assertEquals(0, mMap.size());
assertTrue(mMap.isEmpty());
}
-} \ No newline at end of file
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 935b787250fb..1aaa53837bf9 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5094,6 +5094,36 @@ message MetricsEvent {
// Tag used to report autofill field classification scores
FIELD_AUTOFILL_MATCH_SCORE = 1274;
+ // ACTION: Usb config has been changed to charging
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_USB_CONFIG_CHARGING = 1275;
+
+ // ACTION: Usb config has been changed to mtp (file transfer)
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_USB_CONFIG_MTP = 1276;
+
+ // ACTION: Usb config has been changed to ptp (photo transfer)
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_USB_CONFIG_PTP = 1277;
+
+ // ACTION: Usb config has been changed to rndis (usb tethering)
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_USB_CONFIG_RNDIS = 1278;
+
+ // ACTION: Usb config has been changed to midi
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_USB_CONFIG_MIDI = 1279;
+
+ // ACTION: Usb config has been changed to accessory
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_USB_CONFIG_ACCESSORY = 1280;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 50b0be1a11d2..ba8ce59803f7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.accessibility;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
@@ -762,7 +763,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mPictureInPictureActionReplacingConnection = wrapper;
wrapper.linkToDeath();
}
- mSecurityPolicy.notifyWindowsChanged();
}
}
@@ -2283,6 +2283,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ private void sendAccessibilityEventLocked(AccessibilityEvent event, int userId) {
+ // Resync to avoid calling out with the lock held
+ event.setEventTime(SystemClock.uptimeMillis());
+ mMainHandler.obtainMessage(
+ MainHandler.MSG_SEND_ACCESSIBILITY_EVENT, userId, 0 /* unused */, event)
+ .sendToTarget();
+ }
+
/**
* AIDL-exposed method. System only.
* Inform accessibility that a fingerprint gesture was performed
@@ -2419,6 +2427,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
public static final int MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER = 13;
public static final int MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER = 14;
public static final int MSG_INIT_SERVICE = 15;
+ public static final int MSG_SEND_ACCESSIBILITY_EVENT = 16;
public MainHandler(Looper looper) {
super(looper);
@@ -2519,6 +2528,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
(AccessibilityServiceConnection) msg.obj;
service.initializeService();
} break;
+
+ case MSG_SEND_ACCESSIBILITY_EVENT: {
+ final AccessibilityEvent event = (AccessibilityEvent) msg.obj;
+ final int userId = msg.arg1;
+ sendAccessibilityEvent(event, userId);
+ }
}
}
@@ -2533,7 +2548,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
AccessibilityEvent event = AccessibilityEvent.obtain(
AccessibilityEvent.TYPE_ANNOUNCEMENT);
event.getText().add(message);
- sendAccessibilityEvent(event, mCurrentUserId);
+ sendAccessibilityEventLocked(event, mCurrentUserId);
}
}
}
@@ -2961,21 +2976,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
public class SecurityPolicy {
public static final int INVALID_WINDOW_ID = -1;
- private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
- AccessibilityEvent.TYPE_VIEW_CLICKED
- | AccessibilityEvent.TYPE_VIEW_FOCUSED
- | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
- | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
- | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
- | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
- | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
- | AccessibilityEvent.TYPE_VIEW_SELECTED
- | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
- | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
- | AccessibilityEvent.TYPE_VIEW_SCROLLED
- | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
- | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
- | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
+ private static final int KEEP_SOURCE_EVENT_TYPES = AccessibilityEvent.TYPE_VIEW_CLICKED
+ | AccessibilityEvent.TYPE_VIEW_FOCUSED
+ | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
+ | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
+ | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
+ | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
+ | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+ | AccessibilityEvent.TYPE_WINDOWS_CHANGED
+ | AccessibilityEvent.TYPE_VIEW_SELECTED
+ | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+ | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
+ | AccessibilityEvent.TYPE_VIEW_SCROLLED
+ | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
+ | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
+ | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
// In Z order
public List<AccessibilityWindowInfo> mWindows;
@@ -3137,10 +3152,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mWindows = new ArrayList<>();
}
- final int oldWindowCount = mWindows.size();
- for (int i = oldWindowCount - 1; i >= 0; i--) {
- mWindows.remove(i).recycle();
- }
+ List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows);
+ SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone();
+
+ mWindows.clear();
mA11yWindowInfoById.clear();
for (int i = 0; i < mWindowInfoById.size(); i++) {
@@ -3202,7 +3217,49 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- notifyWindowsChanged();
+ sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById);
+
+ final int oldWindowCount = oldWindowList.size();
+ for (int i = oldWindowCount - 1; i >= 0; i--) {
+ oldWindowList.remove(i).recycle();
+ }
+ }
+
+ private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows,
+ SparseArray<AccessibilityWindowInfo> oldWindowsById) {
+ List<AccessibilityEvent> events = new ArrayList<>();
+ // Send events for all removed windows
+ final int oldWindowsCount = oldWindows.size();
+ for (int i = 0; i < oldWindowsCount; i++) {
+ final AccessibilityWindowInfo window = oldWindows.get(i);
+ if (mA11yWindowInfoById.get(window.getId()) == null) {
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+ window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
+ }
+ }
+
+ // Look for other changes
+ int oldWindowIndex = 0;
+ final int newWindowCount = mWindows.size();
+ for (int i = 0; i < newWindowCount; i++) {
+ final AccessibilityWindowInfo newWindow = mWindows.get(i);
+ final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId());
+ if (oldWindow == null) {
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+ newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED));
+ } else {
+ int changes = newWindow.differenceFrom(oldWindow);
+ if (changes != 0) {
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+ newWindow.getId(), changes));
+ }
+ }
+ }
+
+ final int numEvents = events.size();
+ for (int i = 0; i < numEvents; i++) {
+ sendAccessibilityEventLocked(events.get(i), mCurrentUserId);
+ }
}
public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
@@ -3243,7 +3300,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
public void updateEventSourceLocked(AccessibilityEvent event) {
- if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
+ if ((event.getEventType() & KEEP_SOURCE_EVENT_TYPES) == 0) {
event.setSource((View) null);
}
}
@@ -3357,46 +3414,55 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void setActiveWindowLocked(int windowId) {
if (mActiveWindowId != windowId) {
+ sendAccessibilityEventLocked(
+ AccessibilityEvent.obtainWindowsChangedEvent(
+ mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE),
+ mCurrentUserId);
+
mActiveWindowId = windowId;
if (mWindows != null) {
final int windowCount = mWindows.size();
for (int i = 0; i < windowCount; i++) {
AccessibilityWindowInfo window = mWindows.get(i);
- window.setActive(window.getId() == windowId);
+ if (window.getId() == windowId) {
+ window.setActive(true);
+ sendAccessibilityEventLocked(
+ AccessibilityEvent.obtainWindowsChangedEvent(windowId,
+ AccessibilityEvent.WINDOWS_CHANGE_ACTIVE),
+ mCurrentUserId);
+ } else {
+ window.setActive(false);
+ }
}
}
- notifyWindowsChanged();
}
}
private void setAccessibilityFocusedWindowLocked(int windowId) {
if (mAccessibilityFocusedWindowId != windowId) {
+ sendAccessibilityEventLocked(
+ AccessibilityEvent.obtainWindowsChangedEvent(
+ mAccessibilityFocusedWindowId,
+ WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED),
+ mCurrentUserId);
+
mAccessibilityFocusedWindowId = windowId;
if (mWindows != null) {
final int windowCount = mWindows.size();
for (int i = 0; i < windowCount; i++) {
AccessibilityWindowInfo window = mWindows.get(i);
- window.setAccessibilityFocused(window.getId() == windowId);
+ if (window.getId() == windowId) {
+ window.setAccessibilityFocused(true);
+ sendAccessibilityEventLocked(
+ AccessibilityEvent.obtainWindowsChangedEvent(
+ windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED),
+ mCurrentUserId);
+
+ } else {
+ window.setAccessibilityFocused(false);
+ }
}
}
-
- notifyWindowsChanged();
- }
- }
-
- public void notifyWindowsChanged() {
- if (mWindowsForAccessibilityCallback == null) {
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- // Let the client know the windows changed.
- AccessibilityEvent event = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_WINDOWS_CHANGED);
- event.setEventTime(SystemClock.uptimeMillis());
- sendAccessibilityEvent(event, mCurrentUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
index abfdb683c04c..d5b53bc686da 100644
--- a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
@@ -40,12 +40,6 @@ final class GestureUtils {
return (deltaTime >= timeout);
}
- public static boolean isSamePointerContext(MotionEvent first, MotionEvent second) {
- return (first.getPointerIdBits() == second.getPointerIdBits()
- && first.getPointerId(first.getActionIndex())
- == second.getPointerId(second.getActionIndex()));
- }
-
/**
* Determines whether a two pointer gesture is a dragging one.
*
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 9b2b4eb7ebee..74d2dddcdfb3 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -229,7 +229,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
}
void clearAndTransitionToStateDetecting() {
- mCurrentState = mDelegatingState;
+ mCurrentState = mDetectingState;
mDetectingState.clear();
mViewportDraggingState.clear();
mPanningScalingState.clear();
@@ -649,14 +649,19 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
break;
case ACTION_MOVE: {
if (isFingerDown()
- && distance(mLastDown, /* move */ event) > mSwipeMinDistance
- // For convenience, viewport dragging on 3tap&hold takes precedence
- // over insta-delegating on 3tap&swipe
- // (which is a rare combo to be used aside from magnification)
- && !isMultiTapTriggered(2 /* taps */)) {
-
- // Swipe detected - delegate skipping timeout
- transitionToDelegatingStateAndClear();
+ && distance(mLastDown, /* move */ event) > mSwipeMinDistance) {
+
+ // Swipe detected - transition immediately
+
+ // For convenience, viewport dragging takes precedence
+ // over insta-delegating on 3tap&swipe
+ // (which is a rare combo to be used aside from magnification)
+ if (isMultiTapTriggered(2 /* taps */)) {
+ transitionTo(mViewportDraggingState);
+ clear();
+ } else {
+ transitionToDelegatingStateAndClear();
+ }
}
}
break;
@@ -755,10 +760,10 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
int policyFlags) {
if (event.getActionMasked() == ACTION_DOWN) {
mPreLastDown = mLastDown;
- mLastDown = event;
+ mLastDown = MotionEvent.obtain(event);
} else if (event.getActionMasked() == ACTION_UP) {
mPreLastUp = mLastUp;
- mLastUp = event;
+ mLastUp = MotionEvent.obtain(event);
}
MotionEventInfo info = MotionEventInfo.obtain(event, rawEvent,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e1cb154c88f5..cac7fedd0b00 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -479,7 +479,7 @@ public final class AutofillManagerService extends SystemService {
if (service != null) {
service.destroySessionsLocked();
service.updateLocked(disabled);
- if (!service.isEnabled()) {
+ if (!service.isEnabledLocked()) {
removeCachedServiceLocked(userId);
}
}
@@ -621,6 +621,34 @@ public final class AutofillManagerService extends SystemService {
}
@Override
+ public String getDefaultFieldClassificationAlgorithm() throws RemoteException {
+ final int userId = UserHandle.getCallingUserId();
+
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ return service.getDefaultFieldClassificationAlgorithm(getCallingUid());
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public List<String> getAvailableFieldClassificationAlgorithms() throws RemoteException {
+ final int userId = UserHandle.getCallingUserId();
+
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ return service.getAvailableFieldClassificationAlgorithms(getCallingUid());
+ }
+ }
+
+ return null;
+ }
+
+ @Override
public ComponentName getAutofillServiceComponentName() throws RemoteException {
final int userId = UserHandle.getCallingUserId();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4cdfd625a8f0..65984dd5fdbe 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -51,6 +51,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
+import android.service.autofill.EditDistanceScorer;
import android.service.autofill.FieldClassification;
import android.service.autofill.FieldClassification.Match;
import android.service.autofill.FillEventHistory;
@@ -63,6 +64,8 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
+import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -81,6 +84,7 @@ import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Random;
@@ -105,7 +109,10 @@ final class AutofillManagerServiceImpl {
private final AutoFillUI mUi;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
+ @GuardedBy("mLock")
private RemoteCallbackList<IAutoFillManagerClient> mClients;
+
+ @GuardedBy("mLock")
private AutofillServiceInfo mInfo;
private static final Random sRandom = new Random();
@@ -113,25 +120,74 @@ final class AutofillManagerServiceImpl {
private final LocalLog mRequestsHistory;
private final LocalLog mUiLatencyHistory;
+ // TODO(b/70939974): temporary, will be moved to ExtServices
+ static final class FieldClassificationAlgorithmService {
+
+ /**
+ * Gets the name of all available algorithms.
+ */
+ @NonNull
+ public List<String> getAvailableAlgorithms() {
+ return Arrays.asList(EditDistanceScorer.NAME);
+ }
+
+ /**
+ * Gets the default algorithm that's used when an algorithm is not specified or is invalid.
+ */
+ @NonNull
+ public String getDefaultAlgorithm() {
+ return EditDistanceScorer.NAME;
+ }
+
+ /**
+ * Gets a field classification score.
+ *
+ * @param algorithmName algorithm to be used. If invalid, the default algorithm will be used
+ * instead.
+ * @param algorithmArgs optional arguments to be passed to the algorithm.
+ * @param actualValue value entered by the user.
+ * @param userDataValue value from the user data.
+ *
+ * @return pair containing the algorithm used and the score.
+ */
+ // TODO(b/70939974): use parcelable instead of pair
+ Pair<String, Float> getScore(@NonNull String algorithmName, @Nullable Bundle algorithmArgs,
+ @NonNull AutofillValue actualValue, @NonNull String userDataValue) {
+ if (!EditDistanceScorer.NAME.equals(algorithmName)) {
+ Log.w(TAG, "Ignoring invalid algorithm (" + algorithmName + ") and using "
+ + EditDistanceScorer.NAME + " instead");
+ }
+ return new Pair<>(EditDistanceScorer.NAME,
+ EditDistanceScorer.getInstance().getScore(actualValue, userDataValue));
+ }
+ }
+
+ private final FieldClassificationAlgorithmService mFcService =
+ new FieldClassificationAlgorithmService();
+
/**
* Apps disabled by the service; key is package name, value is when they will be enabled again.
*/
+ @GuardedBy("mLock")
private ArrayMap<String, Long> mDisabledApps;
/**
* Activities disabled by the service; key is component name, value is when they will be enabled
* again.
*/
+ @GuardedBy("mLock")
private ArrayMap<ComponentName, Long> mDisabledActivities;
/**
* Whether service was disabled for user due to {@link UserManager} restrictions.
*/
+ @GuardedBy("mLock")
private boolean mDisabled;
/**
* Data used for field classification.
*/
+ @GuardedBy("mLock")
private UserData mUserData;
/**
@@ -235,7 +291,7 @@ final class AutofillManagerServiceImpl {
}
void updateLocked(boolean disabled) {
- final boolean wasEnabled = isEnabled();
+ final boolean wasEnabled = isEnabledLocked();
if (sVerbose) {
Slog.v(TAG, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled
+ ", mSetupComplete= " + mSetupComplete
@@ -274,7 +330,7 @@ final class AutofillManagerServiceImpl {
Slog.e(TAG, "Bad AutofillServiceInfo for '" + componentName + "': " + e);
mInfo = null;
}
- final boolean isEnabled = isEnabled();
+ final boolean isEnabled = isEnabledLocked();
if (wasEnabled != isEnabled) {
if (!isEnabled) {
final int sessionCount = mSessions.size();
@@ -292,7 +348,7 @@ final class AutofillManagerServiceImpl {
mClients = new RemoteCallbackList<>();
}
mClients.register(client);
- return isEnabled();
+ return isEnabledLocked();
}
void removeClientLocked(IAutoFillManagerClient client) {
@@ -302,7 +358,7 @@ final class AutofillManagerServiceImpl {
}
void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
- if (!isEnabled()) {
+ if (!isEnabledLocked()) {
return;
}
final Session session = mSessions.get(sessionId);
@@ -312,7 +368,7 @@ final class AutofillManagerServiceImpl {
}
void setHasCallback(int sessionId, int uid, boolean hasIt) {
- if (!isEnabled()) {
+ if (!isEnabledLocked()) {
return;
}
final Session session = mSessions.get(sessionId);
@@ -327,7 +383,7 @@ final class AutofillManagerServiceImpl {
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
@NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
int flags, @NonNull ComponentName componentName) {
- if (!isEnabled()) {
+ if (!isEnabledLocked()) {
return 0;
}
@@ -388,7 +444,7 @@ final class AutofillManagerServiceImpl {
}
void finishSessionLocked(int sessionId, int uid) {
- if (!isEnabled()) {
+ if (!isEnabledLocked()) {
return;
}
@@ -411,7 +467,7 @@ final class AutofillManagerServiceImpl {
}
void cancelSessionLocked(int sessionId, int uid) {
- if (!isEnabled()) {
+ if (!isEnabledLocked()) {
return;
}
@@ -799,14 +855,15 @@ final class AutofillManagerServiceImpl {
// Called by AutofillManager
void setUserData(int callingUid, UserData userData) {
synchronized (mLock) {
- if (isCalledByServiceLocked("setUserData", callingUid)) {
- mUserData = userData;
- // Log it
- int numberFields = mUserData == null ? 0: mUserData.getRemoteIds().length;
- mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
- getServicePackageName(), null)
- .setCounterValue(numberFields));
+ if (!isCalledByServiceLocked("setUserData", callingUid)) {
+ return;
}
+ mUserData = userData;
+ // Log it
+ int numberFields = mUserData == null ? 0: mUserData.getRemoteIds().length;
+ mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
+ getServicePackageName(), null)
+ .setCounterValue(numberFields));
}
}
@@ -917,6 +974,11 @@ final class AutofillManagerServiceImpl {
pw.println();
mUserData.dump(prefix2, pw);
}
+
+ pw.print(prefix); pw.print("Available Field Classification algorithms: ");
+ pw.println(mFcService.getAvailableAlgorithms());
+ pw.print(prefix); pw.print("Default Field Classification algorithm: ");
+ pw.println(mFcService.getDefaultAlgorithm());
}
void destroySessionsLocked() {
@@ -964,11 +1026,13 @@ final class AutofillManagerServiceImpl {
final IAutoFillManagerClient client = clients.getBroadcastItem(i);
try {
final boolean resetSession;
+ final boolean isEnabled;
synchronized (mLock) {
resetSession = resetClient || isClientSessionDestroyedLocked(client);
+ isEnabled = isEnabledLocked();
}
int flags = 0;
- if (isEnabled()) {
+ if (isEnabled) {
flags |= AutofillManager.SET_STATE_FLAG_ENABLED;
}
if (resetSession) {
@@ -1004,7 +1068,7 @@ final class AutofillManagerServiceImpl {
return true;
}
- boolean isEnabled() {
+ boolean isEnabledLocked() {
return mSetupComplete && mInfo != null && !mDisabled;
}
@@ -1093,9 +1157,9 @@ final class AutofillManagerServiceImpl {
}
// Called by AutofillManager, checks UID.
- boolean isFieldClassificationEnabled(int uid) {
+ boolean isFieldClassificationEnabled(int callingUid) {
synchronized (mLock) {
- if (!isCalledByServiceLocked("isFieldClassificationEnabled", uid)) {
+ if (!isCalledByServiceLocked("isFieldClassificationEnabled", callingUid)) {
return false;
}
return isFieldClassificationEnabledLocked();
@@ -1110,6 +1174,28 @@ final class AutofillManagerServiceImpl {
mUserId) == 1;
}
+ FieldClassificationAlgorithmService getFieldClassificationService() {
+ return mFcService;
+ }
+
+ List<String> getAvailableFieldClassificationAlgorithms(int callingUid) {
+ synchronized (mLock) {
+ if (!isCalledByServiceLocked("getFCAlgorithms()", callingUid)) {
+ return null;
+ }
+ }
+ return mFcService.getAvailableAlgorithms();
+ }
+
+ String getDefaultFieldClassificationAlgorithm(int callingUid) {
+ synchronized (mLock) {
+ if (!isCalledByServiceLocked("getDefaultFCAlgorithm()", callingUid)) {
+ return null;
+ }
+ }
+ return mFcService.getDefaultAlgorithm();
+ }
+
@Override
public String toString() {
return "AutofillManagerServiceImpl: [userId=" + mUserId
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 01f908407691..96296907b2c5 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -69,6 +69,7 @@ import android.service.autofill.FieldClassification;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -84,6 +85,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.HandlerCaller;
import com.android.internal.util.ArrayUtils;
+import com.android.server.autofill.AutofillManagerServiceImpl.FieldClassificationAlgorithmService;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.PendingUi;
@@ -1088,7 +1090,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// Sets field classification score for field
if (userData!= null) {
- setScore(detectedFieldIds, detectedFieldClassifications, userData,
+ setFieldClassificationScore(mService.getFieldClassificationService(),
+ detectedFieldIds, detectedFieldClassifications, userData,
viewState.id, currentValue);
}
} // else
@@ -1133,7 +1136,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* Adds the matches to {@code detectedFieldsIds} and {@code detectedFieldClassifications} for
* {@code fieldId} based on its {@code currentValue} and {@code userData}.
*/
- private static void setScore(@NonNull ArrayList<AutofillId> detectedFieldIds,
+ private static void setFieldClassificationScore(
+ @NonNull AutofillManagerServiceImpl.FieldClassificationAlgorithmService service,
+ @NonNull ArrayList<AutofillId> detectedFieldIds,
@NonNull ArrayList<FieldClassification> detectedFieldClassifications,
@NonNull UserData userData, @NonNull AutofillId fieldId,
@NonNull AutofillValue currentValue) {
@@ -1150,11 +1155,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
+ final String algorithm = userData.getFieldClassificationAlgorithm();
+ final Bundle algorithmArgs = userData.getAlgorithmArgs();
ArrayList<Match> matches = null;
for (int i = 0; i < userValues.length; i++) {
String remoteId = remoteIds[i];
final String value = userValues[i];
- final float score = userData.getScorer().getScore(currentValue, value);
+ final Pair<String, Float> result = service.getScore(algorithm, algorithmArgs,
+ currentValue, value);
+ final String actualAlgorithm = result.first;
+ final float score = result.second;
if (score > 0) {
if (sVerbose) {
Slog.v(TAG, "adding score " + score + " at index " + i + " and id " + fieldId);
@@ -1162,7 +1172,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (matches == null) {
matches = new ArrayList<>(userValues.length);
}
- matches.add(new Match(remoteId, score));
+ matches.add(new Match(remoteId, score, actualAlgorithm));
}
else if (sVerbose) Slog.v(TAG, "skipping score 0 at index " + i + " and id " + fieldId);
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
index 537592e33d5c..b17f79480036 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
@@ -121,7 +121,7 @@ class BackupManagerConstants extends ContentObserver {
DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
mFullBackupRequiredNetworkType = mParser.getInt(FULL_BACKUP_REQUIRED_NETWORK_TYPE,
DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
- final String backupFinishedNotificationReceivers = mParser.getString(
+ String backupFinishedNotificationReceivers = mParser.getString(
BACKUP_FINISHED_NOTIFICATION_RECEIVERS,
DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS);
if (backupFinishedNotificationReceivers.isEmpty()) {
@@ -190,6 +190,9 @@ class BackupManagerConstants extends ContentObserver {
return mFullBackupRequiredNetworkType;
}
+ /**
+ * Returns an array of package names that should be notified whenever a backup finishes.
+ */
public synchronized String[] getBackupFinishedNotificationReceivers() {
if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getBackupFinishedNotificationReceivers(...) returns "
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 3a37459843be..51c44e103cc4 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -1424,6 +1424,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
final Intent notification = new Intent();
notification.setAction(BACKUP_FINISHED_ACTION);
notification.setPackage(receiver);
+ notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES |
+ Intent.FLAG_RECEIVER_FOREGROUND);
notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName);
mContext.sendBroadcastAsUser(notification, UserHandle.OWNER);
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 06cf9820ca5f..472723dfa909 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3035,15 +3035,8 @@ class AlarmManagerService extends SystemService {
Slog.v(TAG, "sending alarm " + alarm);
}
if (RECORD_ALARMS_IN_HISTORY) {
- if (alarm.workSource != null && alarm.workSource.size() > 0) {
- for (int wi=0; wi<alarm.workSource.size(); wi++) {
- ActivityManager.noteAlarmStart(
- alarm.operation, alarm.workSource.get(wi), alarm.statsTag);
- }
- } else {
- ActivityManager.noteAlarmStart(
- alarm.operation, alarm.uid, alarm.statsTag);
- }
+ ActivityManager.noteAlarmStart(alarm.operation, alarm.workSource, alarm.uid,
+ alarm.statsTag);
}
mDeliveryTracker.deliverLocked(alarm, nowELAPSED, allowWhileIdle);
} catch (RuntimeException e) {
@@ -3553,15 +3546,8 @@ class AlarmManagerService extends SystemService {
fs.aggregateTime += nowELAPSED - fs.startTime;
}
if (RECORD_ALARMS_IN_HISTORY) {
- if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) {
- for (int wi=0; wi<inflight.mWorkSource.size(); wi++) {
- ActivityManager.noteAlarmFinish(
- inflight.mPendingIntent, inflight.mWorkSource.get(wi), inflight.mTag);
- }
- } else {
- ActivityManager.noteAlarmFinish(
- inflight.mPendingIntent, inflight.mUid, inflight.mTag);
- }
+ ActivityManager.noteAlarmFinish(inflight.mPendingIntent, inflight.mWorkSource,
+ inflight.mUid, inflight.mTag);
}
}
@@ -3771,18 +3757,9 @@ class AlarmManagerService extends SystemService {
|| alarm.type == RTC_WAKEUP) {
bs.numWakeup++;
fs.numWakeup++;
- if (alarm.workSource != null && alarm.workSource.size() > 0) {
- for (int wi=0; wi<alarm.workSource.size(); wi++) {
- final String wsName = alarm.workSource.getName(wi);
- ActivityManager.noteWakeupAlarm(
- alarm.operation, alarm.workSource.get(wi),
- (wsName != null) ? wsName : alarm.packageName,
- alarm.statsTag);
- }
- } else {
- ActivityManager.noteWakeupAlarm(
- alarm.operation, alarm.uid, alarm.packageName, alarm.statsTag);
- }
+ ActivityManager.noteWakeupAlarm(
+ alarm.operation, alarm.workSource, alarm.uid, alarm.packageName,
+ alarm.statsTag);
}
}
}
diff --git a/services/core/java/com/android/server/EntropyMixer.java b/services/core/java/com/android/server/EntropyMixer.java
index 9877717943df..5e6e9d34dc25 100644
--- a/services/core/java/com/android/server/EntropyMixer.java
+++ b/services/core/java/com/android/server/EntropyMixer.java
@@ -196,11 +196,14 @@ public class EntropyMixer extends Binder {
* Mixes in the output from HW RNG (if present) into the Linux RNG.
*/
private void addHwRandomEntropy() {
+ if (!new File(hwRandomDevice).exists()) {
+ // HW RNG not present/exposed -- ignore
+ return;
+ }
+
try {
RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice, false);
Slog.i(TAG, "Added HW RNG output to entropy pool");
- } catch (FileNotFoundException ignored) {
- // HW RNG not present/exposed -- ignore
} catch (IOException e) {
Slog.w(TAG, "Failed to add HW RNG output to entropy pool", e);
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index d3ab1259c9ed..989cb886c126 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -19,6 +19,7 @@ package com.android.server;
import static android.Manifest.permission.DUMP;
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.EINVAL;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -1220,7 +1221,11 @@ public class IpSecService extends IIpSecService.Stub {
info.getSpiRecord(direction).getSpi());
}
} catch (ServiceSpecificException e) {
- // FIXME: get the error code and throw is at an IOException from Errno Exception
+ if (e.errorCode == EINVAL) {
+ throw new IllegalArgumentException(e.toString());
+ } else {
+ throw e;
+ }
}
}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 44c02270fe6c..33f77697f88c 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -26,6 +26,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.location.LocationManager;
import android.net.INetworkRecommendationProvider;
@@ -50,14 +51,17 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.TransferPipe;
+import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.DumpUtils;
import java.io.FileDescriptor;
@@ -91,7 +95,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
private final Object mPackageMonitorLock = new Object();
private final Object mServiceConnectionLock = new Object();
private final Handler mHandler;
- private final DispatchingContentObserver mContentObserver;
+ private final DispatchingContentObserver mRecommendationSettingsObserver;
+ private final ContentObserver mUseOpenWifiPackageObserver;
private final Function<NetworkScorerAppData, ScoringServiceConnection> mServiceConnProducer;
@GuardedBy("mPackageMonitorLock")
@@ -255,8 +260,40 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
mContext.registerReceiverAsUser(
mLocationModeReceiver, UserHandle.SYSTEM, locationModeFilter,
null /* broadcastPermission*/, mHandler);
- mContentObserver = new DispatchingContentObserver(context, mHandler);
+ mRecommendationSettingsObserver = new DispatchingContentObserver(context, mHandler);
mServiceConnProducer = serviceConnProducer;
+ mUseOpenWifiPackageObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ Uri useOpenWifiPkgUri = Global.getUriFor(Global.USE_OPEN_WIFI_PACKAGE);
+ if (useOpenWifiPkgUri.equals(uri)) {
+ String useOpenWifiPackage = Global.getString(mContext.getContentResolver(),
+ Global.USE_OPEN_WIFI_PACKAGE);
+ if (!TextUtils.isEmpty(useOpenWifiPackage)) {
+ LocalServices.getService(PackageManagerInternal.class)
+ .grantDefaultPermissionsToDefaultUseOpenWifiApp(useOpenWifiPackage,
+ userId);
+ }
+ }
+ }
+ };
+ mContext.getContentResolver().registerContentObserver(
+ Global.getUriFor(Global.USE_OPEN_WIFI_PACKAGE),
+ false /*notifyForDescendants*/,
+ mUseOpenWifiPackageObserver);
+ // Set a callback for the package manager to query the use open wifi app.
+ LocalServices.getService(PackageManagerInternal.class).setUseOpenWifiAppPackagesProvider(
+ new PackageManagerInternal.PackagesProvider() {
+ @Override
+ public String[] getPackages(int userId) {
+ String useOpenWifiPackage = Global.getString(mContext.getContentResolver(),
+ Global.USE_OPEN_WIFI_PACKAGE);
+ if (!TextUtils.isEmpty(useOpenWifiPackage)) {
+ return new String[]{useOpenWifiPackage};
+ }
+ return null;
+ }
+ });
}
/** Called when the system is ready to run third-party code but before it actually does so. */
@@ -287,11 +324,11 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
private void registerRecommendationSettingsObserver() {
final Uri packageNameUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_PACKAGE);
- mContentObserver.observe(packageNameUri,
+ mRecommendationSettingsObserver.observe(packageNameUri,
ServiceHandler.MSG_RECOMMENDATIONS_PACKAGE_CHANGED);
final Uri settingUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
- mContentObserver.observe(settingUri,
+ mRecommendationSettingsObserver.observe(settingUri,
ServiceHandler.MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 31aea63875ea..46eea78c7f8b 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5595,24 +5595,25 @@ public class AccountManagerService
long ident = Binder.clearCallingIdentity();
try {
packages = mPackageManager.getPackagesForUid(callingUid);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- if (packages != null) {
- for (String name : packages) {
- try {
- PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
- if (packageInfo != null
- && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
- != 0) {
- return true;
+ if (packages != null) {
+ for (String name : packages) {
+ try {
+ PackageInfo packageInfo =
+ mPackageManager.getPackageInfo(name, 0 /* flags */);
+ if (packageInfo != null
+ && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ != 0) {
+ return true;
+ }
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, String.format("Could not find package [%s]", name), e);
}
- } catch (NameNotFoundException e) {
- Log.w(TAG, String.format("Could not find package [%s]", name), e);
}
+ } else {
+ Log.w(TAG, "No known packages with uid " + callingUid);
}
- } else {
- Log.w(TAG, "No known packages with uid " + callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
return false;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d92b3b86d47a..5936ce1f65de 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13858,68 +13858,100 @@ public class ActivityManagerService extends IActivityManager.Stub
Context.WINDOW_SERVICE)).addView(v, lp);
}
- public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag) {
- if (sender != null && !(sender instanceof PendingIntentRecord)) {
- return;
+ @Override
+ public void noteWakeupAlarm(IIntentSender sender, WorkSource workSource, int sourceUid,
+ String sourcePkg, String tag) {
+ if (workSource != null && workSource.isEmpty()) {
+ workSource = null;
}
- final PendingIntentRecord rec = (PendingIntentRecord)sender;
- final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- if (mBatteryStatsService.isOnBattery()) {
- mBatteryStatsService.enforceCallingPermission();
- int MY_UID = Binder.getCallingUid();
- final int uid;
- if (sender == null) {
- uid = sourceUid;
- } else {
- uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
+
+ if (sourceUid <= 0 && workSource == null) {
+ // Try and derive a UID to attribute things to based on the caller.
+ if (sender != null) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
}
- BatteryStatsImpl.Uid.Pkg pkg =
- stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
- sourcePkg != null ? sourcePkg : rec.key.packageName);
- pkg.noteWakeupAlarmLocked(tag);
- StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid >= 0 ? sourceUid : uid,
- tag);
+
+ final PendingIntentRecord rec = (PendingIntentRecord) sender;
+ final int callerUid = Binder.getCallingUid();
+ sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
+ } else {
+ // TODO(narayan): Should we throw an exception in this case ? It means that we
+ // haven't been able to derive a UID to attribute things to.
+ return;
}
}
+
+ if (DEBUG_POWER) {
+ Slog.w(TAG, "noteWakupAlarm[ sourcePkg=" + sourcePkg + ", sourceUid=" + sourceUid
+ + ", workSource=" + workSource + ", tag=" + tag + "]");
+ }
+
+ mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);
}
- public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag) {
- if (sender != null && !(sender instanceof PendingIntentRecord)) {
- return;
+ @Override
+ public void noteAlarmStart(IIntentSender sender, WorkSource workSource, int sourceUid,
+ String tag) {
+ if (workSource != null && workSource.isEmpty()) {
+ workSource = null;
}
- final PendingIntentRecord rec = (PendingIntentRecord)sender;
- final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- mBatteryStatsService.enforceCallingPermission();
- int MY_UID = Binder.getCallingUid();
- final int uid;
- if (sender == null) {
- uid = sourceUid;
+
+ if (sourceUid <= 0 && workSource == null) {
+ // Try and derive a UID to attribute things to based on the caller.
+ if (sender != null) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
+ }
+
+ final PendingIntentRecord rec = (PendingIntentRecord) sender;
+ final int callerUid = Binder.getCallingUid();
+ sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
} else {
- uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
+ // TODO(narayan): Should we throw an exception in this case ? It means that we
+ // haven't been able to derive a UID to attribute things to.
+ return;
}
- mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid);
}
+
+ if (DEBUG_POWER) {
+ Slog.w(TAG, "noteAlarmStart[sourceUid=" + sourceUid + ", workSource=" + workSource +
+ ", tag=" + tag + "]");
+ }
+
+ mBatteryStatsService.noteAlarmStart(tag, workSource, sourceUid);
}
- public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag) {
- if (sender != null && !(sender instanceof PendingIntentRecord)) {
- return;
+ @Override
+ public void noteAlarmFinish(IIntentSender sender, WorkSource workSource, int sourceUid,
+ String tag) {
+ if (workSource != null && workSource.isEmpty()) {
+ workSource = null;
}
- final PendingIntentRecord rec = (PendingIntentRecord)sender;
- final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- mBatteryStatsService.enforceCallingPermission();
- int MY_UID = Binder.getCallingUid();
- final int uid;
- if (sender == null) {
- uid = sourceUid;
+
+ if (sourceUid <= 0 && workSource == null) {
+ // Try and derive a UID to attribute things to based on the caller.
+ if (sender != null) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
+ }
+
+ final PendingIntentRecord rec = (PendingIntentRecord) sender;
+ final int callerUid = Binder.getCallingUid();
+ sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
} else {
- uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
+ // TODO(narayan): Should we throw an exception in this case ? It means that we
+ // haven't been able to derive a UID to attribute things to.
+ return;
}
- mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid);
}
+
+ if (DEBUG_POWER) {
+ Slog.w(TAG, "noteAlarmFinish[sourceUid=" + sourceUid + ", workSource=" + workSource +
+ ", tag=" + tag + "]");
+ }
+
+ mBatteryStatsService.noteAlarmFinish(tag, workSource, sourceUid);
}
public boolean killPids(int[] pids, String pReason, boolean secure) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0a42aa9cce63..21085fa2f717 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3116,6 +3116,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Need to make sure the pinned stack exist so we can resize it below...
stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP);
+ // Calculate the target bounds here before the task is reparented back into pinned windowing
+ // mode (which will reset the saved bounds)
+ final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio);
+
try {
final TaskRecord task = r.getTask();
// Resize the pinned stack to match the current size of the task the activity we are
@@ -3154,11 +3158,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mWindowManager.continueSurfaceLayout();
}
- // Calculate the default bounds (don't use existing stack bounds as we may have just created
- // the stack, and schedule the start of the animation into PiP (the bounds animator that
- // is triggered by this is posted on another thread)
- final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio);
-
stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */,
true /* fromFullscreen */);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 35318f655bc4..430320a58e9c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -38,6 +38,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
import android.os.connectivity.CellularBatteryStats;
import android.os.health.HealthStatsParceler;
import android.os.health.HealthStatsWriter;
@@ -66,6 +67,7 @@ import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -446,17 +448,24 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
- public void noteAlarmStart(String name, int uid) {
+ public void noteWakupAlarm(String name, int uid, WorkSource workSource, String tag) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteAlarmStartLocked(name, uid);
+ mStats.noteWakupAlarmLocked(name, uid, workSource, tag);
}
}
- public void noteAlarmFinish(String name, int uid) {
+ public void noteAlarmStart(String name, WorkSource workSource, int uid) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteAlarmFinishLocked(name, uid);
+ mStats.noteAlarmStartLocked(name, workSource, uid);
+ }
+ }
+
+ public void noteAlarmFinish(String name, WorkSource workSource, int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteAlarmFinishLocked(name, workSource, uid);
}
}
diff --git a/services/core/java/com/android/server/am/ClientLifecycleManager.java b/services/core/java/com/android/server/am/ClientLifecycleManager.java
index 1e7080980d9e..014f7086efa3 100644
--- a/services/core/java/com/android/server/am/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/am/ClientLifecycleManager.java
@@ -21,7 +21,6 @@ import android.app.IApplicationThread;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.ActivityLifecycleItem;
-import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -44,12 +43,8 @@ class ClientLifecycleManager {
*/
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
transaction.schedule();
- if (!(transaction.getClient() instanceof Binder)) {
- // If client is not an instance of Binder - it's a remote call and at this point it is
- // safe to recycle the object. All objects used for local calls will be recycled after
- // the transaction is executed on client in ActivityThread.
- transaction.recycle();
- }
+ // TODO: b/70616950
+ //transaction.recycle();
}
/**
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 3064144072ae..ef5166579cb3 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -25,6 +25,7 @@ import android.hardware.radio.ITuner;
import android.hardware.radio.ITunerCallback;
import android.hardware.radio.RadioManager;
import android.os.ParcelableException;
+import android.util.Slog;
import com.android.server.SystemService;
@@ -33,6 +34,8 @@ import java.util.Objects;
import java.util.OptionalInt;
public class BroadcastRadioService extends SystemService {
+ private static final String TAG = "BcRadioSrv";
+
private final ServiceImpl mServiceImpl = new ServiceImpl();
private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1 =
@@ -84,13 +87,14 @@ public class BroadcastRadioService extends SystemService {
@Override
public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
boolean withAudio, ITunerCallback callback) {
+ Slog.i(TAG, "openTuner(" + moduleId + ", _, " + withAudio + ", _)");
enforcePolicyAccess();
if (callback == null) {
throw new IllegalArgumentException("Callback must not be empty");
}
synchronized (mLock) {
if (mHal2.hasModule(moduleId)) {
- throw new RuntimeException("Not implemented");
+ return mHal2.openSession(moduleId, callback);
} else {
return mHal1.openTuner(moduleId, bandConfig, withAudio, callback);
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 7629477438e4..413a27ce9af0 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -17,6 +17,8 @@
package com.android.server.broadcastradio.hal2;
import android.annotation.NonNull;
+import android.hardware.radio.ITuner;
+import android.hardware.radio.ITunerCallback;
import android.hardware.radio.RadioManager;
import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
import android.hidl.manager.V1_0.IServiceManager;
@@ -28,6 +30,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.stream.Collectors;
public class BroadcastRadioService {
@@ -76,4 +79,15 @@ public class BroadcastRadioService {
public boolean hasModule(int id) {
return mModules.containsKey(id);
}
+
+ public ITuner openSession(int moduleId, @NonNull ITunerCallback callback) {
+ Objects.requireNonNull(callback);
+
+ RadioModule module = mModules.get(moduleId);
+ if (module == null) {
+ throw new IllegalArgumentException("Invalid module ID");
+ }
+
+ return module.openSession(callback);
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index c3394e9e0df5..434e2620a324 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -18,12 +18,17 @@ package com.android.server.broadcastradio.hal2;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.broadcastradio.V2_0.AmFmBandRange;
+import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
import android.hardware.broadcastradio.V2_0.Properties;
+import android.hardware.broadcastradio.V2_0.Result;
import android.hardware.broadcastradio.V2_0.VendorKeyValue;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.os.ParcelableException;
import android.util.Slog;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -35,6 +40,28 @@ import java.util.Set;
class Convert {
private static final String TAG = "BcRadio2Srv.convert";
+ static void throwOnError(String action, int result) {
+ switch (result) {
+ case Result.OK:
+ return;
+ case Result.UNKNOWN_ERROR:
+ throw new ParcelableException(new RuntimeException(action + ": UNKNOWN_ERROR"));
+ case Result.INTERNAL_ERROR:
+ throw new ParcelableException(new RuntimeException(action + ": INTERNAL_ERROR"));
+ case Result.INVALID_ARGUMENTS:
+ throw new IllegalArgumentException(action + ": INVALID_ARGUMENTS");
+ case Result.INVALID_STATE:
+ throw new IllegalStateException(action + ": INVALID_STATE");
+ case Result.NOT_SUPPORTED:
+ throw new UnsupportedOperationException(action + ": NOT_SUPPORTED");
+ case Result.TIMEOUT:
+ throw new ParcelableException(new RuntimeException(action + ": TIMEOUT"));
+ default:
+ throw new ParcelableException(new RuntimeException(
+ action + ": unknown error (" + result + ")"));
+ }
+ }
+
private static @NonNull Map<String, String>
vendorInfoFromHal(@Nullable List<VendorKeyValue> info) {
if (info == null) return Collections.emptyMap();
@@ -94,13 +121,48 @@ class Convert {
return pTypes.stream().mapToInt(Integer::intValue).toArray();
}
+ private static @NonNull RadioManager.BandDescriptor[]
+ amfmConfigToBands(@Nullable AmFmRegionConfig config) {
+ if (config == null) return new RadioManager.BandDescriptor[0];
+
+ int len = config.ranges.size();
+ List<RadioManager.BandDescriptor> bands = new ArrayList<>(len);
+
+ // Just a dummy value.
+ int region = RadioManager.REGION_ITU_1;
+
+ for (AmFmBandRange range : config.ranges) {
+ FrequencyBand bandType = Utils.getBand(range.lowerBound);
+ if (bandType == FrequencyBand.UNKNOWN) {
+ Slog.e(TAG, "Unknown frequency band at " + range.lowerBound + "kHz");
+ continue;
+ }
+ if (bandType == FrequencyBand.FM) {
+ bands.add(new RadioManager.FmBandDescriptor(region, RadioManager.BAND_FM,
+ range.lowerBound, range.upperBound, range.spacing,
+
+ // TODO(b/69958777): stereo, rds, ta, af, ea
+ true, true, true, true, true
+ ));
+ } else { // AM
+ bands.add(new RadioManager.AmBandDescriptor(region, RadioManager.BAND_AM,
+ range.lowerBound, range.upperBound, range.spacing,
+
+ // TODO(b/69958777): stereo
+ true
+ ));
+ }
+ }
+
+ return bands.toArray(new RadioManager.BandDescriptor[bands.size()]);
+ }
+
static @NonNull RadioManager.ModuleProperties
- propertiesFromHal(int id, @NonNull String serviceName, Properties prop) {
+ propertiesFromHal(int id, @NonNull String serviceName, @NonNull Properties prop,
+ @Nullable AmFmRegionConfig amfmConfig) {
+ Objects.requireNonNull(serviceName);
Objects.requireNonNull(prop);
- // TODO(b/69958423): implement region info
- RadioManager.BandDescriptor[] bands = new RadioManager.BandDescriptor[0];
-
int[] supportedIdentifierTypes = prop.supportedIdentifierTypes.stream().
mapToInt(Integer::intValue).toArray();
int[] supportedProgramTypes = identifierTypesToProgramTypes(supportedIdentifierTypes);
@@ -123,7 +185,7 @@ class Convert {
1, // numAudioSources
false, // isCaptureSupported
- bands,
+ amfmConfigToBands(amfmConfig),
true, // isBgScanSupported is deprecated
supportedProgramTypes,
supportedIdentifierTypes,
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Mutable.java b/services/core/java/com/android/server/broadcastradio/hal2/Mutable.java
new file mode 100644
index 000000000000..a9d80549f963
--- /dev/null
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Mutable.java
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+
+package com.android.server.broadcastradio.hal2;
+
+/**
+ * A wrapper class for mutable objects to be used in non-mutable contexts
+ * (i.e. final variables catched in lambda closures).
+ *
+ * @param <E> type of boxed value.
+ */
+final class Mutable<E> {
+ /**
+ * A mutable value.
+ */
+ public E value;
+
+ /**
+ * Initialize value with null pointer.
+ */
+ public Mutable() {
+ value = null;
+ }
+
+ /**
+ * Initialize value with specific value.
+ *
+ * @param value initial value.
+ */
+ public Mutable(E value) {
+ this.value = value;
+ }
+}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 34c1b0ce7d93..8a7ac7355b7e 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -18,9 +18,15 @@ package com.android.server.broadcastradio.hal2;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.radio.ITuner;
import android.hardware.radio.RadioManager;
+import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
+import android.hardware.broadcastradio.V2_0.ITunerSession;
+import android.hardware.broadcastradio.V2_0.Result;
+import android.os.ParcelableException;
import android.os.RemoteException;
+import android.util.MutableInt;
import android.util.Slog;
import java.util.Objects;
@@ -42,8 +48,13 @@ class RadioModule {
IBroadcastRadio service = IBroadcastRadio.getService();
if (service == null) return null;
+ Mutable<AmFmRegionConfig> amfmConfig = new Mutable<>();
+ service.getAmFmRegionConfig(false, (int result, AmFmRegionConfig config) -> {
+ if (result == Result.OK) amfmConfig.value = config;
+ });
+
RadioManager.ModuleProperties prop =
- Convert.propertiesFromHal(idx, fqName, service.getProperties());
+ Convert.propertiesFromHal(idx, fqName, service.getProperties(), amfmConfig.value);
return new RadioModule(service, prop);
} catch (RemoteException ex) {
@@ -51,4 +62,44 @@ class RadioModule {
return null;
}
}
+
+ public @NonNull ITuner openSession(@NonNull android.hardware.radio.ITunerCallback userCb) {
+ TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb));
+ Mutable<ITunerSession> hwSession = new Mutable<>();
+ MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
+
+ try {
+ mService.openSession(cb, (int result, ITunerSession session) -> {
+ hwSession.value = session;
+ halResult.value = result;
+ });
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "failed to open session", ex);
+ throw new ParcelableException(ex);
+ }
+
+ Convert.throwOnError("openSession", halResult.value);
+ Objects.requireNonNull(hwSession.value);
+
+ TunerSession session = new TunerSession(hwSession.value, cb);
+
+ // send out legacy callback about band configuration
+ RadioManager.BandDescriptor[] bands = mProperties.getBands();
+ if (bands != null && bands.length > 0) {
+ RadioManager.BandDescriptor descr = bands[0]; // just pick first
+ Mutable<RadioManager.BandConfig> config = new Mutable<>();
+ if (descr instanceof RadioManager.FmBandDescriptor) {
+ config.value = new RadioManager.FmBandConfig((RadioManager.FmBandDescriptor)descr);
+ } else if (descr instanceof RadioManager.AmBandDescriptor) {
+ config.value = new RadioManager.AmBandConfig((RadioManager.AmBandDescriptor)descr);
+ } else {
+ Slog.w(TAG, "Descriptor is neither AM nor FM");
+ }
+ if (config.value != null) {
+ TunerCallback.dispatch(() -> userCb.onConfigurationChanged(config.value));
+ }
+ }
+
+ return session;
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
new file mode 100644
index 000000000000..5ee6a4c693cd
--- /dev/null
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+
+package com.android.server.broadcastradio.hal2;
+
+import android.annotation.NonNull;
+import android.hardware.broadcastradio.V2_0.ITunerCallback;
+import android.hardware.broadcastradio.V2_0.ProgramInfo;
+import android.hardware.broadcastradio.V2_0.ProgramListChunk;
+import android.hardware.broadcastradio.V2_0.ProgramSelector;
+import android.hardware.broadcastradio.V2_0.VendorKeyValue;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+class TunerCallback extends ITunerCallback.Stub {
+ private static final String TAG = "BcRadio2Srv.cb";
+
+ final android.hardware.radio.ITunerCallback mCb;
+
+ interface RunnableThrowingRemoteException {
+ void run() throws RemoteException;
+ }
+
+ TunerCallback(@NonNull android.hardware.radio.ITunerCallback clientCallback) {
+ mCb = Objects.requireNonNull(clientCallback);
+ }
+
+ static void dispatch(RunnableThrowingRemoteException func) {
+ try {
+ func.run();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "callback call failed", ex);
+ }
+ }
+
+ @Override
+ public void onTuneFailed(int result, ProgramSelector selector) {}
+
+ @Override
+ public void onCurrentProgramInfoChanged(ProgramInfo info) {}
+
+ @Override
+ public void onProgramListUpdated(ProgramListChunk chunk) {}
+
+ @Override
+ public void onAntennaStateChange(boolean connected) {}
+
+ @Override
+ public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {}
+}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
new file mode 100644
index 000000000000..e8faf3dfa63f
--- /dev/null
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ */
+
+package com.android.server.broadcastradio.hal2;
+
+import android.annotation.NonNull;
+import android.graphics.Bitmap;
+import android.hardware.broadcastradio.V2_0.ITunerSession;
+import android.hardware.radio.ITuner;
+import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.RadioManager;
+import android.util.Slog;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+class TunerSession extends ITuner.Stub {
+ private static final String TAG = "BcRadio2Srv.session";
+
+ private final Object mLock = new Object();
+
+ private final ITunerSession mHwSession;
+ private final TunerCallback mCallback;
+ private boolean mIsClosed = false;
+
+ TunerSession(@NonNull ITunerSession hwSession, @NonNull TunerCallback callback) {
+ mHwSession = Objects.requireNonNull(hwSession);
+ mCallback = Objects.requireNonNull(callback);
+ }
+
+ @Override
+ public void close() {
+ synchronized (mLock) {
+ if (mIsClosed) return;
+ mIsClosed = true;
+ }
+ }
+
+ @Override
+ public boolean isClosed() {
+ return mIsClosed;
+ }
+
+ private void checkNotClosedLocked() {
+ if (mIsClosed) {
+ throw new IllegalStateException("Tuner is closed, no further operations are allowed");
+ }
+ }
+
+ @Override
+ public void setConfiguration(RadioManager.BandConfig config) {}
+
+ @Override
+ public RadioManager.BandConfig getConfiguration() {
+ return null;
+ }
+
+ @Override
+ public void setMuted(boolean mute) {}
+
+ @Override
+ public boolean isMuted() {
+ return false;
+ }
+
+ @Override
+ public void step(boolean directionDown, boolean skipSubChannel) {}
+
+ @Override
+ public void scan(boolean directionDown, boolean skipSubChannel) {}
+
+ @Override
+ public void tune(ProgramSelector selector) {}
+
+ @Override
+ public void cancel() {}
+
+ @Override
+ public void cancelAnnouncement() {}
+
+ @Override
+ public RadioManager.ProgramInfo getProgramInformation() {
+ return null;
+ }
+
+ @Override
+ public Bitmap getImage(int id) {
+ return null;
+ }
+
+ @Override
+ public boolean startBackgroundScan() {
+ return false;
+ }
+
+ @Override
+ public List<RadioManager.ProgramInfo> getProgramList(Map vendorFilter) {
+ return null;
+ }
+
+ @Override
+ public boolean isAnalogForced() {
+ return false;
+ }
+
+ @Override
+ public void setAnalogForced(boolean isForced) {}
+
+ @Override
+ public Map setParameters(Map parameters) {
+ return null;
+ }
+
+ @Override
+ public Map getParameters(List<String> keys) {
+ return null;
+ }
+
+ @Override
+ public boolean isAntennaConnected() {
+ return true;
+ }
+}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
new file mode 100644
index 000000000000..3520f37880c5
--- /dev/null
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+
+package com.android.server.broadcastradio.hal2;
+
+enum FrequencyBand {
+ UNKNOWN,
+ FM,
+ AM_LW,
+ AM_MW,
+ AM_SW,
+};
+
+class Utils {
+ private static final String TAG = "BcRadio2Srv.utils";
+
+ static FrequencyBand getBand(int freq) {
+ // keep in sync with hardware/interfaces/broadcastradio/common/utils2x/Utils.cpp
+ if (freq < 30) return FrequencyBand.UNKNOWN;
+ if (freq < 500) return FrequencyBand.AM_LW;
+ if (freq < 1705) return FrequencyBand.AM_MW;
+ if (freq < 30000) return FrequencyBand.AM_SW;
+ if (freq < 60000) return FrequencyBand.UNKNOWN;
+ if (freq < 110000) return FrequencyBand.FM;
+ return FrequencyBand.UNKNOWN;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7715727f6d73..c7a43153c0aa 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -305,6 +305,7 @@ public class Vpn {
} else {
for (Network underlying : underlyingNetworks) {
final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
+ if (underlyingCaps == null) continue;
for (int underlyingType : underlyingCaps.getTransportTypes()) {
transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 3b9d40fa0825..0b62907a0d0c 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -17,6 +17,8 @@
package com.android.server.display;
import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.hardware.display.BrightnessConfiguration;
import android.os.PowerManager;
import android.util.MathUtils;
@@ -41,11 +43,30 @@ public abstract class BrightnessMappingStrategy {
private static final boolean DEBUG = false;
@Nullable
- public static BrightnessMappingStrategy create(
- float[] luxLevels, int[] brightnessLevelsBacklight, float[] brightnessLevelsNits,
- float[] nitsRange, int[] backlightRange) {
+ public static BrightnessMappingStrategy create(Resources resources) {
+ float[] luxLevels = getLuxLevels(resources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLevels));
+ int[] brightnessLevelsBacklight = resources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
+ float[] brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
+
+ float[] nitsRange = getFloatArray(resources.obtainTypedArray(
+ com.android.internal.R.array.config_screenBrightnessNits));
+ int[] backlightRange = resources.getIntArray(
+ com.android.internal.R.array.config_screenBrightnessBacklight);
+
if (isValidMapping(nitsRange, backlightRange)
&& isValidMapping(luxLevels, brightnessLevelsNits)) {
+ int minimumBacklight = resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
+ int maximumBacklight = resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
+ if (backlightRange[0] > minimumBacklight
+ || backlightRange[backlightRange.length - 1] < maximumBacklight) {
+ Slog.w(TAG, "Screen brightness mapping does not cover whole range of available"
+ + " backlight values, autobrightness functionality may be impaired.");
+ }
BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
builder.setCurve(luxLevels, brightnessLevelsNits);
return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange);
@@ -56,6 +77,25 @@ public abstract class BrightnessMappingStrategy {
}
}
+ private static float[] getLuxLevels(int[] lux) {
+ // The first control point is implicit and always at 0 lux.
+ float[] levels = new float[lux.length + 1];
+ for (int i = 0; i < lux.length; i++) {
+ levels[i + 1] = (float) lux[i];
+ }
+ return levels;
+ }
+
+ private static float[] getFloatArray(TypedArray array) {
+ final int N = array.length();
+ float[] vals = new float[N];
+ for (int i = 0; i < N; i++) {
+ vals[i] = array.getFloat(i, -1.0f);
+ }
+ array.recycle();
+ return vals;
+ }
+
private static boolean isValidMapping(float[] x, float[] y) {
if (x == null || y == null || x.length == 0 || y.length == 0) {
return false;
@@ -124,10 +164,17 @@ public abstract class BrightnessMappingStrategy {
* brightness and 0 is the display at minimum brightness.
*
* @param lux The current ambient brightness in lux.
- * @return The desired brightness of the display compressed to the range [0, 1.0].
+ * @return The desired brightness of the display normalized to the range [0, 1.0].
*/
public abstract float getBrightness(float lux);
+ /**
+ * Gets the display's brightness in nits for the given backlight value.
+ *
+ * Returns -1.0f if there's no available mapping for the backlight to nits.
+ */
+ public abstract float getNits(int backlight);
+
public abstract void dump(PrintWriter pw);
private static float normalizeAbsoluteBrightness(int brightness) {
@@ -186,6 +233,11 @@ public abstract class BrightnessMappingStrategy {
}
@Override
+ public float getNits(int backlight) {
+ return -1.0f;
+ }
+
+ @Override
public void dump(PrintWriter pw) {
pw.println("SimpleMappingStrategy");
pw.println(" mSpline=" + mSpline);
@@ -209,7 +261,11 @@ public abstract class BrightnessMappingStrategy {
// A spline mapping from nits to the corresponding backlight value, normalized to the range
// [0, 1.0].
- private final Spline mBacklightSpline;
+ private final Spline mNitsToBacklightSpline;
+
+ // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to
+ // a brightness in nits.
+ private final Spline mBacklightToNitsSpline;
// The default brightness configuration.
private final BrightnessConfiguration mDefaultConfig;
@@ -227,19 +283,18 @@ public abstract class BrightnessMappingStrategy {
// Setup the backlight spline
final int N = nits.length;
- float[] x = new float[N];
- float[] y = new float[N];
+ float[] normalizedBacklight = new float[N];
for (int i = 0; i < N; i++) {
- x[i] = nits[i];
- y[i] = normalizeAbsoluteBrightness(backlight[i]);
+ normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]);
}
- mBacklightSpline = Spline.createSpline(x, y);
+ mNitsToBacklightSpline = Spline.createSpline(nits, normalizedBacklight);
+ mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits);
if (DEBUG) {
- Slog.d(TAG, "Backlight spline: " + mBacklightSpline);
+ Slog.d(TAG, "Backlight spline: " + mNitsToBacklightSpline);
for (float v = 1f; v < nits[nits.length - 1] * 1.25f; v *= 1.25f) {
Slog.d(TAG, String.format(
- " %7.1f: %7.1f", v, mBacklightSpline.interpolate(v)));
+ " %7.1f: %7.1f", v, mNitsToBacklightSpline.interpolate(v)));
}
}
@@ -275,7 +330,12 @@ public abstract class BrightnessMappingStrategy {
@Override
public float getBrightness(float lux) {
- return mBacklightSpline.interpolate(mBrightnessSpline.interpolate(lux));
+ return mNitsToBacklightSpline.interpolate(mBrightnessSpline.interpolate(lux));
+ }
+
+ @Override
+ public float getNits(int backlight) {
+ return mBacklightToNitsSpline.interpolate(normalizeAbsoluteBrightness(backlight));
}
@Override
@@ -283,7 +343,7 @@ public abstract class BrightnessMappingStrategy {
pw.println("PhysicalMappingStrategy");
pw.println(" mConfig=" + mConfig);
pw.println(" mBrightnessSpline=" + mBrightnessSpline);
- pw.println(" mBacklightSpline=" + mBacklightSpline);
+ pw.println(" mNitsToBacklightSpline=" + mNitsToBacklightSpline);
}
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 42247f94e69f..cbb1c0139bca 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -24,7 +24,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ParceledListSlice;
-import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -34,6 +33,8 @@ import android.net.Uri;
import android.os.BatteryManager;
import android.os.Environment;
import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -88,7 +89,7 @@ public class BrightnessTracker {
private static final String TAG_EVENTS = "events";
private static final String TAG_EVENT = "event";
- private static final String ATTR_BRIGHTNESS = "brightness";
+ private static final String ATTR_NITS = "nits";
private static final String ATTR_TIMESTAMP = "timestamp";
private static final String ATTR_PACKAGE_NAME = "packageName";
private static final String ATTR_USER = "user";
@@ -97,7 +98,10 @@ public class BrightnessTracker {
private static final String ATTR_BATTERY_LEVEL = "batteryLevel";
private static final String ATTR_NIGHT_MODE = "nightMode";
private static final String ATTR_COLOR_TEMPERATURE = "colorTemperature";
- private static final String ATTR_LAST_BRIGHTNESS = "lastBrightness";
+ private static final String ATTR_LAST_NITS = "lastNits";
+
+ private static final int MSG_BACKGROUND_START = 0;
+ private static final int MSG_BRIGHTNESS_CHANGED = 1;
// Lock held while accessing mEvents, is held while writing events to flash.
private final Object mEventsLock = new Object();
@@ -113,9 +117,7 @@ public class BrightnessTracker {
private final Context mContext;
private final ContentResolver mContentResolver;
private Handler mBgHandler;
- // mSettingsObserver, mBroadcastReceiver and mSensorListener should only be used on
- // the mBgHandler thread.
- private SettingsObserver mSettingsObserver;
+ // mBroadcastReceiver and mSensorListener should only be used on the mBgHandler thread.
private BroadcastReceiver mBroadcastReceiver;
private SensorListener mSensorListener;
@@ -126,9 +128,9 @@ public class BrightnessTracker {
@GuardedBy("mDataCollectionLock")
private float mLastBatteryLevel = Float.NaN;
@GuardedBy("mDataCollectionLock")
- private int mIgnoreBrightness = -1;
+ private float mLastBrightness = -1;
@GuardedBy("mDataCollectionLock")
- private int mLastBrightness = -1;
+ private boolean mStarted;
private final Injector mInjector;
@@ -144,33 +146,31 @@ public class BrightnessTracker {
}
}
- /** Start listening for brightness slider events */
- public void start() {
+ /**
+ * Start listening for brightness slider events
+ *
+ * @param brightness the initial screen brightness
+ */
+ public void start(float initialBrightness) {
if (DEBUG) {
Slog.d(TAG, "Start");
}
- mBgHandler = mInjector.getBackgroundHandler();
+ mBgHandler = new TrackerHandler(mInjector.getBackgroundHandler().getLooper());
mUserManager = mContext.getSystemService(UserManager.class);
- mBgHandler.post(() -> backgroundStart());
+ mBgHandler.obtainMessage(MSG_BACKGROUND_START, (Float) initialBrightness).sendToTarget();
}
- private void backgroundStart() {
+ private void backgroundStart(float initialBrightness) {
readEvents();
- mLastBrightness = mInjector.getSystemIntForUser(mContentResolver,
- Settings.System.SCREEN_BRIGHTNESS, -1,
- UserHandle.USER_CURRENT);
-
mSensorListener = new SensorListener();
+
if (mInjector.isInteractive(mContext)) {
mInjector.registerSensorListener(mContext, mSensorListener, mBgHandler);
}
- mSettingsObserver = new SettingsObserver(mBgHandler);
- mInjector.registerBrightnessObserver(mContentResolver, mSettingsObserver);
-
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SHUTDOWN);
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
@@ -180,6 +180,10 @@ public class BrightnessTracker {
mInjector.registerReceiver(mContext, mBroadcastReceiver, intentFilter);
mInjector.scheduleIdleJob(mContext);
+ synchronized (mDataCollectionLock) {
+ mLastBrightness = initialBrightness;
+ mStarted = true;
+ }
}
/** Stop listening for events */
@@ -188,10 +192,14 @@ public class BrightnessTracker {
if (DEBUG) {
Slog.d(TAG, "Stop");
}
+ mBgHandler.removeMessages(MSG_BACKGROUND_START);
mInjector.unregisterSensorListener(mContext, mSensorListener);
mInjector.unregisterReceiver(mContext, mBroadcastReceiver);
- mInjector.unregisterBrightnessObserver(mContext, mSettingsObserver);
mInjector.cancelIdleJob(mContext);
+
+ synchronized (mDataCollectionLock) {
+ mStarted = false;
+ }
}
/**
@@ -220,40 +228,45 @@ public class BrightnessTracker {
return new ParceledListSlice<>(out);
}
- /** Sets brightness without logging the brightness change event */
- public void setBrightness(int brightness, int userId) {
- synchronized (mDataCollectionLock) {
- mIgnoreBrightness = brightness;
- }
- mInjector.putSystemIntForUser(mContentResolver, Settings.System.SCREEN_BRIGHTNESS,
- brightness, userId);
- }
-
public void persistEvents() {
scheduleWriteEvents();
}
- private void handleBrightnessChanged() {
+ /**
+ * Notify the BrightnessTracker that the user has changed the brightness of the display.
+ */
+ public void notifyBrightnessChanged(float brightness, boolean userInitiated) {
if (DEBUG) {
- Slog.d(TAG, "Brightness change");
+ Slog.d(TAG, String.format("notifyBrightnessChanged(brightness=%f, userInitiated=%b)",
+ brightness, userInitiated));
}
- final BrightnessChangeEvent event = new BrightnessChangeEvent();
- event.timeStamp = mInjector.currentTimeMillis();
-
- int brightness = mInjector.getSystemIntForUser(mContentResolver,
- Settings.System.SCREEN_BRIGHTNESS, -1,
- UserHandle.USER_CURRENT);
+ Message m = mBgHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED,
+ userInitiated ? 1 : 0, 0 /*unused*/, (Float) brightness);
+ m.sendToTarget();
+ }
+ private void handleBrightnessChanged(float brightness, boolean userInitiated) {
+ final BrightnessChangeEvent event;
synchronized (mDataCollectionLock) {
- int previousBrightness = mLastBrightness;
+ if (!mStarted) {
+ // Not currently gathering brightness change information
+ return;
+ }
+
+ float previousBrightness = mLastBrightness;
mLastBrightness = brightness;
- if (brightness == -1 || brightness == mIgnoreBrightness) {
- // Notified of brightness change but no setting or self change so ignore.
- mIgnoreBrightness = -1;
+ if (!userInitiated) {
+ // We want to record what current brightness is so that we know what the user
+ // changed it from, but if it wasn't user initiated then we don't want to record it
+ // as a BrightnessChangeEvent.
return;
}
+
+ event = new BrightnessChangeEvent();
+ event.timeStamp = mInjector.currentTimeMillis();
+
final int readingCount = mLastSensorReadings.size();
if (readingCount == 0) {
// No sensor data so ignore this.
@@ -386,7 +399,7 @@ public class BrightnessTracker {
if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) {
mEvents.append(toWrite[i]);
out.startTag(null, TAG_EVENT);
- out.attribute(null, ATTR_BRIGHTNESS, Integer.toString(toWrite[i].brightness));
+ out.attribute(null, ATTR_NITS, Float.toString(toWrite[i].brightness));
out.attribute(null, ATTR_TIMESTAMP, Long.toString(toWrite[i].timeStamp));
out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName);
out.attribute(null, ATTR_USER, Integer.toString(userSerialNo));
@@ -394,8 +407,8 @@ public class BrightnessTracker {
out.attribute(null, ATTR_NIGHT_MODE, Boolean.toString(toWrite[i].nightMode));
out.attribute(null, ATTR_COLOR_TEMPERATURE, Integer.toString(
toWrite[i].colorTemperature));
- out.attribute(null, ATTR_LAST_BRIGHTNESS,
- Integer.toString(toWrite[i].lastBrightness));
+ out.attribute(null, ATTR_LAST_NITS,
+ Float.toString(toWrite[i].lastBrightness));
StringBuilder luxValues = new StringBuilder();
StringBuilder luxTimestamps = new StringBuilder();
for (int j = 0; j < toWrite[i].luxValues.length; ++j) {
@@ -446,8 +459,8 @@ public class BrightnessTracker {
if (TAG_EVENT.equals(tag)) {
BrightnessChangeEvent event = new BrightnessChangeEvent();
- String brightness = parser.getAttributeValue(null, ATTR_BRIGHTNESS);
- event.brightness = Integer.parseInt(brightness);
+ String brightness = parser.getAttributeValue(null, ATTR_NITS);
+ event.brightness = Float.parseFloat(brightness);
String timestamp = parser.getAttributeValue(null, ATTR_TIMESTAMP);
event.timeStamp = Long.parseLong(timestamp);
event.packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
@@ -460,8 +473,8 @@ public class BrightnessTracker {
String colorTemperature =
parser.getAttributeValue(null, ATTR_COLOR_TEMPERATURE);
event.colorTemperature = Integer.parseInt(colorTemperature);
- String lastBrightness = parser.getAttributeValue(null, ATTR_LAST_BRIGHTNESS);
- event.lastBrightness = Integer.parseInt(lastBrightness);
+ String lastBrightness = parser.getAttributeValue(null, ATTR_LAST_NITS);
+ event.lastBrightness = Float.parseFloat(lastBrightness);
String luxValue = parser.getAttributeValue(null, ATTR_LUX);
String luxTimestamp = parser.getAttributeValue(null, ATTR_LUX_TIMESTAMPS);
@@ -582,22 +595,6 @@ public class BrightnessTracker {
}
}
- private final class SettingsObserver extends ContentObserver {
- public SettingsObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (DEBUG) {
- Slog.v(TAG, "settings change " + uri);
- }
- // Self change is based on observer passed to notifyObserver, SettingsProvider
- // passes null so no changes are self changes.
- handleBrightnessChanged();
- }
- }
-
private final class Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -623,6 +620,24 @@ public class BrightnessTracker {
}
}
+ private final class TrackerHandler extends Handler {
+ public TrackerHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_BACKGROUND_START:
+ backgroundStart((float)msg.obj /*initial brightness*/);
+ break;
+ case MSG_BRIGHTNESS_CHANGED:
+ float newBrightness = (float) msg.obj;
+ boolean userInitiatedChange = (msg.arg1 == 1);
+ handleBrightnessChanged(newBrightness, userInitiatedChange);
+ break;
+ }
+ }
+ }
+
@VisibleForTesting
static class Injector {
public void registerSensorListener(Context context,
@@ -638,18 +653,6 @@ public class BrightnessTracker {
sensorManager.unregisterListener(sensorListener);
}
- public void registerBrightnessObserver(ContentResolver resolver,
- ContentObserver settingsObserver) {
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS),
- false, settingsObserver, UserHandle.USER_ALL);
- }
-
- public void unregisterBrightnessObserver(Context context,
- ContentObserver settingsObserver) {
- context.getContentResolver().unregisterContentObserver(settingsObserver);
- }
-
public void registerReceiver(Context context,
BroadcastReceiver receiver, IntentFilter filter) {
context.registerReceiver(receiver, filter);
@@ -664,16 +667,6 @@ public class BrightnessTracker {
return BackgroundThread.getHandler();
}
- public int getSystemIntForUser(ContentResolver resolver, String setting, int defaultValue,
- int userId) {
- return Settings.System.getIntForUser(resolver, setting, defaultValue, userId);
- }
-
- public void putSystemIntForUser(ContentResolver resolver, String setting, int value,
- int userId) {
- Settings.System.putIntForUser(resolver, setting, value, userId);
- }
-
public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue,
int userId) {
return Settings.Secure.getIntForUser(resolver, setting, defaultValue, userId);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 9b97934cfc3b..02e4fe00f893 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -270,8 +270,6 @@ public final class DisplayManagerService extends SystemService {
private final Injector mInjector;
- private final BrightnessTracker mBrightnessTracker;
-
public DisplayManagerService(Context context) {
this(context, new Injector());
}
@@ -290,7 +288,6 @@ public final class DisplayManagerService extends SystemService {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
- mBrightnessTracker = new BrightnessTracker(context, null);
mCurrentUserId = UserHandle.USER_SYSTEM;
}
@@ -1339,9 +1336,6 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mPersistentDataStore.dump(pw);
-
- pw.println();
- mBrightnessTracker.dump(pw);
}
}
@@ -1418,10 +1412,6 @@ public final class DisplayManagerService extends SystemService {
break;
}
- case MSG_REGISTER_BRIGHTNESS_TRACKER:
- mBrightnessTracker.start();
- break;
-
case MSG_LOAD_BRIGHTNESS_CONFIGURATION:
loadBrightnessConfiguration();
break;
@@ -1833,22 +1823,9 @@ public final class DisplayManagerService extends SystemService {
final int userId = UserHandle.getUserId(callingUid);
final long token = Binder.clearCallingIdentity();
try {
- return mBrightnessTracker.getEvents(userId, hasUsageStats);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override // Binder call
- public void setBrightness(int brightness) {
- // STOPSHIP - remove when adaptive brightness controller accepts curves.
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.BRIGHTNESS_SLIDER_USAGE,
- "Permission to set brightness.");
- int userId = UserHandle.getUserId(Binder.getCallingUid());
- final long token = Binder.clearCallingIdentity();
- try {
- mBrightnessTracker.setBrightness(brightness, userId);
+ synchronized (mSyncRoot) {
+ return mDisplayPowerController.getBrightnessEvents(userId, hasUsageStats);
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2028,7 +2005,9 @@ public final class DisplayManagerService extends SystemService {
@Override
public void persistBrightnessSliderEvents() {
- mBrightnessTracker.persistEvents();
+ synchronized (mSyncRoot) {
+ mDisplayPowerController.persistBrightnessSliderEvents();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index a2d954822e64..e5a4b0a78a65 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -24,13 +24,16 @@ import com.android.server.policy.WindowManagerPolicy;
import android.animation.Animator;
import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.Context;
+import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.display.BrightnessChangeEvent;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
@@ -96,7 +99,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static final int MSG_SCREEN_ON_UNBLOCKED = 3;
private static final int MSG_SCREEN_OFF_UNBLOCKED = 4;
private static final int MSG_CONFIGURE_BRIGHTNESS = 5;
- private static final int MSG_USER_SWITCH = 6;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -151,9 +153,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
- // The minimum screen brightness to use in a very dark room.
- private final int mScreenBrightnessDarkConfig;
-
// The minimum allowed brightness.
private final int mScreenBrightnessRangeMinimum;
@@ -261,6 +260,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private long mScreenOnBlockStartRealTime;
private long mScreenOffBlockStartRealTime;
+ // The last brightness that was set by the user and not temporary. Set to -1 when a brightness
+ // has yet to be recorded.
+ private int mLastBrightness;
+ // The last auto brightness adjustment that was set by the user and not temporary. Set to
+ // Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
+ private float mLastAutoBrightnessAdjustment;
+
// Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_SCREEN_* fields.
private int mReportedScreenStateToPolicy;
@@ -289,6 +295,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
+ // The mapper between ambient lux, display backlight values, and display brightness.
+ @Nullable
+ private BrightnessMappingStrategy mBrightnessMapper;
+
// The default brightness configuration. Used for whenever we don't have a valid brightness
// configuration set. This is typically seen with users that don't have a brightness
// configuration that's different from the default.
@@ -302,6 +312,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private ObjectAnimator mColorFadeOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
+ // Tracker for brightness changes
+ private final BrightnessTracker mBrightnessTracker;
+
/**
* Creates the display power controller.
*/
@@ -309,6 +322,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker) {
mHandler = new DisplayControllerHandler(handler.getLooper());
+ mBrightnessTracker = new BrightnessTracker(context, null);
mCallbacks = callbacks;
mBatteryStats = BatteryStatsService.getService();
@@ -327,23 +341,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim));
- mScreenBrightnessDarkConfig = clampAbsoluteBrightness(resources.getInteger(
- com.android.internal.R.integer.config_screenBrightnessDark));
- if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
- Slog.w(TAG, "Expected config_screenBrightnessDark ("
- + mScreenBrightnessDarkConfig + ") to be less than or equal to "
- + "config_screenBrightnessDim (" + mScreenBrightnessDimConfig + ").");
- }
- if (mScreenBrightnessDarkConfig > screenBrightnessSettingMinimum) {
- Slog.w(TAG, "Expected config_screenBrightnessDark ("
- + mScreenBrightnessDarkConfig + ") to be less than or equal to "
- + "config_screenBrightnessSettingMinimum ("
- + screenBrightnessSettingMinimum + ").");
- }
-
- int screenBrightnessRangeMinimum = Math.min(Math.min(
- screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
- mScreenBrightnessDarkConfig);
+ mScreenBrightnessRangeMinimum =
+ Math.min(screenBrightnessSettingMinimum, mScreenBrightnessDimConfig);
mScreenBrightnessRangeMaximum = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMaximum));
@@ -362,18 +361,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
if (mUseSoftwareAutoBrightnessConfig) {
- float[] luxLevels = getLuxLevels(resources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessLevels));
- int[] backlightValues = resources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
- float[] brightnessValuesNits = getFloatArray(resources.obtainTypedArray(
- com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
-
- final float screenMinimumNits = resources.getFloat(
- com.android.internal.R.dimen.config_screenBrightnessMinimumNits);
- final float screenMaximumNits = resources.getFloat(
- com.android.internal.R.dimen.config_screenBrightnessMaximumNits);
-
final float dozeScaleFactor = resources.getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
@@ -413,31 +400,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
+ "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
}
- if (backlightValues != null && backlightValues.length > 0) {
- final int bottom = backlightValues[0];
- if (mScreenBrightnessDarkConfig > bottom) {
- Slog.w(TAG, "config_screenBrightnessDark (" + mScreenBrightnessDarkConfig
- + ") should be less than or equal to the first value of "
- + "config_autoBrightnessLcdBacklightValues ("
- + bottom + ").");
- }
- if (bottom < screenBrightnessRangeMinimum) {
- screenBrightnessRangeMinimum = bottom;
- }
- }
-
- float[] nitsRange = { screenMinimumNits, screenMaximumNits };
- int[] backlightRange = { screenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum };
-
- BrightnessMappingStrategy mapper = BrightnessMappingStrategy.create(
- luxLevels, backlightValues, brightnessValuesNits,
- nitsRange, backlightRange);
- if (mapper != null) {
+ mBrightnessMapper = BrightnessMappingStrategy.create(resources);
+ if (mBrightnessMapper != null) {
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
- handler.getLooper(), sensorManager, mapper, lightSensorWarmUpTimeConfig,
- screenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum,
- dozeScaleFactor, lightSensorRate, initialLightSensorRate,
- brighteningLightDebounce, darkeningLightDebounce,
+ handler.getLooper(), sensorManager, mBrightnessMapper,
+ lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
+ mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
+ initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
autoBrightnessAdjustmentMaxGamma, dynamicHysteresis);
} else {
@@ -445,9 +414,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
- mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
-
-
mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic();
mColorFadeFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
@@ -466,32 +432,32 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
+ mLastBrightness = -1;
+ mLastAutoBrightnessAdjustment = Float.NaN;
}
- private static float[] getLuxLevels(int[] lux) {
- // The first control point is implicit and always at 0 lux.
- float[] levels = new float[lux.length + 1];
- for (int i = 0; i < lux.length; i++) {
- levels[i + 1] = (float) lux[i];
- }
- return levels;
+ /**
+ * Returns true if the proximity sensor screen-off function is available.
+ */
+ public boolean isProximitySensorAvailable() {
+ return mProximitySensor != null;
}
- private static float[] getFloatArray(TypedArray array) {
- final int N = array.length();
- float[] vals = new float[N];
- for (int i = 0; i < N; i++) {
- vals[i] = array.getFloat(i, -1.0f);
- }
- array.recycle();
- return vals;
+ /**
+ * Get the {@link BrightnessChangeEvent}s for the specified user.
+ * @param userId userId to fetch data for
+ * @param includePackage if false will null out the package name in events
+ */
+ public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(
+ @UserIdInt int userId, boolean includePackage) {
+ return mBrightnessTracker.getEvents(userId, includePackage);
}
/**
- * Returns true if the proximity sensor screen-off function is available.
+ * Persist the brightness slider events to disk.
*/
- public boolean isProximitySensorAvailable() {
- return mProximitySensor != null;
+ public void persistBrightnessSliderEvents() {
+ mBrightnessTracker.persistEvents();
}
/**
@@ -588,6 +554,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} catch (RemoteException ex) {
// same process
}
+
+ // Initialize all of the brightness tracking state
+ final float brightness = getNits(mPowerState.getScreenBrightness());
+ if (brightness >= 0.0f) {
+ mBrightnessTracker.start(brightness);
+ }
}
private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
@@ -722,16 +694,32 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
brightness = PowerManager.BRIGHTNESS_OFF;
}
+
+ final boolean autoBrightnessEnabledInDoze =
+ mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
+ final boolean autoBrightnessEnabled = mPowerRequest.useAutoBrightness
+ && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
+ && brightness < 0
+ && mAutomaticBrightnessController != null;
+ final boolean brightnessAdjustmentChanged =
+ !Float.isNaN(mLastAutoBrightnessAdjustment)
+ && mPowerRequest.screenAutoBrightnessAdjustment != mLastAutoBrightnessAdjustment;
+ final boolean brightnessChanged = mLastBrightness >= 0
+ && mPowerRequest.screenBrightness != mLastBrightness;
+
+ // Update the last set brightness values.
+ final boolean userInitiatedChange;
+ if (mPowerRequest.brightnessSetByUser && !mPowerRequest.brightnessIsTemporary) {
+ userInitiatedChange = autoBrightnessEnabled && brightnessAdjustmentChanged
+ || !autoBrightnessEnabled && brightnessChanged;
+ mLastBrightness = mPowerRequest.screenBrightness;
+ mLastAutoBrightnessAdjustment = mPowerRequest.screenAutoBrightnessAdjustment;
+ } else {
+ userInitiatedChange = false;
+ }
+
// Configure auto-brightness.
- boolean autoBrightnessEnabled = false;
if (mAutomaticBrightnessController != null) {
- final boolean autoBrightnessEnabledInDoze =
- mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
- autoBrightnessEnabled = mPowerRequest.useAutoBrightness
- && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
- && brightness < 0;
- final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
- && mPowerRequest.brightnessSetByUser;
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mBrightnessConfiguration, mPowerRequest.screenAutoBrightnessAdjustment,
state != Display.STATE_ON, userInitiatedChange);
@@ -854,6 +842,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
}
+
+ final float brightnessInNits = getNits(brightness);
+ if (!mPowerRequest.brightnessIsTemporary && brightnessInNits >= 0.0f) {
+ // We only want to track changes made by the user and on devices that can actually
+ // map the display backlight values into a physical brightness unit.
+ mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiatedChange);
+ }
}
// Determine whether the display is ready for use in the newly requested state.
@@ -1312,6 +1307,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mHandler.post(mOnStateChangedRunnable);
}
+ private float getNits(int backlight) {
+ if (mBrightnessMapper != null) {
+ return mBrightnessMapper.getNits(backlight);
+ } else {
+ return -1.0f;
+ }
+ }
+
private final Runnable mOnStateChangedRunnable = new Runnable() {
@Override
public void run() {
@@ -1362,7 +1365,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
pw.println("Display Power Controller Configuration:");
pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
- pw.println(" mScreenBrightnessDarkConfig=" + mScreenBrightnessDarkConfig);
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
@@ -1383,7 +1385,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
pw.println("Display Power Controller Thread State:");
pw.println(" mPowerRequest=" + mPowerRequest);
pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
-
pw.println(" mProximitySensor=" + mProximitySensor);
pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
pw.println(" mProximityThreshold=" + mProximityThreshold);
@@ -1392,6 +1393,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
pw.println(" mPendingProximityDebounceTime="
+ TimeUtils.formatUptime(mPendingProximityDebounceTime));
pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
+ pw.println(" mLastBrightness=" + mLastBrightness);
+ pw.println(" mLastAutoBrightnessAdjustment=" + mLastAutoBrightnessAdjustment);
pw.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness);
pw.println(" mAppliedDimming=" + mAppliedDimming);
pw.println(" mAppliedLowPower=" + mAppliedLowPower);
@@ -1420,6 +1423,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mAutomaticBrightnessController.dump(pw);
}
+ if (mBrightnessTracker != null) {
+ pw.println();
+ mBrightnessTracker.dump(pw);
+ }
}
private static String proximityToString(int state) {
diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
index c356b639deba..033437a53891 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
@@ -221,7 +221,7 @@ import java.util.ArrayList;
case Result.NOT_INIT:
return ContextHubTransaction.RESULT_FAILED_UNINITIALIZED;
case Result.TRANSACTION_PENDING:
- return ContextHubTransaction.RESULT_FAILED_PENDING;
+ return ContextHubTransaction.RESULT_FAILED_BUSY;
case Result.TRANSACTION_FAILED:
case Result.UNKNOWN_FAILURE:
default: /* fall through */
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 482acefac3a5..02218ffc14ea 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2026,8 +2026,9 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
- public Map<String, byte[]> recoverKeys(@NonNull String sessionId, @NonNull byte[] recoveryKeyBlob,
- @NonNull List<KeyEntryRecoveryData> applicationKeys, @UserIdInt int userId)
+ public Map<String, byte[]> recoverKeys(@NonNull String sessionId,
+ @NonNull byte[] recoveryKeyBlob, @NonNull List<KeyEntryRecoveryData> applicationKeys,
+ @UserIdInt int userId)
throws RemoteException {
return mRecoverableKeyStoreManager.recoverKeys(
sessionId, recoveryKeyBlob, applicationKeys, userId);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
index bc080be70bcb..e851d8cf21b3 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
@@ -298,8 +298,8 @@ public class KeySyncUtils {
.order(ByteOrder.LITTLE_ENDIAN)
.put(SecureBox.encodePublicKey(thmPublicKey))
.putLong(counterId)
- .putInt(maxAttempts)
.putLong(deviceId)
+ .putInt(maxAttempts)
.array();
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 95f5cb7ae112..a8b8361b4f03 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -88,7 +88,8 @@ public class PlatformKeyManager {
*
* @hide
*/
- public static PlatformKeyManager getInstance(Context context, RecoverableKeyStoreDb database, int userId)
+ public static PlatformKeyManager getInstance(Context context, RecoverableKeyStoreDb database,
+ int userId)
throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException {
context = context.getApplicationContext();
PlatformKeyManager keyManager = new PlatformKeyManager(
@@ -115,16 +116,12 @@ public class PlatformKeyManager {
/**
* Returns the current generation ID of the platform key. This increments whenever a platform
* key has to be replaced. (e.g., because the user has removed and then re-added their lock
- * screen).
+ * screen). Returns -1 if no key has been generated yet.
*
* @hide
*/
public int getGenerationId() {
- int generationId = mDatabase.getPlatformKeyGenerationId(mUserId);
- if (generationId == -1) {
- return 1;
- }
- return generationId;
+ return mDatabase.getPlatformKeyGenerationId(mUserId);
}
/**
@@ -149,7 +146,6 @@ public class PlatformKeyManager {
public void regenerate() throws NoSuchAlgorithmException, KeyStoreException {
int nextId = getGenerationId() + 1;
generateAndLoadKey(nextId);
- setGenerationId(nextId);
}
/**
@@ -207,13 +203,20 @@ public class PlatformKeyManager {
Locale.US, "Platform key generation %d exists already.", generationId));
return;
}
- if (generationId == 1) {
+ if (generationId == -1) {
Log.i(TAG, "Generating initial platform ID.");
} else {
Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no "
+ "entry was present in AndroidKeyStore. Generating fresh key.", generationId));
}
+ if (generationId == -1) {
+ generationId = 1;
+ } else {
+ // Had to generate a fresh key, bump the generation id
+ generationId++;
+ }
+
generateAndLoadKey(generationId);
}
@@ -296,6 +299,8 @@ public class PlatformKeyManager {
.setBoundToSpecificSecureUserId(mUserId)
.build());
+ setGenerationId(generationId);
+
try {
secretKey.destroy();
} catch (DestroyFailedException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index fe1cad4b18ac..eccf241dd47f 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -216,7 +216,6 @@ public class RecoverableKeyStoreManager {
// Any application should be able to check status for its own keys.
// If caller is a recovery agent it can check statuses for other packages, but
// only for recoverable keys it manages.
- checkRecoverKeyStorePermission();
return mDatabase.getStatusForAllKeys(Binder.getCallingUid());
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index 838311e185e8..5ca5da4ead56 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -590,6 +590,7 @@ public class RecoverableKeyStoreDb {
*
* @hide
*/
+ @Nullable
public Long getServerParameters(int userId, int uid) {
SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
index 171703ac8933..f35e6ec92dae 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -33,6 +33,7 @@ import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.net.INetworkWatchlistManager;
@@ -92,6 +93,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
}
}
+ @GuardedBy("mLoggingSwitchLock")
private volatile boolean mIsLoggingEnabled = false;
private final Object mLoggingSwitchLock = new Object();
@@ -220,36 +222,11 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
}
}
- /**
- * Set a new network watchlist.
- * This method should be called by ConfigUpdater only.
- *
- * @return True if network watchlist is updated.
- */
- public boolean setNetworkSecurityWatchlist(List<byte[]> domainsCrc32Digests,
- List<byte[]> domainsSha256Digests,
- List<byte[]> ipAddressesCrc32Digests,
- List<byte[]> ipAddressesSha256Digests) {
- Slog.i(TAG, "Setting network watchlist");
- if (domainsCrc32Digests == null || domainsSha256Digests == null
- || ipAddressesCrc32Digests == null || ipAddressesSha256Digests == null) {
- Slog.e(TAG, "Parameters cannot be null");
- return false;
- }
- if (domainsCrc32Digests.size() != domainsSha256Digests.size()
- || ipAddressesCrc32Digests.size() != ipAddressesSha256Digests.size()) {
- Slog.e(TAG, "Must need to have the same number of CRC32 and SHA256 digests");
- return false;
- }
- if (domainsSha256Digests.size() + ipAddressesSha256Digests.size()
- > MAX_NUM_OF_WATCHLIST_DIGESTS) {
- Slog.e(TAG, "Total watchlist size cannot exceed " + MAX_NUM_OF_WATCHLIST_DIGESTS);
- return false;
- }
- mSettings.writeSettingsToDisk(domainsCrc32Digests, domainsSha256Digests,
- ipAddressesCrc32Digests, ipAddressesSha256Digests);
- Slog.i(TAG, "Set network watchlist: Success");
- return true;
+ @Override
+ public void reloadWatchlist() throws RemoteException {
+ enforceWatchlistLoggingPermission();
+ Slog.i(TAG, "Reloading watchlist");
+ mSettings.reloadSettings();
}
@Override
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
index f48463f5ae63..838aa53938fa 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -21,10 +21,12 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Environment;
import android.util.Pair;
import com.android.internal.util.HexDump;
+import java.io.File;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
@@ -83,9 +85,12 @@ class WatchlistReportDbHelper extends SQLiteOpenHelper {
HashMap<String, String> appDigestCNCList;
}
+ static File getSystemWatchlistDbFile() {
+ return new File(Environment.getDataSystemDirectory(), NAME);
+ }
+
private WatchlistReportDbHelper(Context context) {
- super(context, WatchlistSettings.getSystemWatchlistFile(NAME).getAbsolutePath(),
- null, VERSION);
+ super(context, getSystemWatchlistDbFile().getAbsolutePath(), null, VERSION);
// Memory optimization - close idle connections after 30s of inactivity
setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index c50f0d56c992..70002ea21aff 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -19,8 +19,10 @@ package com.android.server.net.watchlist;
import android.os.Environment;
import android.util.AtomicFile;
import android.util.Log;
+import android.util.Slog;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.HexDump;
@@ -51,10 +53,9 @@ import java.util.zip.CRC32;
class WatchlistSettings {
private static final String TAG = "WatchlistSettings";
- // Settings xml will be stored in /data/system/network_watchlist/watchlist_settings.xml
- static final String SYSTEM_WATCHLIST_DIR = "network_watchlist";
-
- private static final String WATCHLIST_XML_FILE = "watchlist_settings.xml";
+ // Watchlist config that pushed by ConfigUpdater.
+ private static final String NETWORK_WATCHLIST_DB_PATH =
+ "/data/misc/network_watchlist/network_watchlist.xml";
private static class XmlTags {
private static final String WATCHLIST_SETTINGS = "watchlist-settings";
@@ -65,86 +66,74 @@ class WatchlistSettings {
private static final String HASH = "hash";
}
- private static WatchlistSettings sInstance = new WatchlistSettings();
+ private static class CrcShaDigests {
+ final HarmfulDigests crc32Digests;
+ final HarmfulDigests sha256Digests;
+
+ public CrcShaDigests(HarmfulDigests crc32Digests, HarmfulDigests sha256Digests) {
+ this.crc32Digests = crc32Digests;
+ this.sha256Digests = sha256Digests;
+ }
+ }
+
+ private final static WatchlistSettings sInstance = new WatchlistSettings();
private final AtomicFile mXmlFile;
- private final Object mLock = new Object();
- private HarmfulDigests mCrc32DomainDigests = new HarmfulDigests(new ArrayList<>());
- private HarmfulDigests mSha256DomainDigests = new HarmfulDigests(new ArrayList<>());
- private HarmfulDigests mCrc32IpDigests = new HarmfulDigests(new ArrayList<>());
- private HarmfulDigests mSha256IpDigests = new HarmfulDigests(new ArrayList<>());
- public static synchronized WatchlistSettings getInstance() {
+ private volatile CrcShaDigests mDomainDigests;
+ private volatile CrcShaDigests mIpDigests;
+
+ public static WatchlistSettings getInstance() {
return sInstance;
}
private WatchlistSettings() {
- this(getSystemWatchlistFile(WATCHLIST_XML_FILE));
+ this(new File(NETWORK_WATCHLIST_DB_PATH));
}
@VisibleForTesting
protected WatchlistSettings(File xmlFile) {
mXmlFile = new AtomicFile(xmlFile);
- readSettingsLocked();
- }
-
- static File getSystemWatchlistFile(String filename) {
- final File dataSystemDir = Environment.getDataSystemDirectory();
- final File systemWatchlistDir = new File(dataSystemDir, SYSTEM_WATCHLIST_DIR);
- systemWatchlistDir.mkdirs();
- return new File(systemWatchlistDir, filename);
+ reloadSettings();
}
- private void readSettingsLocked() {
- synchronized (mLock) {
- FileInputStream stream;
- try {
- stream = mXmlFile.openRead();
- } catch (FileNotFoundException e) {
- Log.i(TAG, "No watchlist settings: " + mXmlFile.getBaseFile().getAbsolutePath());
- return;
- }
+ public void reloadSettings() {
+ try (FileInputStream stream = mXmlFile.openRead()){
final List<byte[]> crc32DomainList = new ArrayList<>();
final List<byte[]> sha256DomainList = new ArrayList<>();
final List<byte[]> crc32IpList = new ArrayList<>();
final List<byte[]> sha256IpList = new ArrayList<>();
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
- parser.nextTag();
- parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_SETTINGS);
- while (parser.nextTag() == XmlPullParser.START_TAG) {
- String tagName = parser.getName();
- switch (tagName) {
- case XmlTags.CRC32_DOMAIN:
- parseHash(parser, tagName, crc32DomainList);
- break;
- case XmlTags.CRC32_IP:
- parseHash(parser, tagName, crc32IpList);
- break;
- case XmlTags.SHA256_DOMAIN:
- parseHash(parser, tagName, sha256DomainList);
- break;
- case XmlTags.SHA256_IP:
- parseHash(parser, tagName, sha256IpList);
- break;
- default:
- Log.w(TAG, "Unknown element: " + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
- parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_SETTINGS);
- writeSettingsToMemory(crc32DomainList, sha256DomainList, crc32IpList, sha256IpList);
- } catch (IllegalStateException | NullPointerException | NumberFormatException |
- XmlPullParserException | IOException | IndexOutOfBoundsException e) {
- Log.w(TAG, "Failed parsing " + e);
- } finally {
- try {
- stream.close();
- } catch (IOException e) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ parser.nextTag();
+ parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ switch (tagName) {
+ case XmlTags.CRC32_DOMAIN:
+ parseHash(parser, tagName, crc32DomainList);
+ break;
+ case XmlTags.CRC32_IP:
+ parseHash(parser, tagName, crc32IpList);
+ break;
+ case XmlTags.SHA256_DOMAIN:
+ parseHash(parser, tagName, sha256DomainList);
+ break;
+ case XmlTags.SHA256_IP:
+ parseHash(parser, tagName, sha256IpList);
+ break;
+ default:
+ Log.w(TAG, "Unknown element: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
}
}
+ parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+ writeSettingsToMemory(crc32DomainList, sha256DomainList, crc32IpList, sha256IpList);
+ Log.i(TAG, "Reload watchlist done");
+ } catch (IllegalStateException | NullPointerException | NumberFormatException |
+ XmlPullParserException | IOException | IndexOutOfBoundsException e) {
+ Slog.e(TAG, "Failed parsing xml", e);
}
}
@@ -161,101 +150,61 @@ class WatchlistSettings {
}
/**
- * Write network watchlist settings to disk.
- * Adb should not use it, should use writeSettingsToMemory directly instead.
- */
- public void writeSettingsToDisk(List<byte[]> newCrc32DomainList,
- List<byte[]> newSha256DomainList,
- List<byte[]> newCrc32IpList,
- List<byte[]> newSha256IpList) {
- synchronized (mLock) {
- FileOutputStream stream;
- try {
- stream = mXmlFile.startWrite();
- } catch (IOException e) {
- Log.w(TAG, "Failed to write display settings: " + e);
- return;
- }
-
- try {
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(stream, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
- out.startTag(null, XmlTags.WATCHLIST_SETTINGS);
-
- writeHashSetToXml(out, XmlTags.SHA256_DOMAIN, newSha256DomainList);
- writeHashSetToXml(out, XmlTags.SHA256_IP, newSha256IpList);
- writeHashSetToXml(out, XmlTags.CRC32_DOMAIN, newCrc32DomainList);
- writeHashSetToXml(out, XmlTags.CRC32_IP, newCrc32IpList);
-
- out.endTag(null, XmlTags.WATCHLIST_SETTINGS);
- out.endDocument();
- mXmlFile.finishWrite(stream);
- writeSettingsToMemory(newCrc32DomainList, newSha256DomainList, newCrc32IpList,
- newSha256IpList);
- } catch (IOException e) {
- Log.w(TAG, "Failed to write display settings, restoring backup.", e);
- mXmlFile.failWrite(stream);
- }
- }
- }
-
- /**
* Write network watchlist settings to memory.
*/
public void writeSettingsToMemory(List<byte[]> newCrc32DomainList,
List<byte[]> newSha256DomainList,
List<byte[]> newCrc32IpList,
List<byte[]> newSha256IpList) {
- synchronized (mLock) {
- mCrc32DomainDigests = new HarmfulDigests(newCrc32DomainList);
- mCrc32IpDigests = new HarmfulDigests(newCrc32IpList);
- mSha256DomainDigests = new HarmfulDigests(newSha256DomainList);
- mSha256IpDigests = new HarmfulDigests(newSha256IpList);
- }
- }
-
- private static void writeHashSetToXml(XmlSerializer out, String tagName, List<byte[]> hashSet)
- throws IOException {
- out.startTag(null, tagName);
- for (byte[] hash : hashSet) {
- out.startTag(null, XmlTags.HASH);
- out.text(HexDump.toHexString(hash));
- out.endTag(null, XmlTags.HASH);
- }
- out.endTag(null, tagName);
+ mDomainDigests = new CrcShaDigests(new HarmfulDigests(newCrc32DomainList),
+ new HarmfulDigests(newSha256DomainList));
+ mIpDigests = new CrcShaDigests(new HarmfulDigests(newCrc32IpList),
+ new HarmfulDigests(newSha256IpList));
}
public boolean containsDomain(String domain) {
+ final CrcShaDigests domainDigests = mDomainDigests;
+ if (domainDigests == null) {
+ Slog.wtf(TAG, "domainDigests should not be null");
+ return false;
+ }
// First it does a quick CRC32 check.
final byte[] crc32 = getCrc32(domain);
- if (!mCrc32DomainDigests.contains(crc32)) {
+ if (!domainDigests.crc32Digests.contains(crc32)) {
return false;
}
// Now we do a slow SHA256 check.
final byte[] sha256 = getSha256(domain);
- return mSha256DomainDigests.contains(sha256);
+ return domainDigests.sha256Digests.contains(sha256);
}
public boolean containsIp(String ip) {
+ final CrcShaDigests ipDigests = mIpDigests;
+ if (ipDigests == null) {
+ Slog.wtf(TAG, "ipDigests should not be null");
+ return false;
+ }
// First it does a quick CRC32 check.
final byte[] crc32 = getCrc32(ip);
- if (!mCrc32IpDigests.contains(crc32)) {
+ if (!ipDigests.crc32Digests.contains(crc32)) {
return false;
}
// Now we do a slow SHA256 check.
final byte[] sha256 = getSha256(ip);
- return mSha256IpDigests.contains(sha256);
+ return ipDigests.sha256Digests.contains(sha256);
}
- /** Get CRC32 of a string */
+ /** Get CRC32 of a string
+ *
+ * TODO: Review if we should use CRC32 or other algorithms
+ */
private byte[] getCrc32(String str) {
final CRC32 crc = new CRC32();
crc.update(str.getBytes());
final long tmp = crc.getValue();
- return new byte[]{(byte)(tmp >> 24 & 255), (byte)(tmp >> 16 & 255),
- (byte)(tmp >> 8 & 255), (byte)(tmp & 255)};
+ return new byte[]{(byte) (tmp >> 24 & 255), (byte) (tmp >> 16 & 255),
+ (byte) (tmp >> 8 & 255), (byte) (tmp & 255)};
}
/** Get SHA256 of a string */
@@ -273,12 +222,12 @@ class WatchlistSettings {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Domain CRC32 digest list:");
- mCrc32DomainDigests.dump(fd, pw, args);
+ mDomainDigests.crc32Digests.dump(fd, pw, args);
pw.println("Domain SHA256 digest list:");
- mSha256DomainDigests.dump(fd, pw, args);
+ mDomainDigests.sha256Digests.dump(fd, pw, args);
pw.println("Ip CRC32 digest list:");
- mCrc32IpDigests.dump(fd, pw, args);
+ mIpDigests.crc32Digests.dump(fd, pw, args);
pw.println("Ip SHA256 digest list:");
- mSha256IpDigests.dump(fd, pw, args);
+ mIpDigests.sha256Digests.dump(fd, pw, args);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 696d89575e2d..2d55698a22fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -163,10 +163,12 @@ import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManager.PackageInfoFlags;
+import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser.Package;
@@ -757,6 +759,9 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mPackages")
final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
+ @GuardedBy("mPackages")
+ final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
+
class PackageParserCallback implements PackageParser.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -2095,6 +2100,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ if (allNewUsers && !update) {
+ notifyPackageAdded(packageName);
+ }
+
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
@@ -12983,6 +12992,34 @@ public class PackageManagerService extends IPackageManager.Stub
});
}
+ @Override
+ public void notifyPackageAdded(String packageName) {
+ final PackageListObserver[] observers;
+ synchronized (mPackages) {
+ if (mPackageListObservers.size() == 0) {
+ return;
+ }
+ observers = (PackageListObserver[]) mPackageListObservers.toArray();
+ }
+ for (int i = observers.length - 1; i >= 0; --i) {
+ observers[i].onPackageAdded(packageName);
+ }
+ }
+
+ @Override
+ public void notifyPackageRemoved(String packageName) {
+ final PackageListObserver[] observers;
+ synchronized (mPackages) {
+ if (mPackageListObservers.size() == 0) {
+ return;
+ }
+ observers = (PackageListObserver[]) mPackageListObservers.toArray();
+ }
+ for (int i = observers.length - 1; i >= 0; --i) {
+ observers[i].onPackageRemoved(packageName);
+ }
+ }
+
/**
* Sends a broadcast for the given action.
* <p>If {@code isInstantApp} is {@code true}, then the broadcast is protected with
@@ -17640,6 +17677,7 @@ public class PackageManagerService extends IPackageManager.Stub
removedPackage, extras,
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
null, null, broadcastUsers, instantUserIds);
+ packageSender.notifyPackageRemoved(removedPackage);
}
}
if (removedAppId >= 0) {
@@ -20395,10 +20433,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
sUserManager.systemReady();
-
// If we upgraded grant all default permissions before kicking off.
for (int userId : grantPermissionsUserIds) {
- mDefaultPermissionPolicy.grantDefaultPermissions(mPackages.values(), userId);
+ mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}
if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
@@ -22445,8 +22482,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
void onNewUserCreated(final int userId) {
+ mDefaultPermissionPolicy.grantDefaultPermissions(userId);
synchronized(mPackages) {
- mDefaultPermissionPolicy.grantDefaultPermissions(mPackages.values(), userId);
// If permission review for legacy apps is required, we represent
// dagerous permissions for such apps as always granted runtime
// permissions to keep per user flag state whether review is needed.
@@ -22933,6 +22970,29 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
@Override
+ public PackageList getPackageList(PackageListObserver observer) {
+ synchronized (mPackages) {
+ final int N = mPackages.size();
+ final ArrayList<String> list = new ArrayList<>(N);
+ for (int i = 0; i < N; i++) {
+ list.add(mPackages.keyAt(i));
+ }
+ final PackageList packageList = new PackageList(list, observer);
+ if (observer != null) {
+ mPackageListObservers.add(packageList);
+ }
+ return packageList;
+ }
+ }
+
+ @Override
+ public void removePackageListObserver(PackageListObserver observer) {
+ synchronized (mPackages) {
+ mPackageListObservers.remove(observer);
+ }
+ }
+
+ @Override
public PackageParser.Package getDisabledPackage(String packageName) {
synchronized (mPackages) {
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
@@ -22989,6 +23049,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
@Override
+ public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setUseOpenWifiAppPackagesProvider(provider);
+ }
+
+ @Override
public void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider) {
mDefaultPermissionPolicy.setSyncAdapterPackagesProvider(provider);
}
@@ -23013,6 +23078,12 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
@Override
+ public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultUseOpenWifiApp(
+ packageName, userId);
+ }
+
+ @Override
public void setKeepUninstalledPackages(final List<String> packageList) {
Preconditions.checkNotNull(packageList);
List<String> removedFromList = null;
@@ -23594,4 +23665,6 @@ interface PackageSender {
final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds);
void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
+ void notifyPackageAdded(String packageName);
+ void notifyPackageRemoved(String packageName);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 648f847ac3c5..4cf18149d853 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3122,7 +3122,7 @@ public final class Settings {
ATTR_VOLUME_UUID);
final VersionInfo ver = findOrCreateVersion(volumeUuid);
ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
- ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
+ ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_DATABASE_VERSION);
ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 768eb8f37549..c3dce3133026 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,7 +27,6 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
-import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.KeyguardManager;
@@ -795,12 +794,7 @@ public class UserManagerService extends IUserManager.Stub {
"target should only be specified when we are disabling quiet mode.");
}
- if (!isAllowedToSetWorkMode(callingPackage, Binder.getCallingUid())) {
- throw new SecurityException("Not allowed to call trySetQuietModeEnabled, "
- + "caller is foreground default launcher "
- + "nor with MANAGE_USERS/MODIFY_QUIET_MODE permission");
- }
-
+ ensureCanModifyQuietMode(callingPackage, Binder.getCallingUid(), target != null);
final long identity = Binder.clearCallingIdentity();
try {
if (enableQuietMode) {
@@ -824,35 +818,44 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
- * An app can modify quiet mode if the caller meets one of the condition:
+ * The caller can modify quiet mode if it meets one of these conditions:
* <ul>
* <li>Has system UID or root UID</li>
* <li>Has {@link Manifest.permission#MODIFY_QUIET_MODE}</li>
* <li>Has {@link Manifest.permission#MANAGE_USERS}</li>
* </ul>
+ * <p>
+ * If caller wants to start an intent after disabling the quiet mode, it must has
+ * {@link Manifest.permission#MANAGE_USERS}.
*/
- private boolean isAllowedToSetWorkMode(String callingPackage, int callingUid) {
+ private void ensureCanModifyQuietMode(String callingPackage, int callingUid,
+ boolean startIntent) {
if (hasManageUsersPermission()) {
- return true;
+ return;
+ }
+ if (startIntent) {
+ throw new SecurityException("MANAGE_USERS permission is required to start intent "
+ + "after disabling quiet mode.");
}
-
final boolean hasModifyQuietModePermission = ActivityManager.checkComponentPermission(
Manifest.permission.MODIFY_QUIET_MODE,
callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
if (hasModifyQuietModePermission) {
- return true;
+ return;
}
+ verifyCallingPackage(callingPackage, callingUid);
final ShortcutServiceInternal shortcutInternal =
LocalServices.getService(ShortcutServiceInternal.class);
if (shortcutInternal != null) {
boolean isForegroundLauncher =
shortcutInternal.isForegroundDefaultLauncher(callingPackage, callingUid);
if (isForegroundLauncher) {
- return true;
+ return;
}
}
- return false;
+ throw new SecurityException("Can't modify quiet mode, caller is neither foreground "
+ + "default launcher nor has MANAGE_USERS/MODIFY_QUIET_MODE permission");
}
private void setQuietModeEnabled(
@@ -3932,4 +3935,16 @@ public class UserManagerService extends IUserManager.Stub {
return false;
}
}
+
+ /**
+ * Check if the calling package name matches with the calling UID, throw
+ * {@link SecurityException} if not.
+ */
+ private void verifyCallingPackage(String callingPackage, int callingUid) {
+ int packageUid = mPm.getPackageUid(callingPackage, 0, UserHandle.getUserId(callingUid));
+ if (packageUid != callingUid) {
+ throw new SecurityException("Specified package " + callingPackage
+ + " does not match the calling uid " + callingUid);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 01f3c576f72b..34c3ce359e86 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -30,6 +30,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
@@ -134,6 +135,11 @@ public final class DefaultPermissionGrantPolicy {
LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
+ private static final Set<String> COARSE_LOCATION_PERMISSIONS = new ArraySet<>();
+ static {
+ COARSE_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
+ }
+
private static final Set<String> CALENDAR_PERMISSIONS = new ArraySet<>();
static {
CALENDAR_PERMISSIONS.add(Manifest.permission.READ_CALENDAR);
@@ -182,6 +188,7 @@ public final class DefaultPermissionGrantPolicy {
private PackagesProvider mSmsAppPackagesProvider;
private PackagesProvider mDialerAppPackagesProvider;
private PackagesProvider mSimCallManagerPackagesProvider;
+ private PackagesProvider mUseOpenWifiAppPackagesProvider;
private SyncAdapterPackagesProvider mSyncAdapterPackagesProvider;
private ArrayMap<String, List<DefaultPermissionGrant>> mGrantExceptions;
@@ -246,17 +253,23 @@ public final class DefaultPermissionGrantPolicy {
}
}
+ public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
+ synchronized (mLock) {
+ mUseOpenWifiAppPackagesProvider = provider;
+ }
+ }
+
public void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider) {
synchronized (mLock) {
mSyncAdapterPackagesProvider = provider;
}
}
- public void grantDefaultPermissions(Collection<PackageParser.Package> packages, int userId) {
+ public void grantDefaultPermissions(int userId) {
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) {
- grantAllRuntimePermissions(packages, userId);
+ grantAllRuntimePermissions(userId);
} else {
- grantPermissionsToSysComponentsAndPrivApps(packages, userId);
+ grantPermissionsToSysComponentsAndPrivApps(userId);
grantDefaultSystemHandlerPermissions(userId);
grantDefaultPermissionExceptions(userId);
}
@@ -278,10 +291,14 @@ public final class DefaultPermissionGrantPolicy {
}
}
- private void grantAllRuntimePermissions(
- Collection<PackageParser.Package> packages, int userId) {
+ private void grantAllRuntimePermissions(int userId) {
Log.i(TAG, "Granting all runtime permissions for user " + userId);
- for (PackageParser.Package pkg : packages) {
+ final PackageList packageList = mServiceInternal.getPackageList();
+ for (String packageName : packageList.getPackageNames()) {
+ final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
+ if (pkg == null) {
+ continue;
+ }
grantRuntimePermissionsForPackage(userId, pkg);
}
}
@@ -290,10 +307,14 @@ public final class DefaultPermissionGrantPolicy {
mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
}
- private void grantPermissionsToSysComponentsAndPrivApps(
- Collection<PackageParser.Package> packages, int userId) {
+ private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
Log.i(TAG, "Granting permissions to platform components for user " + userId);
- for (PackageParser.Package pkg : packages) {
+ final PackageList packageList = mServiceInternal.getPackageList();
+ for (String packageName : packageList.getPackageNames()) {
+ final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
+ if (pkg == null) {
+ continue;
+ }
if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
|| !doesPackageSupportRuntimePermissions(pkg)
|| pkg.requestedPermissions.isEmpty()) {
@@ -311,6 +332,7 @@ public final class DefaultPermissionGrantPolicy {
final PackagesProvider smsAppPackagesProvider;
final PackagesProvider dialerAppPackagesProvider;
final PackagesProvider simCallManagerPackagesProvider;
+ final PackagesProvider useOpenWifiAppPackagesProvider;
final SyncAdapterPackagesProvider syncAdapterPackagesProvider;
synchronized (mLock) {
@@ -319,6 +341,7 @@ public final class DefaultPermissionGrantPolicy {
smsAppPackagesProvider = mSmsAppPackagesProvider;
dialerAppPackagesProvider = mDialerAppPackagesProvider;
simCallManagerPackagesProvider = mSimCallManagerPackagesProvider;
+ useOpenWifiAppPackagesProvider = mUseOpenWifiAppPackagesProvider;
syncAdapterPackagesProvider = mSyncAdapterPackagesProvider;
}
@@ -332,6 +355,8 @@ public final class DefaultPermissionGrantPolicy {
? dialerAppPackagesProvider.getPackages(userId) : null;
String[] simCallManagerPackageNames = (simCallManagerPackagesProvider != null)
? simCallManagerPackagesProvider.getPackages(userId) : null;
+ String[] useOpenWifiAppPackageNames = (useOpenWifiAppPackagesProvider != null)
+ ? useOpenWifiAppPackagesProvider.getPackages(userId) : null;
String[] contactsSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
syncAdapterPackagesProvider.getPackages(ContactsContract.AUTHORITY, userId) : null;
String[] calendarSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
@@ -449,6 +474,18 @@ public final class DefaultPermissionGrantPolicy {
}
}
+ // Use Open Wifi
+ if (useOpenWifiAppPackageNames != null) {
+ for (String useOpenWifiPackageName : useOpenWifiAppPackageNames) {
+ PackageParser.Package useOpenWifiPackage =
+ getSystemPackage(useOpenWifiPackageName);
+ if (useOpenWifiPackage != null) {
+ grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(useOpenWifiPackage,
+ userId);
+ }
+ }
+ }
+
// SMS
if (smsAppPackageNames == null) {
Intent smsIntent = new Intent(Intent.ACTION_MAIN);
@@ -818,6 +855,13 @@ public final class DefaultPermissionGrantPolicy {
}
}
+ private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
+ PackageParser.Package useOpenWifiPackage, int userId) {
+ if (doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
+ grantRuntimePermissions(useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, userId);
+ }
+ }
+
public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default sms app for user:" + userId);
if (packageName == null) {
@@ -850,6 +894,19 @@ public final class DefaultPermissionGrantPolicy {
}
}
+ public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
+ Log.i(TAG, "Granting permissions to default Use Open WiFi app for user:" + userId);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package useOpenWifiPackage = getPackage(packageName);
+ if (useOpenWifiPackage != null
+ && doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
+ grantRuntimePermissions(
+ useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, false, true, userId);
+ }
+ }
+
private void grantDefaultPermissionsToDefaultSimCallManager(
PackageParser.Package simCallManagerPackage, int userId) {
Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
@@ -1005,7 +1062,7 @@ public final class DefaultPermissionGrantPolicy {
}
private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
- boolean systemFixed, boolean isDefaultPhoneOrSms, int userId) {
+ boolean systemFixed, boolean ignoreSystemPackage, int userId) {
if (pkg.requestedPermissions.isEmpty()) {
return;
}
@@ -1013,13 +1070,13 @@ public final class DefaultPermissionGrantPolicy {
List<String> requestedPermissions = pkg.requestedPermissions;
Set<String> grantablePermissions = null;
- // If this is the default Phone or SMS app we grant permissions regardless
- // whether the version on the system image declares the permission as used since
- // selecting the app as the default Phone or SMS the user makes a deliberate
+ // In some cases, like for the Phone or SMS app, we grant permissions regardless
+ // of if the version on the system image declares the permission as used since
+ // selecting the app as the default for that function the user makes a deliberate
// choice to grant this app the permissions needed to function. For all other
// apps, (default grants on first boot and user creation) we don't grant default
// permissions if the version on the system image does not declare them.
- if (!isDefaultPhoneOrSms && pkg.isUpdatedSystemApp()) {
+ if (!ignoreSystemPackage && pkg.isUpdatedSystemApp()) {
final PackageParser.Package disabledPkg =
mServiceInternal.getDisabledPackage(pkg.packageName);
if (disabledPkg != null) {
@@ -1053,7 +1110,7 @@ public final class DefaultPermissionGrantPolicy {
// Unless the caller wants to override user choices. The override is
// to make sure we can grant the needed permission to the default
// sms and phone apps after the user chooses this in the UI.
- if (flags == 0 || isDefaultPhoneOrSms) {
+ if (flags == 0 || ignoreSystemPackage) {
// Never clobber policy or system.
final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 02c8f681e7c4..86b22bb9c219 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -57,6 +57,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
@@ -1976,6 +1977,16 @@ public final class PowerManagerService extends SystemService
return true;
}
}
+
+ final ArrayList<WorkChain> workChains = wakeLock.mWorkSource.getWorkChains();
+ if (workChains != null) {
+ for (int k = 0; k < workChains.size(); k++) {
+ final int uid = workChains.get(k).getAttributionUid();
+ if (userId == UserHandle.getUserId(uid)) {
+ return true;
+ }
+ }
+ }
}
return userId == UserHandle.getUserId(wakeLock.mOwnerUid);
}
@@ -2441,6 +2452,7 @@ public final class PowerManagerService extends SystemService
float screenAutoBrightnessAdjustment = 0.0f;
boolean autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ boolean brightnessIsTemporary = false;
if (!mBootCompleted) {
// Keep the brightness steady during boot. This requires the
// bootloader brightness and the default brightness to be identical.
@@ -2455,6 +2467,7 @@ public final class PowerManagerService extends SystemService
brightnessSetByUser = false;
} else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
screenBrightness = mTemporaryScreenBrightnessSettingOverride;
+ brightnessIsTemporary = true;
} else if (isValidBrightness(mScreenBrightnessSetting)) {
screenBrightness = mScreenBrightnessSetting;
}
@@ -2464,6 +2477,7 @@ public final class PowerManagerService extends SystemService
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
screenAutoBrightnessAdjustment =
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
+ brightnessIsTemporary = true;
} else if (isValidAutoBrightnessAdjustment(
mScreenAutoBrightnessAdjustmentSetting)) {
screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
@@ -2479,6 +2493,7 @@ public final class PowerManagerService extends SystemService
mDisplayPowerRequest.screenAutoBrightnessAdjustment =
screenAutoBrightnessAdjustment;
mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
+ mDisplayPowerRequest.brightnessIsTemporary = brightnessIsTemporary;
mDisplayPowerRequest.useAutoBrightness = autoBrightness;
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
diff --git a/services/core/java/com/android/server/updates/NetworkWatchlistInstallReceiver.java b/services/core/java/com/android/server/updates/NetworkWatchlistInstallReceiver.java
new file mode 100644
index 000000000000..3b7ddc2e803f
--- /dev/null
+++ b/services/core/java/com/android/server/updates/NetworkWatchlistInstallReceiver.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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.
+ */
+
+package com.android.server.updates;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkWatchlistManager;
+import android.os.RemoteException;
+import android.util.Slog;
+
+public class NetworkWatchlistInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ public NetworkWatchlistInstallReceiver() {
+ super("/data/misc/network_watchlist/", "network_watchlist.xml", "metadata/", "version");
+ }
+
+ @Override
+ protected void postInstall(Context context, Intent intent) {
+ try {
+ context.getSystemService(NetworkWatchlistManager.class).reloadWatchlist();
+ } catch (Exception e) {
+ // Network Watchlist is not available
+ Slog.wtf("NetworkWatchlistInstallReceiver", "Unable to reload watchlist");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index b86cd50dc922..c16a5315060f 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -139,7 +139,7 @@ class AppWindowThumbnail implements Animatable {
@Override
public Builder makeAnimationLeash() {
- return mAppToken.makeSurface().setParent(mAppToken.getAppAnimationLayer());
+ return mAppToken.makeSurface();
}
@Override
@@ -148,6 +148,11 @@ class AppWindowThumbnail implements Animatable {
}
@Override
+ public SurfaceControl getAnimationLeashParent() {
+ return mAppToken.getAppAnimationLayer();
+ }
+
+ @Override
public SurfaceControl getParentSurfaceControl() {
return mAppToken.getParentSurfaceControl();
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 44d7948b12b6..dcd88dd074d1 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+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.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
@@ -53,6 +56,7 @@ import static com.android.server.wm.proto.AppWindowTokenProto.WINDOW_TOKEN;
import android.annotation.CallSuper;
import android.app.Activity;
+import android.app.WindowConfiguration.WindowingMode;
import android.content.res.Configuration;
import android.graphics.GraphicBuffer;
import android.graphics.Point;
@@ -1211,6 +1215,30 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
@Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ final int prevWinMode = getWindowingMode();
+ super.onConfigurationChanged(newParentConfig);
+ final int winMode = getWindowingMode();
+
+ if (prevWinMode == winMode) {
+ return;
+ }
+
+ if (prevWinMode != WINDOWING_MODE_UNDEFINED && winMode == WINDOWING_MODE_PINNED) {
+ // Entering PiP from fullscreen, reset the snap fraction
+ mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
+ } else if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED) {
+ // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds
+ // for the next re-entry into PiP (assuming the activity is not hidden or destroyed)
+ final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
+ if (pinnedStack != null) {
+ mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this,
+ pinnedStack.mPreAnimationBounds);
+ }
+ }
+ }
+
+ @Override
void checkAppWindowsReadyToShow() {
if (allDrawn == mLastAllDrawn) {
return;
@@ -1512,9 +1540,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
@Override
- public SurfaceControl.Builder makeAnimationLeash() {
- return super.makeAnimationLeash()
- .setParent(getAppAnimationLayer());
+ public SurfaceControl getAnimationLeashParent() {
+ return getAppAnimationLayer();
}
boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
@@ -1541,6 +1568,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (stack != null) {
stack.getRelativePosition(mTmpPoint);
stack.getBounds(mTmpRect);
+ mTmpRect.offsetTo(0, 0);
}
final AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
@@ -1837,6 +1865,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
@Override
void setHidden(boolean hidden) {
super.setHidden(hidden);
+
+ if (hidden) {
+ // Once the app window is hidden, reset the last saved PiP snap fraction
+ mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
+ }
scheduleAnimation();
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d053015cea82..63dfbc2c25b6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1923,6 +1923,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mService.unregisterPointerEventListener(mService.mMousePositionTracker);
}
}
+ mService.mAnimator.removeDisplayLocked(mDisplayId);
+
// The pending transaction won't be applied so we should
// just clean up any surfaces pending destruction.
onPendingTransactionApplied();
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index d8726bfc2c20..69cbe4607cf1 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -48,6 +48,7 @@ import com.android.internal.policy.PipSnapAlgorithm;
import com.android.server.UiThread;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -71,6 +72,7 @@ class PinnedStackController {
private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
+ public static final float INVALID_SNAP_FRACTION = -1f;
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
private final Handler mHandler = UiThread.getHandler();
@@ -101,6 +103,8 @@ class PinnedStackController {
private float mDefaultAspectRatio;
private Point mScreenEdgeInsets;
private int mCurrentMinSize;
+ private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
+ private WeakReference<AppWindowToken> mLastPipActivity = null;
// The aspect ratio bounds of the PIP.
private float mMinAspectRatio;
@@ -113,6 +117,7 @@ class PinnedStackController {
private final Rect mTmpAnimatingBoundsRect = new Rect();
private final Point mTmpDisplaySize = new Point();
+
/**
* The callback object passed to listeners for them to notify the controller of state changes.
*/
@@ -250,9 +255,35 @@ class PinnedStackController {
}
/**
+ * Saves the current snap fraction for re-entry of the current activity into PiP.
+ */
+ void saveReentrySnapFraction(final AppWindowToken token, final Rect stackBounds) {
+ mReentrySnapFraction = getSnapFraction(stackBounds);
+ mLastPipActivity = new WeakReference<>(token);
+ }
+
+ /**
+ * Resets the last saved snap fraction so that the default bounds will be returned.
+ */
+ void resetReentrySnapFraction(AppWindowToken token) {
+ if (mLastPipActivity != null && mLastPipActivity.get() == token) {
+ mReentrySnapFraction = INVALID_SNAP_FRACTION;
+ mLastPipActivity = null;
+ }
+ }
+
+ /**
* @return the default bounds to show the PIP when there is no active PIP.
*/
- Rect getDefaultBounds() {
+ Rect getDefaultOrLastSavedBounds() {
+ return getDefaultBounds(mReentrySnapFraction);
+ }
+
+ /**
+ * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
+ * will apply the default bounds to the provided snap fraction.
+ */
+ Rect getDefaultBounds(float snapFraction) {
synchronized (mService.mWindowMap) {
final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
@@ -260,8 +291,14 @@ class PinnedStackController {
final Rect defaultBounds = new Rect();
final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
- Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
- 0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
+ if (snapFraction != INVALID_SNAP_FRACTION) {
+ defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
+ final Rect movementBounds = getMovementBounds(defaultBounds);
+ mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
+ } else {
+ Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
+ 0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
+ }
return defaultBounds;
}
}
@@ -299,9 +336,7 @@ class PinnedStackController {
final Rect postChangeStackBounds = mTmpRect;
// Calculate the snap fraction of the current stack along the old movement bounds
- final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds);
- final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds,
- preChangeMovementBounds);
+ final float snapFraction = getSnapFraction(postChangeStackBounds);
mDisplayInfo.copyFrom(displayInfo);
// Calculate the stack bounds in the new orientation to the same same fraction along the
@@ -414,7 +449,7 @@ class PinnedStackController {
try {
final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
- final Rect normalBounds = getDefaultBounds();
+ final Rect normalBounds = getDefaultBounds(INVALID_SNAP_FRACTION);
if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
transformBoundsToAspectRatio(normalBounds, mAspectRatio,
false /* useCurrentMinEdgeSize */);
@@ -486,6 +521,14 @@ class PinnedStackController {
}
/**
+ * @return the default snap fraction to apply instead of the default gravity when calculating
+ * the default stack bounds when first entering PiP.
+ */
+ private float getSnapFraction(Rect stackBounds) {
+ return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
+ }
+
+ /**
* @return the pixels for a given dp value.
*/
private int dpToPx(float dpValue, DisplayMetrics dm) {
@@ -494,7 +537,8 @@ class PinnedStackController {
void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "PinnedStackController");
- pw.print(prefix + " defaultBounds="); getDefaultBounds().printShortString(pw);
+ pw.print(prefix + " defaultBounds=");
+ getDefaultBounds(INVALID_SNAP_FRACTION).printShortString(pw);
pw.println();
mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
pw.print(prefix + " movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
@@ -516,7 +560,7 @@ class PinnedStackController {
void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- getDefaultBounds().writeToProto(proto, DEFAULT_BOUNDS);
+ getDefaultBounds(INVALID_SNAP_FRACTION).writeToProto(proto, DEFAULT_BOUNDS);
mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
getMovementBounds(mTmpRect).writeToProto(proto, MOVEMENT_BOUNDS);
proto.end(token);
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index b021a7223e2e..02fbfba9d332 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -61,7 +61,7 @@ public class PinnedStackWindowController extends StackWindowController {
displayContent.getPinnedStackController();
if (stackBounds == null) {
// Calculate the aspect ratio bounds from the default bounds
- stackBounds = pinnedStackController.getDefaultBounds();
+ stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
}
if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
@@ -173,7 +173,7 @@ public class PinnedStackWindowController extends StackWindowController {
* from fullscreen to non-fullscreen bounds.
*/
public boolean deferScheduleMultiWindowModeChanged() {
- synchronized(mWindowMap) {
+ synchronized (mWindowMap) {
return mContainer.deferScheduleMultiWindowModeChanged();
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index bda5bc954103..a32e711df534 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -72,23 +72,29 @@ class SurfaceAnimator {
target.mInnerAnimationFinishedCallback.onAnimationFinished(anim);
return;
}
- if (anim != mAnimation) {
- // Callback was from another animation - ignore.
- return;
- }
- final Transaction t = new Transaction();
- SurfaceControl.openTransaction();
- try {
- reset(t, true /* destroyLeash */);
- animationFinishedCallback.run();
- } finally {
- // TODO: This should use pendingTransaction eventually, but right now things
- // happening on the animation finished callback are happening on the global
- // transaction.
- SurfaceControl.mergeToGlobalTransaction(t);
- SurfaceControl.closeTransaction();
- }
+ // TODO: This should use pendingTransaction eventually, but right now things
+ // happening on the animation finished callback are happening on the global
+ // transaction.
+ // For now we need to run this after it's guaranteed that the transaction that
+ // reparents the surface onto the leash is executed already. Otherwise this may be
+ // executed first, leading to surface loss, as the reparent operations wouldn't
+ // be in order.
+ mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
+ if (anim != mAnimation) {
+ // Callback was from another animation - ignore.
+ return;
+ }
+ final Transaction t = new Transaction();
+ SurfaceControl.openTransaction();
+ try {
+ reset(t, true /* destroyLeash */);
+ animationFinishedCallback.run();
+ } finally {
+ SurfaceControl.mergeToGlobalTransaction(t);
+ SurfaceControl.closeTransaction();
+ }
+ });
}
};
}
@@ -213,7 +219,7 @@ class SurfaceAnimator {
return;
}
final SurfaceControl surface = mAnimatable.getSurfaceControl();
- final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
+ final SurfaceControl parent = mAnimatable.getAnimationLeashParent();
if (surface == null || parent == null) {
Slog.w(TAG, "Unable to transfer animation, surface or parent is null");
cancelAnimation();
@@ -287,6 +293,7 @@ class SurfaceAnimator {
int height, boolean hidden) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
+ .setParent(mAnimatable.getAnimationLeashParent())
.setName(surface + " - animation-leash")
.setSize(width, height);
final SurfaceControl leash = builder.build();
@@ -355,6 +362,11 @@ class SurfaceAnimator {
SurfaceControl.Builder makeAnimationLeash();
/**
+ * @return The parent that should be used for the animation leash.
+ */
+ @Nullable SurfaceControl getAnimationLeashParent();
+
+ /**
* @return The surface of the object to be animated.
*/
@Nullable SurfaceControl getSurfaceControl();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 3ffc7fae5d0a..eb8eae1a95d7 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -44,6 +44,7 @@ import static com.android.server.wm.proto.StackProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.RemoteException;
@@ -145,6 +146,7 @@ public class TaskStack extends WindowContainer<Task> implements
* For {@link #prepareSurfaces}.
*/
final Rect mTmpDimBoundsRect = new Rect();
+ private final Point mLastSurfaceSize = new Point();
TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
super(service);
@@ -743,7 +745,13 @@ public class TaskStack extends WindowContainer<Task> implements
}
final Rect stackBounds = getBounds();
- transaction.setSize(mSurfaceControl, stackBounds.width(), stackBounds.height());
+ final int width = stackBounds.width();
+ final int height = stackBounds.height();
+ if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
+ return;
+ }
+ transaction.setSize(mSurfaceControl, width, height);
+ mLastSurfaceSize.set(width, height);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 986529344a78..031b57b73b05 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -92,8 +92,8 @@ public class WindowAnimationSpec implements AnimationSpec {
t.setFinalCrop(leash, mStackBounds);
t.setWindowCrop(leash, tmp.transformation.getClipRect());
} else {
- mTmpRect.set(tmp.transformation.getClipRect());
- mTmpRect.intersect(mStackBounds);
+ mTmpRect.set(mStackBounds);
+ mTmpRect.intersect(tmp.transformation.getClipRect());
t.setWindowCrop(leash, mTmpRect);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 8bceb640aa50..729587375421 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -35,6 +35,7 @@ import com.android.server.AnimationThread;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.ArrayList;
/**
* Singleton class that carries out the animations and Surface operations in a separate task
@@ -87,6 +88,12 @@ public class WindowAnimator {
*/
private boolean mAnimationFrameCallbackScheduled;
+ /**
+ * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is
+ * executed and the corresponding transaction is closed and applied.
+ */
+ private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
+
WindowAnimator(final WindowManagerService service) {
mService = service;
mContext = service.mContext;
@@ -262,6 +269,7 @@ public class WindowAnimator {
mService.destroyPreservedSurfaceLocked();
mService.mWindowPlacerLocked.destroyPendingSurfaces();
+ executeAfterPrepareSurfacesRunnables();
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
@@ -425,4 +433,23 @@ public class WindowAnimator {
void orAnimating(boolean animating) {
mAnimating |= animating;
}
+
+ /**
+ * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
+ * the corresponding transaction is closed and applied.
+ */
+ void addAfterPrepareSurfacesRunnable(Runnable r) {
+ mAfterPrepareSurfacesRunnables.add(r);
+ scheduleAnimation();
+ }
+
+ private void executeAfterPrepareSurfacesRunnables() {
+
+ // Traverse in order they were added.
+ final int size = mAfterPrepareSurfacesRunnables.size();
+ for (int i = 0; i < size; i++) {
+ mAfterPrepareSurfacesRunnables.get(i).run();
+ }
+ mAfterPrepareSurfacesRunnables.clear();
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b251b53bc051..af314101cd2b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -95,6 +95,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
protected final WindowManagerService mService;
private final Point mTmpPos = new Point();
+ protected final Point mLastSurfacePosition = new Point();
/** Total number of elements in this subtree, including our own hierarchy element. */
private int mTreeWeight = 1;
@@ -1088,6 +1089,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return makeSurface();
}
+ @Override
+ public SurfaceControl getAnimationLeashParent() {
+ return getParentSurfaceControl();
+ }
+
/**
* @return The layer on which all app animations are happening.
*/
@@ -1172,7 +1178,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
getRelativePosition(mTmpPos);
+ if (mTmpPos.equals(mLastSurfacePosition)) {
+ return;
+ }
+
transaction.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
+ mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y);
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).updateSurfacePosition(transaction);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index dfb385bddcdf..fcbc80234947 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -48,8 +48,8 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPL
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -112,15 +112,36 @@ import static com.android.server.wm.proto.WindowStateProto.CHILD_WINDOWS;
import static com.android.server.wm.proto.WindowStateProto.CONTAINING_FRAME;
import static com.android.server.wm.proto.WindowStateProto.CONTENT_FRAME;
import static com.android.server.wm.proto.WindowStateProto.CONTENT_INSETS;
+import static com.android.server.wm.proto.WindowStateProto.CUTOUT;
+import static com.android.server.wm.proto.WindowStateProto.DECOR_FRAME;
+import static com.android.server.wm.proto.WindowStateProto.DESTROYING;
+import static com.android.server.wm.proto.WindowStateProto.DISPLAY_FRAME;
import static com.android.server.wm.proto.WindowStateProto.DISPLAY_ID;
import static com.android.server.wm.proto.WindowStateProto.FRAME;
import static com.android.server.wm.proto.WindowStateProto.GIVEN_CONTENT_INSETS;
+import static com.android.server.wm.proto.WindowStateProto.HAS_SURFACE;
import static com.android.server.wm.proto.WindowStateProto.IDENTIFIER;
+import static com.android.server.wm.proto.WindowStateProto.IS_ON_SCREEN;
+import static com.android.server.wm.proto.WindowStateProto.IS_READY_FOR_DISPLAY;
+import static com.android.server.wm.proto.WindowStateProto.IS_VISIBLE;
+import static com.android.server.wm.proto.WindowStateProto.OUTSETS;
+import static com.android.server.wm.proto.WindowStateProto.OUTSET_FRAME;
+import static com.android.server.wm.proto.WindowStateProto.OVERSCAN_FRAME;
+import static com.android.server.wm.proto.WindowStateProto.OVERSCAN_INSETS;
import static com.android.server.wm.proto.WindowStateProto.PARENT_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
+import static com.android.server.wm.proto.WindowStateProto.REMOVED;
+import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT;
+import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT;
+import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH;
import static com.android.server.wm.proto.WindowStateProto.SHOWN_POSITION;
+import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS;
+import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS;
import static com.android.server.wm.proto.WindowStateProto.SURFACE_POSITION;
+import static com.android.server.wm.proto.WindowStateProto.SYSTEM_UI_VISIBILITY;
+import static com.android.server.wm.proto.WindowStateProto.VIEW_VISIBILITY;
+import static com.android.server.wm.proto.WindowStateProto.VISIBLE_FRAME;
+import static com.android.server.wm.proto.WindowStateProto.VISIBLE_INSETS;
import static com.android.server.wm.proto.WindowStateProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
@@ -142,6 +163,7 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.MergedConfiguration;
import android.util.Slog;
@@ -2222,12 +2244,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWinAnimator + ": " + mPolicyVisibilityAfterAnim);
}
mPolicyVisibility = mPolicyVisibilityAfterAnim;
- setDisplayLayoutNeeded();
if (!mPolicyVisibility) {
+ mWinAnimator.hide("checkPolicyVisibilityChange");
if (mService.mCurrentFocus == this) {
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG,
"setAnimationLocked: setting mFocusMayChange true");
mService.mFocusMayChange = true;
+ setDisplayLayoutNeeded();
}
// Window is no longer visible -- make sure if we were waiting
// for it to be displayed before enabling the display, that
@@ -3083,6 +3106,27 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
for (int i = 0; i < mChildren.size(); i++) {
mChildren.get(i).writeToProto(proto, CHILD_WINDOWS, trim);
}
+ proto.write(REQUESTED_WIDTH, mRequestedWidth);
+ proto.write(REQUESTED_HEIGHT, mRequestedHeight);
+ proto.write(VIEW_VISIBILITY, mViewVisibility);
+ proto.write(SYSTEM_UI_VISIBILITY, mSystemUiVisibility);
+ proto.write(HAS_SURFACE, mHasSurface);
+ proto.write(IS_READY_FOR_DISPLAY, isReadyForDisplay());
+ mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
+ mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME);
+ mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
+ mDecorFrame.writeToProto(proto, DECOR_FRAME);
+ mOutsetFrame.writeToProto(proto, OUTSET_FRAME);
+ mOverscanInsets.writeToProto(proto, OVERSCAN_INSETS);
+ mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
+ mStableInsets.writeToProto(proto, STABLE_INSETS);
+ mOutsets.writeToProto(proto, OUTSETS);
+ mDisplayCutout.writeToProto(proto, CUTOUT);
+ proto.write(REMOVE_ON_EXIT, mRemoveOnExit);
+ proto.write(DESTROYING, mDestroying);
+ proto.write(REMOVED, mRemoved);
+ proto.write(IS_ON_SCREEN, isOnScreen());
+ proto.write(IS_VISIBLE, isVisible());
proto.end(token);
}
@@ -3675,6 +3719,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
windowInfo.activityToken = mAppToken.appToken.asBinder();
}
windowInfo.title = mAttrs.accessibilityTitle;
+ // Panel windows have no public way to set the a11y title directly. Use the
+ // regular title as a fallback.
+ if (TextUtils.isEmpty(windowInfo.title)
+ && (mAttrs.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW)
+ && (mAttrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW)) {
+ windowInfo.title = mAttrs.getTitle();
+ }
windowInfo.accessibilityIdOfAnchor = mAttrs.accessibilityIdOfAnchor;
windowInfo.focused = isFocused();
Task task = getTask();
@@ -4291,8 +4342,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx;
float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy;
float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy;
- float9[Matrix.MTRANS_X] = mSurfacePosition.x + mShownPosition.x;
- float9[Matrix.MTRANS_Y] = mSurfacePosition.y + mShownPosition.y;
+ int x = mSurfacePosition.x + mShownPosition.x;
+ int y = mSurfacePosition.y + mShownPosition.y;
+
+ // If changed, also adjust transformFrameToSurfacePosition
+ final WindowContainer parent = getParent();
+ if (isChildWindow()) {
+ final WindowState parentWindow = getParentWindow();
+ x += parentWindow.mFrame.left - parentWindow.mAttrs.surfaceInsets.left;
+ y += parentWindow.mFrame.top - parentWindow.mAttrs.surfaceInsets.top;
+ } else if (parent != null) {
+ final Rect parentBounds = parent.getBounds();
+ x += parentBounds.left;
+ y += parentBounds.top;
+ }
+ float9[Matrix.MTRANS_X] = x;
+ float9[Matrix.MTRANS_Y] = y;
float9[Matrix.MPERSP_0] = 0;
float9[Matrix.MPERSP_1] = 0;
float9[Matrix.MPERSP_2] = 1;
@@ -4417,6 +4482,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Leash is now responsible for position, so set our position to 0.
t.setPosition(mSurfaceControl, 0, 0);
+ mLastSurfacePosition.set(0, 0);
}
@Override
@@ -4432,13 +4498,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition);
- if (!mSurfaceAnimator.hasLeash()) {
+ if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) {
t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
}
}
private void transformFrameToSurfacePosition(int left, int top, Point outPoint) {
outPoint.set(left, top);
+
+ // If changed, also adjust getTransformationMatrix
final WindowContainer parentWindowContainer = getParent();
if (isChildWindow()) {
// TODO: This probably falls apart at some point and we should
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d2247ac2c973..96b0bd5f7b2f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -42,8 +42,10 @@ import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
+import static com.android.server.wm.proto.WindowStateAnimatorProto.DRAW_STATE;
import static com.android.server.wm.proto.WindowStateAnimatorProto.LAST_CLIP_RECT;
import static com.android.server.wm.proto.WindowStateAnimatorProto.SURFACE;
+import static com.android.server.wm.proto.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
import android.content.Context;
import android.graphics.Matrix;
@@ -1381,6 +1383,8 @@ class WindowStateAnimator {
if (mSurfaceController != null) {
mSurfaceController.writeToProto(proto, SURFACE);
}
+ proto.write(DRAW_STATE, mDrawState);
+ mSystemDecorRect.writeToProto(proto, SYSTEM_DECOR_RECT);
proto.end(token);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index e55d4ea35739..c1e95ebeddf2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -67,7 +67,8 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {}
public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm,
- ParcelableKeyGenParameterSpec keySpec, KeymasterCertificateChain attestationChain) {
+ ParcelableKeyGenParameterSpec keySpec, int idAttestationFlags,
+ KeymasterCertificateChain attestationChain) {
return false;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e5351b48e14d..11fce4d7101c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -45,6 +45,10 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_
import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
import static android.app.admin.DevicePolicyManager.LEAVE_ALL_SYSTEM_APPS_ENABLED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -217,8 +221,10 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -5052,17 +5058,82 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
+ private void enforceIsDeviceOwnerOrCertInstallerOfDeviceOwner(
+ ComponentName who, String callerPackage, int callerUid) throws SecurityException {
+ if (who == null) {
+ if (!mOwners.hasDeviceOwner()) {
+ throw new SecurityException("Not in Device Owner mode.");
+ }
+ if (UserHandle.getUserId(callerUid) != mOwners.getDeviceOwnerUserId()) {
+ throw new SecurityException("Caller not from device owner user");
+ }
+ if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) {
+ throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid() +
+ "has no permission to generate keys.");
+ }
+ } else {
+ // Caller provided - check it is the device owner.
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public static int[] translateIdAttestationFlags(
+ int idAttestationFlags) {
+ Map<Integer, Integer> idTypeToAttestationFlag = new HashMap();
+ idTypeToAttestationFlag.put(ID_TYPE_SERIAL, AttestationUtils.ID_TYPE_SERIAL);
+ idTypeToAttestationFlag.put(ID_TYPE_IMEI, AttestationUtils.ID_TYPE_IMEI);
+ idTypeToAttestationFlag.put(ID_TYPE_MEID, AttestationUtils.ID_TYPE_MEID);
+
+ int numFlagsSet = Integer.bitCount(idAttestationFlags);
+ // No flags are set - return null to indicate no device ID attestation information should
+ // be included in the attestation record.
+ if (numFlagsSet == 0) {
+ return null;
+ }
+
+ // If the ID_TYPE_BASE_INFO is set, make sure that a non-null array is returned, even if
+ // no other flag is set. That will lead to inclusion of general device make data in the
+ // attestation record, but no specific device identifiers.
+ if ((idAttestationFlags & ID_TYPE_BASE_INFO) != 0) {
+ numFlagsSet -= 1;
+ idAttestationFlags = idAttestationFlags & (~ID_TYPE_BASE_INFO);
+ }
+
+ int[] attestationUtilsFlags = new int[numFlagsSet];
+ int i = 0;
+ for (Integer idType: idTypeToAttestationFlag.keySet()) {
+ if ((idType & idAttestationFlags) != 0) {
+ attestationUtilsFlags[i++] = idTypeToAttestationFlag.get(idType);
+ }
+ }
+
+ return attestationUtilsFlags;
+ }
+
@Override
public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm,
ParcelableKeyGenParameterSpec parcelableKeySpec,
+ int idAttestationFlags,
KeymasterCertificateChain attestationChain) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_INSTALL);
+ // Get attestation flags, if any.
+ final int[] attestationUtilsFlags = translateIdAttestationFlags(idAttestationFlags);
+ final boolean deviceIdAttestationRequired = attestationUtilsFlags != null;
+ final int callingUid = mInjector.binderGetCallingUid();
+
+ if (deviceIdAttestationRequired && attestationUtilsFlags.length > 0) {
+ enforceIsDeviceOwnerOrCertInstallerOfDeviceOwner(who, callerPackage, callingUid);
+ } else {
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_CERT_INSTALL);
+ }
final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec();
- if (TextUtils.isEmpty(keySpec.getKeystoreAlias())) {
+ final String alias = keySpec.getKeystoreAlias();
+ if (TextUtils.isEmpty(alias)) {
throw new IllegalArgumentException("Empty alias provided.");
}
- final String alias = keySpec.getKeystoreAlias();
// As the caller will be granted access to the key, ensure no UID was specified, as
// it will not have the desired effect.
if (keySpec.getUid() != KeyStore.UID_SELF) {
@@ -5070,7 +5141,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
- final int callingUid = mInjector.binderGetCallingUid();
+ if (deviceIdAttestationRequired && (keySpec.getAttestationChallenge() == null)) {
+ throw new IllegalArgumentException(
+ "Requested Device ID attestation but challenge is empty.");
+ }
final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
final long id = mInjector.binderClearCallingIdentity();
@@ -5103,7 +5177,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final byte[] attestationChallenge = keySpec.getAttestationChallenge();
if (attestationChallenge != null) {
final boolean attestationResult = keyChain.attestKey(
- alias, attestationChallenge, attestationChain);
+ alias, attestationChallenge, attestationUtilsFlags, attestationChain);
if (!attestationResult) {
Log.e(LOG_TAG, String.format(
"Attestation for %s failed, deleting key.", alias));
@@ -11802,10 +11876,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final long id = mInjector.binderClearCallingIdentity();
try {
- //STOPSHIP add support for COMP, DO, edge cases when device is rebooted/work mode off,
+ //STOPSHIP add support for COMP, edge cases when device is rebooted/work mode off,
//transfer callbacks and broadcast
- if (isProfileOwner(admin, callingUserId)) {
- transferProfileOwner(admin, target, callingUserId);
+ synchronized (this) {
+ if (isProfileOwner(admin, callingUserId)) {
+ transferProfileOwnerLocked(admin, target, callingUserId);
+ } else if (isDeviceOwner(admin, callingUserId)) {
+ transferDeviceOwnerLocked(admin, target, callingUserId);
+ }
}
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -11815,15 +11893,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
/**
* Transfers the profile owner for user with id profileOwnerUserId from admin to target.
*/
- private void transferProfileOwner(ComponentName admin, ComponentName target,
+ private void transferProfileOwnerLocked(ComponentName admin, ComponentName target,
int profileOwnerUserId) {
- synchronized (this) {
- transferActiveAdminUncheckedLocked(target, admin, profileOwnerUserId);
- mOwners.transferProfileOwner(target, profileOwnerUserId);
- Slog.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId);
- mOwners.writeProfileOwner(profileOwnerUserId);
- mDeviceAdminServiceController.startServiceForOwner(
- target.getPackageName(), profileOwnerUserId, "transfer-profile-owner");
- }
+ transferActiveAdminUncheckedLocked(target, admin, profileOwnerUserId);
+ mOwners.transferProfileOwner(target, profileOwnerUserId);
+ Slog.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId);
+ mOwners.writeProfileOwner(profileOwnerUserId);
+ mDeviceAdminServiceController.startServiceForOwner(
+ target.getPackageName(), profileOwnerUserId, "transfer-profile-owner");
+ }
+
+ /**
+ * Transfers the device owner for user with id userId from admin to target.
+ */
+ private void transferDeviceOwnerLocked(ComponentName admin, ComponentName target, int userId) {
+ transferActiveAdminUncheckedLocked(target, admin, userId);
+ mOwners.transferDeviceOwner(target);
+ Slog.i(LOG_TAG, "Device owner set: " + target + " on user " + userId);
+ mOwners.writeDeviceOwner();
+ mDeviceAdminServiceController.startServiceForOwner(
+ target.getPackageName(), userId, "transfer-device-owner");
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 9042a8d8b305..2a23888b875c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -288,6 +288,17 @@ class Owners {
}
}
+ void transferDeviceOwner(ComponentName target) {
+ synchronized (mLock) {
+ // We don't set a name because it's not used anyway.
+ // See DevicePolicyManagerService#getDeviceOwnerName
+ mDeviceOwner = new OwnerInfo(null, target,
+ mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
+ mDeviceOwner.remoteBugreportHash);
+ pushToPackageManagerLocked();
+ }
+ }
+
ComponentName getProfileOwnerComponent(int userId) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
index c20c37678b24..a473bc61941c 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
@@ -16,19 +16,17 @@
package com.android.server.backup;
+import static com.google.common.truth.Truth.assertThat;
+
import android.app.AlarmManager;
import android.content.Context;
import android.os.Handler;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
-import com.android.server.backup.testing.ShadowBackupTransportStub;
-import com.android.server.backup.testing.ShadowContextImplForBackup;
-import com.android.server.backup.testing.ShadowPackageManagerForBackup;
import com.android.server.testing.FrameworkRobolectricTestRunner;
import com.android.server.testing.SystemLoaderClasses;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,19 +34,9 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import static com.google.common.truth.Truth.assertThat;
-
@RunWith(FrameworkRobolectricTestRunner.class)
-@Config(
- manifest = Config.NONE,
- sdk = 26,
- shadows = {
- ShadowContextImplForBackup.class,
- ShadowBackupTransportStub.class,
- ShadowPackageManagerForBackup.class
- }
-)
-@SystemLoaderClasses({TransportManager.class})
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderClasses({BackupManagerConstants.class})
@Presubmit
public class BackupManagerConstantsTest {
private static final String PACKAGE_NAME = "some.package.name";
@@ -59,17 +47,13 @@ public class BackupManagerConstantsTest {
MockitoAnnotations.initMocks(this);
}
- @After
- public void tearDown() throws Exception {
- }
-
@Test
public void testDefaultValues() throws Exception {
final Context context = RuntimeEnvironment.application.getApplicationContext();
final Handler handler = new Handler();
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.BACKUP_MANAGER_CONSTANTS, null);
+ Settings.Secure.putString(
+ context.getContentResolver(), Settings.Secure.BACKUP_MANAGER_CONSTANTS, null);
final BackupManagerConstants constants =
new BackupManagerConstants(handler, context.getContentResolver());
@@ -93,17 +77,21 @@ public class BackupManagerConstantsTest {
final Context context = RuntimeEnvironment.application.getApplicationContext();
final Handler handler = new Handler();
- final String recievers_setting = "backup_finished_notification_receivers=" +
- PACKAGE_NAME + ':' + ANOTHER_PACKAGE_NAME;
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.BACKUP_MANAGER_CONSTANTS, recievers_setting);
+ final String recieversSetting =
+ "backup_finished_notification_receivers="
+ + PACKAGE_NAME
+ + ':'
+ + ANOTHER_PACKAGE_NAME;
+ Settings.Secure.putString(
+ context.getContentResolver(),
+ Settings.Secure.BACKUP_MANAGER_CONSTANTS,
+ recieversSetting);
final BackupManagerConstants constants =
new BackupManagerConstants(handler, context.getContentResolver());
constants.start();
- assertThat(constants.getBackupFinishedNotificationReceivers()).isEqualTo(new String[] {
- PACKAGE_NAME,
- ANOTHER_PACKAGE_NAME});
+ assertThat(constants.getBackupFinishedNotificationReceivers())
+ .isEqualTo(new String[] {PACKAGE_NAME, ANOTHER_PACKAGE_NAME});
}
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 3b7db9f73010..4176d2a7d9d5 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -24,12 +24,15 @@ import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -42,7 +45,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.INetworkRecommendationProvider;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
@@ -63,6 +68,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
@@ -128,7 +134,9 @@ public class NetworkScoreServiceTest {
@Mock private UnaryOperator<List<ScoredNetwork>> mScanResultsFilter;
@Mock private WifiInfo mWifiInfo;
@Mock private NetworkScoreService.ScoringServiceConnection mServiceConnection;
+ @Mock private PackageManagerInternal mPackageManagerInternal;
@Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
+ @Captor private ArgumentCaptor<PackageManagerInternal.PackagesProvider> mPackagesProviderCaptor;
private ContentResolver mContentResolver;
private NetworkScoreService mNetworkScoreService;
@@ -156,6 +164,7 @@ public class NetworkScoreServiceTest {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
mHandlerThread.start();
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
networkScorerAppData -> mServiceConnection, mHandlerThread.getLooper());
WifiConfiguration configuration = new WifiConfiguration();
@@ -181,6 +190,29 @@ public class NetworkScoreServiceTest {
@After
public void tearDown() throws Exception {
mHandlerThread.quitSafely();
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ }
+
+ @Test
+ public void testConstructor_setsUseOpenWifiPackagesProvider() {
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.USE_OPEN_WIFI_PACKAGE, "com.some.app");
+
+ verify(mPackageManagerInternal)
+ .setUseOpenWifiAppPackagesProvider(mPackagesProviderCaptor.capture());
+
+ String[] packages = mPackagesProviderCaptor.getValue().getPackages(0);
+ assertEquals(1, packages.length);
+ assertEquals("com.some.app", packages[0]);
+ }
+
+ @Test
+ public void testConstructor_registersUseOpenWifiPackageContentObserver() {
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.USE_OPEN_WIFI_PACKAGE, "com.some.other.app");
+
+ verify(mPackageManagerInternal, timeout(500))
+ .grantDefaultPermissionsToDefaultUseOpenWifiApp("com.some.other.app", 0);
}
@Test
@@ -947,8 +979,8 @@ public class NetworkScoreServiceTest {
}
private static class CountDownHandler extends Handler {
- CountDownLatch latch = new CountDownLatch(1);
- int receivedWhat;
+ final CountDownLatch latch = new CountDownLatch(1);
+ volatile int receivedWhat;
CountDownHandler(Looper looper) {
super(looper);
@@ -956,8 +988,8 @@ public class NetworkScoreServiceTest {
@Override
public void handleMessage(Message msg) {
- latch.countDown();
receivedWhat = msg.what;
+ latch.countDown();
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index 8a54c4e7f9c0..8d5556eac447 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.content.Context;
+import android.os.Message;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.DebugUtils;
@@ -48,6 +49,34 @@ import org.junit.runner.RunWith;
import java.util.function.IntConsumer;
+/**
+ * Tests the state transitions of {@link MagnificationGestureHandler}
+ *
+ * Here's a dot graph describing the transitions being tested:
+ * {@code
+ * digraph {
+ * IDLE -> SHORTCUT_TRIGGERED [label="a11y\nbtn"]
+ * SHORTCUT_TRIGGERED -> IDLE [label="a11y\nbtn"]
+ * IDLE -> DOUBLE_TAP [label="2tap"]
+ * DOUBLE_TAP -> IDLE [label="timeout"]
+ * DOUBLE_TAP -> TRIPLE_TAP_AND_HOLD [label="down"]
+ * SHORTCUT_TRIGGERED -> TRIPLE_TAP_AND_HOLD [label="down"]
+ * TRIPLE_TAP_AND_HOLD -> ZOOMED [label="up"]
+ * TRIPLE_TAP_AND_HOLD -> DRAGGING_TMP [label="hold/\nswipe"]
+ * DRAGGING_TMP -> IDLE [label="release"]
+ * ZOOMED -> ZOOMED_DOUBLE_TAP [label="2tap"]
+ * ZOOMED_DOUBLE_TAP -> ZOOMED [label="timeout"]
+ * ZOOMED_DOUBLE_TAP -> DRAGGING [label="hold"]
+ * ZOOMED_DOUBLE_TAP -> IDLE [label="tap"]
+ * DRAGGING -> ZOOMED [label="release"]
+ * ZOOMED -> IDLE [label="a11y\nbtn"]
+ * ZOOMED -> PANNING [label="2hold"]
+ * PANNING -> PANNING_SCALING [label="pinch"]
+ * PANNING_SCALING -> ZOOMED [label="release"]
+ * PANNING -> ZOOMED [label="release"]
+ * }
+ * }
+ */
@RunWith(AndroidJUnit4.class)
public class MagnificationGestureHandlerTest {
@@ -76,6 +105,8 @@ public class MagnificationGestureHandlerTest {
private MagnificationGestureHandler mMgh;
private TestHandler mHandler;
+ private long mLastDownTime = Integer.MIN_VALUE;
+
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
@@ -104,7 +135,13 @@ public class MagnificationGestureHandlerTest {
MagnificationGestureHandler h = new MagnificationGestureHandler(
mContext, mMagnificationController,
detectTripleTap, detectShortcutTrigger);
- mHandler = new TestHandler(h.mDetectingState, mClock);
+ mHandler = new TestHandler(h.mDetectingState, mClock) {
+ @Override
+ protected String messageToString(Message m) {
+ return DebugUtils.valueToString(
+ MagnificationGestureHandler.DetectingState.class, "MESSAGE_", m.what);
+ }
+ };
h.mDetectingState.mHandler = mHandler;
h.setNext(strictMock(EventStreamTransformation.class));
return h;
@@ -184,11 +221,11 @@ public class MagnificationGestureHandlerTest {
fastForward1sec();
}, STATE_ZOOMED);
- // tap+tap+swipe gets delegated
- assertTransition(STATE_2TAPS, () -> {
- allowEventDelegation();
- swipe();
- }, STATE_IDLE);
+ // tap+tap+swipe doesn't get delegated
+ assertTransition(STATE_2TAPS, () -> swipe(), STATE_IDLE);
+
+ // tap+tap+swipe initiates viewport dragging immediately
+ assertTransition(STATE_2TAPS, () -> swipeAndHold(), STATE_DRAGGING_TMP);
}
@Test
@@ -439,23 +476,24 @@ public class MagnificationGestureHandlerTest {
}
private void tap() {
- MotionEvent downEvent = downEvent();
- send(downEvent);
- send(upEvent(downEvent.getDownTime()));
+ send(downEvent());
+ send(upEvent());
}
private void swipe() {
- MotionEvent downEvent = downEvent();
- send(downEvent);
+ swipeAndHold();
+ send(upEvent());
+ }
+
+ private void swipeAndHold() {
+ send(downEvent());
send(moveEvent(DEFAULT_X * 2, DEFAULT_Y * 2));
- send(upEvent(downEvent.getDownTime()));
}
private void longTap() {
- MotionEvent downEvent = downEvent();
- send(downEvent);
+ send(downEvent());
fastForward(2000);
- send(upEvent(downEvent.getDownTime()));
+ send(upEvent());
}
private void triggerShortcut() {
@@ -473,16 +511,17 @@ public class MagnificationGestureHandlerTest {
}
private MotionEvent moveEvent(float x, float y) {
- return MotionEvent.obtain(defaultDownTime(), mClock.now(), ACTION_MOVE, x, y, 0);
+ return MotionEvent.obtain(mLastDownTime, mClock.now(), ACTION_MOVE, x, y, 0);
}
private MotionEvent downEvent() {
- return MotionEvent.obtain(mClock.now(), mClock.now(),
+ mLastDownTime = mClock.now();
+ return MotionEvent.obtain(mLastDownTime, mLastDownTime,
ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0);
}
private MotionEvent upEvent() {
- return upEvent(defaultDownTime());
+ return upEvent(mLastDownTime);
}
private MotionEvent upEvent(long downTime) {
@@ -490,11 +529,6 @@ public class MagnificationGestureHandlerTest {
MotionEvent.ACTION_UP, DEFAULT_X, DEFAULT_Y, 0);
}
- private long defaultDownTime() {
- MotionEvent lastDown = mMgh.mDetectingState.mLastDown;
- return lastDown == null ? mClock.now() - 1 : lastDown.getDownTime();
- }
-
private MotionEvent pointerEvent(int action, float x, float y) {
MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
defPointerProperties.id = 0;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 60783db8bb3c..58ac7d28eade 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -17,6 +17,10 @@ package com.android.server.devicepolicy;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
@@ -71,6 +75,7 @@ import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.security.KeyChain;
+import android.security.keystore.AttestationUtils;
import android.telephony.TelephonyManager;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
@@ -4459,6 +4464,47 @@ public class DevicePolicyManagerTest extends DpmTestBase {
});
}
+ private void assertAttestationFlags(int attestationFlags, int[] expectedFlags) {
+ int[] gotFlags = DevicePolicyManagerService.translateIdAttestationFlags(attestationFlags);
+ Arrays.sort(gotFlags);
+ Arrays.sort(expectedFlags);
+ assertTrue(Arrays.equals(expectedFlags, gotFlags));
+ }
+
+ public void testTranslationOfIdAttestationFlag() {
+ int[] allIdTypes = new int[]{ID_TYPE_SERIAL, ID_TYPE_IMEI, ID_TYPE_MEID};
+ int[] correspondingAttUtilsTypes = new int[]{
+ AttestationUtils.ID_TYPE_SERIAL, AttestationUtils.ID_TYPE_IMEI,
+ AttestationUtils.ID_TYPE_MEID};
+
+ // Test translation of zero flags
+ assertNull(DevicePolicyManagerService.translateIdAttestationFlags(0));
+
+ // Test translation of the ID_TYPE_BASE_INFO flag, which should yield an empty, but
+ // non-null array
+ assertAttestationFlags(ID_TYPE_BASE_INFO, new int[] {});
+
+ // Test translation of a single flag
+ assertAttestationFlags(ID_TYPE_BASE_INFO | ID_TYPE_SERIAL,
+ new int[] {AttestationUtils.ID_TYPE_SERIAL});
+ assertAttestationFlags(ID_TYPE_SERIAL, new int[] {AttestationUtils.ID_TYPE_SERIAL});
+
+ // Test translation of two flags
+ assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI,
+ new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL});
+ assertAttestationFlags(ID_TYPE_BASE_INFO | ID_TYPE_MEID | ID_TYPE_SERIAL,
+ new int[] {AttestationUtils.ID_TYPE_MEID, AttestationUtils.ID_TYPE_SERIAL});
+
+ // Test translation of all three flags
+ assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI | ID_TYPE_MEID,
+ new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL,
+ AttestationUtils.ID_TYPE_MEID});
+ // Test translation of all three flags
+ assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI | ID_TYPE_MEID | ID_TYPE_BASE_INFO,
+ new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL,
+ AttestationUtils.ID_TYPE_MEID});
+ }
+
private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
when(getServices().settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index 2629b12375a4..5105f4e2a9c9 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -20,7 +20,13 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.os.PowerManager;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -35,18 +41,18 @@ import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
public class BrightnessMappingStrategyTest {
- private static final float[] LUX_LEVELS = {
- 0f,
- 5f,
- 20f,
- 40f,
- 100f,
- 325f,
- 600f,
- 1250f,
- 2200f,
- 4000f,
- 5000f
+ private static final int[] LUX_LEVELS = {
+ 0,
+ 5,
+ 20,
+ 40,
+ 100,
+ 325,
+ 600,
+ 1250,
+ 2200,
+ 4000,
+ 5000
};
private static final float[] DISPLAY_LEVELS_NITS = {
@@ -80,11 +86,13 @@ public class BrightnessMappingStrategyTest {
private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
private static final int[] BACKLIGHT_RANGE = { 1, 255 };
+ private static final float[] EMPTY_FLOAT_ARRAY = new float[0];
+ private static final int[] EMPTY_INT_ARRAY = new int[0];
+
@Test
public void testSimpleStrategyMappingAtControlPoints() {
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(
- LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
- null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 0; i < LUX_LEVELS.length; i++) {
final float expectedLevel =
@@ -96,9 +104,8 @@ public class BrightnessMappingStrategyTest {
@Test
public void testSimpleStrategyMappingBetweenControlPoints() {
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(
- LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
- null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 1; i < LUX_LEVELS.length; i++) {
final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
@@ -111,9 +118,9 @@ public class BrightnessMappingStrategyTest {
@Test
public void testPhysicalStrategyMappingAtControlPoints() {
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(
- LUX_LEVELS, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
+ DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
for (int i = 0; i < LUX_LEVELS.length; i++) {
final float expectedLevel = DISPLAY_LEVELS_NITS[i] / DISPLAY_RANGE_NITS[1];
@@ -124,9 +131,9 @@ public class BrightnessMappingStrategyTest {
@Test
public void testPhysicalStrategyMappingBetweenControlPoints() {
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(
- LUX_LEVELS, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
+ DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
Spline backlightToBrightness =
Spline.createSpline(toFloatArray(BACKLIGHT_RANGE), DISPLAY_RANGE_NITS);
@@ -141,82 +148,79 @@ public class BrightnessMappingStrategyTest {
@Test
public void testDefaultStrategyIsPhysical() {
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(
- LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
+ Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
}
@Test
public void testNonStrictlyIncreasingLuxLevelsFails() {
- final float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
+ final int[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
final int idx = lux.length / 2;
- float tmp = lux[idx];
+ int tmp = lux[idx];
lux[idx] = lux[idx+1];
lux[idx+1] = tmp;
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(
- lux, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ Resources res = createResources(lux, DISPLAY_LEVELS_NITS,
+ DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
assertNull(strategy);
// And make sure we get the same result even if it's monotone but not increasing.
lux[idx] = lux[idx+1];
- strategy = BrightnessMappingStrategy.create(
- lux, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ res = createResources(lux, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ strategy = BrightnessMappingStrategy.create(res);
assertNull(strategy);
}
@Test
public void testDifferentNumberOfControlPointValuesFails() {
//Extra lux level
- final float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length+1);
+ final int[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length+1);
// Make sure it's strictly increasing so that the only failure is the differing array
// lengths
lux[lux.length - 1] = lux[lux.length - 2] + 1;
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(
- lux, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ Resources res = createResources(lux, DISPLAY_LEVELS_NITS,
+ DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
assertNull(strategy);
- strategy = BrightnessMappingStrategy.create(
- lux, DISPLAY_LEVELS_BACKLIGHT,
- null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ res = createResources(lux, DISPLAY_LEVELS_BACKLIGHT);
+ strategy = BrightnessMappingStrategy.create(res);
assertNull(strategy);
// Extra backlight level
final int[] backlight = Arrays.copyOf(
DISPLAY_LEVELS_BACKLIGHT, DISPLAY_LEVELS_BACKLIGHT.length+1);
backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
- strategy = BrightnessMappingStrategy.create(
- LUX_LEVELS, backlight,
- null /*brightnessLevelsNits*/, null /*nitsRange*/, null /*backlightRange*/);
+ res = createResources(LUX_LEVELS, backlight);
+ strategy = BrightnessMappingStrategy.create(res);
assertNull(strategy);
// Extra nits level
final float[] nits = Arrays.copyOf(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_NITS.length+1);
nits[nits.length - 1] = nits[nits.length - 2] + 1;
- strategy = BrightnessMappingStrategy.create(
- LUX_LEVELS, null /*brightnessLevelsBacklight*/,
- nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ strategy = BrightnessMappingStrategy.create(res);
assertNull(strategy);
}
@Test
public void testPhysicalStrategyRequiresNitsMapping() {
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(
- LUX_LEVELS, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, null, BACKLIGHT_RANGE);
+ Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, EMPTY_FLOAT_ARRAY /*nitsRange*/, BACKLIGHT_RANGE);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
assertNull(physical);
- physical = BrightnessMappingStrategy.create(
- LUX_LEVELS, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, null);
+ res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, EMPTY_INT_ARRAY /*backlightRange*/);
+ physical = BrightnessMappingStrategy.create(res);
assertNull(physical);
- physical = BrightnessMappingStrategy.create(
- LUX_LEVELS, null /*brightnessLevelsBacklight*/,
- DISPLAY_LEVELS_NITS, null, null);
+ res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
+ DISPLAY_LEVELS_NITS, EMPTY_FLOAT_ARRAY /*nitsRange*/,
+ EMPTY_INT_ARRAY /*backlightRange*/);
+ physical = BrightnessMappingStrategy.create(res);
assertNull(physical);
}
@@ -227,4 +231,73 @@ public class BrightnessMappingStrategyTest {
}
return newVals;
}
+
+ private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight) {
+ return createResources(luxLevels, brightnessLevelsBacklight,
+ EMPTY_FLOAT_ARRAY /*brightnessLevelsNits*/, EMPTY_FLOAT_ARRAY /*nitsRange*/,
+ EMPTY_INT_ARRAY /*backlightRange*/);
+ }
+
+ private Resources createResources(int[] luxLevels, float[] brightnessLevelsNits,
+ float[] nitsRange, int[] backlightRange) {
+ return createResources(luxLevels, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
+ brightnessLevelsNits, nitsRange, backlightRange);
+ }
+
+ private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight,
+ float[] brightnessLevelsNits, float[] nitsRange, int[] backlightRange) {
+ Resources mockResources = mock(Resources.class);
+ // For historical reasons, the lux levels resource implicitly defines the first point as 0,
+ // so we need to chop it off of the array the mock resource object returns.
+ int[] luxLevelsResource = Arrays.copyOfRange(luxLevels, 1, luxLevels.length);
+ when(mockResources.getIntArray(com.android.internal.R.array.config_autoBrightnessLevels))
+ .thenReturn(luxLevelsResource);
+
+ when(mockResources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLcdBacklightValues))
+ .thenReturn(brightnessLevelsBacklight);
+
+ TypedArray mockBrightnessLevelNits = createFloatTypedArray(brightnessLevelsNits);
+ when(mockResources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
+ .thenReturn(mockBrightnessLevelNits);
+
+ TypedArray mockNitsRange = createFloatTypedArray(nitsRange);
+ when(mockResources.obtainTypedArray(
+ com.android.internal.R.array.config_screenBrightnessNits))
+ .thenReturn(mockNitsRange);
+
+ when(mockResources.getIntArray(
+ com.android.internal.R.array.config_screenBrightnessBacklight))
+ .thenReturn(backlightRange);
+
+ when(mockResources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum))
+ .thenReturn(1);
+ when(mockResources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMaximum))
+ .thenReturn(255);
+ return mockResources;
+ }
+
+ private TypedArray createFloatTypedArray(float[] vals) {
+ TypedArray mockArray = mock(TypedArray.class);
+ when(mockArray.length()).thenAnswer(invocation -> {
+ return vals.length;
+ });
+ when(mockArray.getFloat(anyInt(), anyFloat())).thenAnswer(invocation -> {
+ final float def = (float) invocation.getArguments()[1];
+ if (vals == null) {
+ return def;
+ }
+ int idx = (int) invocation.getArguments()[0];
+ if (idx >= 0 && idx < vals.length) {
+ return vals[idx];
+ } else {
+ return def;
+ }
+ });
+ return mockArray;
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 926009ebfbae..08edd52c7112 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -66,6 +66,8 @@ import java.util.concurrent.TimeUnit;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BrightnessTrackerTest {
+ private static final float DEFAULT_INITIAL_BRIGHTNESS = 2.5f;
+ private static final float FLOAT_DELTA = 0.01f;
private BrightnessTracker mTracker;
private TestInjector mInjector;
@@ -98,7 +100,6 @@ public class BrightnessTrackerTest {
mInjector.mInteractive = false;
startTracker(mTracker);
assertNull(mInjector.mSensorListener);
- assertNotNull(mInjector.mSettingsObserver);
assertNotNull(mInjector.mBroadcastReceiver);
assertTrue(mInjector.mIdleScheduled);
Intent onIntent = new Intent();
@@ -119,7 +120,6 @@ public class BrightnessTrackerTest {
mTracker.stop();
assertNull(mInjector.mSensorListener);
- assertNull(mInjector.mSettingsObserver);
assertNull(mInjector.mBroadcastReceiver);
assertFalse(mInjector.mIdleScheduled);
}
@@ -128,12 +128,10 @@ public class BrightnessTrackerTest {
public void testBrightnessEvent() {
final int brightness = 20;
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
startTracker(mTracker);
mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, brightness);
List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
@@ -141,10 +139,11 @@ public class BrightnessTrackerTest {
BrightnessChangeEvent event = events.get(0);
assertEquals(mInjector.currentTimeMillis(), event.timeStamp);
assertEquals(1, event.luxValues.length);
- assertEquals(1.0f, event.luxValues[0], 0.1f);
+ assertEquals(1.0f, event.luxValues[0], FLOAT_DELTA);
assertEquals(mInjector.currentTimeMillis() - TimeUnit.SECONDS.toMillis(2),
event.luxTimestamps[0]);
- assertEquals(brightness, event.brightness);
+ assertEquals(brightness, event.brightness, FLOAT_DELTA);
+ assertEquals(DEFAULT_INITIAL_BRIGHTNESS, event.lastBrightness, FLOAT_DELTA);
// System had no data so these should all be at defaults.
assertEquals(Float.NaN, event.batteryLevel, 0.0);
@@ -154,21 +153,18 @@ public class BrightnessTrackerTest {
@Test
public void testBrightnessFullPopulatedEvent() {
- final int lastBrightness = 230;
+ final int initialBrightness = 230;
final int brightness = 130;
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, lastBrightness);
mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3333);
- startTracker(mTracker);
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
+ startTracker(mTracker, initialBrightness);
mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
batteryChangeEvent(30, 60));
mInjector.mSensorListener.onSensorChanged(createSensorEvent(1000.0f));
final long sensorTime = mInjector.currentTimeMillis();
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, brightness);
List<BrightnessChangeEvent> eventsNoPackage
= mTracker.getEvents(0, false).getList();
List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
@@ -179,9 +175,9 @@ public class BrightnessTrackerTest {
assertEquals(event.timeStamp, mInjector.currentTimeMillis());
assertArrayEquals(new float[] {1000.0f}, event.luxValues, 0.01f);
assertArrayEquals(new long[] {sensorTime}, event.luxTimestamps);
- assertEquals(brightness, event.brightness);
- assertEquals(lastBrightness, event.lastBrightness);
- assertEquals(0.5, event.batteryLevel, 0.01);
+ assertEquals(brightness, event.brightness, FLOAT_DELTA);
+ assertEquals(initialBrightness, event.lastBrightness, FLOAT_DELTA);
+ assertEquals(0.5, event.batteryLevel, FLOAT_DELTA);
assertTrue(event.nightMode);
assertEquals(3333, event.colorTemperature);
assertEquals("a.package", event.packageName);
@@ -192,45 +188,34 @@ public class BrightnessTrackerTest {
}
@Test
- public void testIgnoreSelfChange() {
+ public void testIgnoreAutomaticBrightnessChange() {
final int initialBrightness = 30;
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, initialBrightness);
- startTracker(mTracker);
+ startTracker(mTracker, initialBrightness);
mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
final int systemUpdatedBrightness = 20;
- mTracker.setBrightness(systemUpdatedBrightness, 0);
- assertEquals(systemUpdatedBrightness,
- (int) mInjector.mSystemIntSettings.get(Settings.System.SCREEN_BRIGHTNESS));
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, systemUpdatedBrightness, false /*userInitiated*/);
List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
// No events because we filtered out our change.
assertEquals(0, events.size());
final int firstUserUpdateBrightness = 20;
// Then change comes from somewhere else so we shouldn't filter.
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS,
- firstUserUpdateBrightness);
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, firstUserUpdateBrightness);
// and with a different brightness value.
final int secondUserUpdateBrightness = 34;
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS,
- secondUserUpdateBrightness);
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, secondUserUpdateBrightness);
events = mTracker.getEvents(0, true).getList();
assertEquals(2, events.size());
// First event is change from system update (20) to first user update (20)
- assertEquals(systemUpdatedBrightness, events.get(0).lastBrightness);
- assertEquals(firstUserUpdateBrightness, events.get(0).brightness);
+ assertEquals(systemUpdatedBrightness, events.get(0).lastBrightness, FLOAT_DELTA);
+ assertEquals(firstUserUpdateBrightness, events.get(0).brightness, FLOAT_DELTA);
// Second event is from first to second user update.
- assertEquals(firstUserUpdateBrightness, events.get(1).lastBrightness);
- assertEquals(secondUserUpdateBrightness, events.get(1).brightness);
+ assertEquals(firstUserUpdateBrightness, events.get(1).lastBrightness, FLOAT_DELTA);
+ assertEquals(secondUserUpdateBrightness, events.get(1).brightness, FLOAT_DELTA);
mTracker.stop();
}
@@ -243,9 +228,7 @@ public class BrightnessTrackerTest {
for (int brightness = 0; brightness <= 255; ++brightness) {
mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
mInjector.incrementTime(TimeUnit.SECONDS.toNanos(1));
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, brightness);
}
List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
@@ -254,14 +237,13 @@ public class BrightnessTrackerTest {
assertEquals(100, events.size());
for (int i = 0; i < events.size(); i++) {
BrightnessChangeEvent event = events.get(i);
- assertEquals(156 + i, event.brightness);
+ assertEquals(156 + i, event.brightness, FLOAT_DELTA);
}
}
@Test
public void testLimitedSensorEvents() {
final int brightness = 20;
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
startTracker(mTracker);
// 20 Sensor events 1 second apart.
@@ -269,8 +251,7 @@ public class BrightnessTrackerTest {
mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
mInjector.mSensorListener.onSensorChanged(createSensorEvent(i + 1.0f));
}
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, 20);
List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
@@ -284,7 +265,7 @@ public class BrightnessTrackerTest {
assertEquals(event.luxTimestamps[11 - i],
mInjector.currentTimeMillis() - i * TimeUnit.SECONDS.toMillis(1));
}
- assertEquals(brightness, event.brightness);
+ assertEquals(brightness, event.brightness, FLOAT_DELTA);
}
@Test
@@ -298,25 +279,25 @@ public class BrightnessTrackerTest {
String eventFile =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<events>\n"
- + "<event brightness=\"194\" timestamp=\""
+ + "<event nits=\"194.2\" timestamp=\""
+ Long.toString(someTimeAgo) + "\" packageName=\""
+ "com.example.app\" user=\"10\" "
- + "lastBrightness=\"32\" "
+ + "lastNits=\"32.333\" "
+ "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\"\n"
+ "lux=\"32.2,31.1\" luxTimestamps=\""
+ Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\"/>"
- + "<event brightness=\"71\" timestamp=\""
+ + "<event nits=\"71\" timestamp=\""
+ Long.toString(someTimeAgo) + "\" packageName=\""
+ "com.android.anapp\" user=\"11\" "
- + "lastBrightness=\"32\" "
+ + "lastNits=\"32\" "
+ "batteryLevel=\"0.5\" nightMode=\"true\" colorTemperature=\"3235\"\n"
+ "lux=\"132.2,131.1\" luxTimestamps=\""
+ Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\"/>"
// Event that is too old so shouldn't show up.
- + "<event brightness=\"142\" timestamp=\""
+ + "<event nits=\"142\" timestamp=\""
+ Long.toString(twoMonthsAgo) + "\" packageName=\""
+ "com.example.app\" user=\"10\" "
- + "lastBrightness=\"32\" "
+ + "lastNits=\"32\" "
+ "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\"\n"
+ "lux=\"32.2,31.1\" luxTimestamps=\""
+ Long.toString(twoMonthsAgo) + "," + Long.toString(twoMonthsAgo) + "\"/>"
@@ -326,27 +307,27 @@ public class BrightnessTrackerTest {
assertEquals(1, events.size());
BrightnessChangeEvent event = events.get(0);
assertEquals(someTimeAgo, event.timeStamp);
- assertEquals(194, event.brightness);
- assertArrayEquals(new float[] {32.2f, 31.1f}, event.luxValues, 0.01f);
+ assertEquals(194.2, event.brightness, FLOAT_DELTA);
+ assertArrayEquals(new float[] {32.2f, 31.1f}, event.luxValues, FLOAT_DELTA);
assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps);
- assertEquals(32, event.lastBrightness);
+ assertEquals(32.333, event.lastBrightness, FLOAT_DELTA);
assertEquals(0, event.userId);
assertFalse(event.nightMode);
- assertEquals(1.0f, event.batteryLevel, 0.01);
+ assertEquals(1.0f, event.batteryLevel, FLOAT_DELTA);
assertEquals("com.example.app", event.packageName);
events = tracker.getEvents(1, true).getList();
assertEquals(1, events.size());
event = events.get(0);
assertEquals(someTimeAgo, event.timeStamp);
- assertEquals(71, event.brightness);
- assertArrayEquals(new float[] {132.2f, 131.1f}, event.luxValues, 0.01f);
+ assertEquals(71, event.brightness, FLOAT_DELTA);
+ assertArrayEquals(new float[] {132.2f, 131.1f}, event.luxValues, FLOAT_DELTA);
assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps);
- assertEquals(32, event.lastBrightness);
+ assertEquals(32, event.lastBrightness, FLOAT_DELTA);
assertEquals(1, event.userId);
assertTrue(event.nightMode);
assertEquals(3235, event.colorTemperature);
- assertEquals(0.5f, event.batteryLevel, 0.01);
+ assertEquals(0.5f, event.batteryLevel, FLOAT_DELTA);
assertEquals("com.android.anapp", event.packageName);
}
@@ -370,7 +351,7 @@ public class BrightnessTrackerTest {
eventFile =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<events>\n"
- + "<event brightness=\"194\" timestamp=\"" + someTimeAgo + "\" packageName=\""
+ + "<event nits=\"194\" timestamp=\"" + someTimeAgo + "\" packageName=\""
+ "com.example.app\" user=\"10\" "
+ "batteryLevel=\"0.7\" nightMode=\"false\" colorTemperature=\"0\" />\n"
+ "</events>";
@@ -386,7 +367,6 @@ public class BrightnessTrackerTest {
public void testWriteThenRead() throws Exception {
final int brightness = 20;
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3339);
@@ -399,8 +379,7 @@ public class BrightnessTrackerTest {
mInjector.mSensorListener.onSensorChanged(createSensorEvent(3000.0f));
final long secondSensorTime = mInjector.currentTimeMillis();
mInjector.incrementTime(TimeUnit.SECONDS.toMillis(3));
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, brightness);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mTracker.writeEventsLocked(baos);
mTracker.stop();
@@ -414,10 +393,10 @@ public class BrightnessTrackerTest {
assertEquals(1, events.size());
BrightnessChangeEvent event = events.get(0);
- assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, 0.01f);
+ assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, FLOAT_DELTA);
assertArrayEquals(new long[] {firstSensorTime, secondSensorTime}, event.luxTimestamps);
- assertEquals(brightness, event.brightness);
- assertEquals(0.3, event.batteryLevel, 0.01f);
+ assertEquals(brightness, event.brightness, FLOAT_DELTA);
+ assertEquals(0.3, event.batteryLevel, FLOAT_DELTA);
assertTrue(event.nightMode);
assertEquals(3339, event.colorTemperature);
}
@@ -426,7 +405,6 @@ public class BrightnessTrackerTest {
public void testWritePrunesOldEvents() throws Exception {
final int brightness = 20;
- mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3339);
@@ -437,14 +415,12 @@ public class BrightnessTrackerTest {
mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
mInjector.mSensorListener.onSensorChanged(createSensorEvent(2000.0f));
final long sensorTime = mInjector.currentTimeMillis();
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, brightness);
// 31 days later
mInjector.incrementTime(TimeUnit.DAYS.toMillis(31));
mInjector.mSensorListener.onSensorChanged(createSensorEvent(3000.0f));
- mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
- Settings.System.SCREEN_BRIGHTNESS));
+ notifyBrightnessChanged(mTracker, brightness);
final long eventTime = mInjector.currentTimeMillis();
List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
@@ -460,10 +436,10 @@ public class BrightnessTrackerTest {
assertEquals(eventTime, event.timeStamp);
// We will keep one of the old sensor events because we keep 1 event outside the window.
- assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, 0.01f);
+ assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, FLOAT_DELTA);
assertArrayEquals(new long[] {sensorTime, eventTime}, event.luxTimestamps);
- assertEquals(brightness, event.brightness);
- assertEquals(0.3, event.batteryLevel, 0.01f);
+ assertEquals(brightness, event.brightness, FLOAT_DELTA);
+ assertEquals(0.3, event.batteryLevel, FLOAT_DELTA);
assertTrue(event.nightMode);
assertEquals(3339, event.colorTemperature);
}
@@ -472,7 +448,7 @@ public class BrightnessTrackerTest {
public void testParcelUnParcel() {
Parcel parcel = Parcel.obtain();
BrightnessChangeEvent event = new BrightnessChangeEvent();
- event.brightness = 23;
+ event.brightness = 23f;
event.timeStamp = 345L;
event.packageName = "com.example";
event.userId = 12;
@@ -485,7 +461,7 @@ public class BrightnessTrackerTest {
event.batteryLevel = 0.7f;
event.nightMode = false;
event.colorTemperature = 345;
- event.lastBrightness = 50;
+ event.lastBrightness = 50f;
event.writeToParcel(parcel, 0);
byte[] parceled = parcel.marshall();
@@ -497,16 +473,16 @@ public class BrightnessTrackerTest {
BrightnessChangeEvent event2 = BrightnessChangeEvent.CREATOR.createFromParcel(parcel);
parcel.recycle();
- assertEquals(event.brightness, event2.brightness);
+ assertEquals(event.brightness, event2.brightness, FLOAT_DELTA);
assertEquals(event.timeStamp, event2.timeStamp);
assertEquals(event.packageName, event2.packageName);
assertEquals(event.userId, event2.userId);
- assertArrayEquals(event.luxValues, event2.luxValues, 0.01f);
+ assertArrayEquals(event.luxValues, event2.luxValues, FLOAT_DELTA);
assertArrayEquals(event.luxTimestamps, event2.luxTimestamps);
- assertEquals(event.batteryLevel, event2.batteryLevel, 0.01f);
+ assertEquals(event.batteryLevel, event2.batteryLevel, FLOAT_DELTA);
assertEquals(event.nightMode, event2.nightMode);
assertEquals(event.colorTemperature, event2.colorTemperature);
- assertEquals(event.lastBrightness, event2.lastBrightness);
+ assertEquals(event.lastBrightness, event2.lastBrightness, FLOAT_DELTA);
parcel = Parcel.obtain();
event.batteryLevel = Float.NaN;
@@ -518,7 +494,7 @@ public class BrightnessTrackerTest {
parcel.unmarshall(parceled, 0, parceled.length);
parcel.setDataPosition(0);
event2 = BrightnessChangeEvent.CREATOR.createFromParcel(parcel);
- assertEquals(event.batteryLevel, event2.batteryLevel, 0.01f);
+ assertEquals(event.batteryLevel, event2.batteryLevel, FLOAT_DELTA);
}
private InputStream getInputStream(String data) {
@@ -550,7 +526,21 @@ public class BrightnessTrackerTest {
}
private void startTracker(BrightnessTracker tracker) {
- tracker.start();
+ startTracker(tracker, DEFAULT_INITIAL_BRIGHTNESS);
+ }
+
+ private void startTracker(BrightnessTracker tracker, float initialBrightness) {
+ tracker.start(initialBrightness);
+ mInjector.waitForHandler();
+ }
+
+ private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness) {
+ notifyBrightnessChanged(tracker, brightness, true /*userInitiated*/);
+ }
+
+ private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness,
+ boolean userInitiated) {
+ tracker.notifyBrightnessChanged(brightness, userInitiated);
mInjector.waitForHandler();
}
@@ -578,7 +568,6 @@ public class BrightnessTrackerTest {
private class TestInjector extends BrightnessTracker.Injector {
SensorEventListener mSensorListener;
- ContentObserver mSettingsObserver;
BroadcastReceiver mBroadcastReceiver;
Map<String, Integer> mSystemIntSettings = new HashMap<>();
Map<String, Integer> mSecureIntSettings = new HashMap<>();
@@ -610,18 +599,6 @@ public class BrightnessTrackerTest {
}
@Override
- public void registerBrightnessObserver(ContentResolver resolver,
- ContentObserver settingsObserver) {
- mSettingsObserver = settingsObserver;
- }
-
- @Override
- public void unregisterBrightnessObserver(Context context,
- ContentObserver settingsObserver) {
- mSettingsObserver = null;
- }
-
- @Override
public void registerReceiver(Context context,
BroadcastReceiver shutdownReceiver, IntentFilter shutdownFilter) {
mBroadcastReceiver = shutdownReceiver;
@@ -647,23 +624,6 @@ public class BrightnessTrackerTest {
}
@Override
- public int getSystemIntForUser(ContentResolver resolver, String setting, int defaultValue,
- int userId) {
- Integer value = mSystemIntSettings.get(setting);
- if (value == null) {
- return defaultValue;
- } else {
- return value;
- }
- }
-
- @Override
- public void putSystemIntForUser(ContentResolver resolver, String setting, int value,
- int userId) {
- mSystemIntSettings.put(setting, value);
- }
-
- @Override
public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue,
int userId) {
Integer value = mSecureIntSettings.get(setting);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
index ba40c67cb35d..114da1aaebb5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
@@ -386,37 +386,38 @@ public class KeySyncUtilsTest {
}
@Test
- public void packVaultParams_encodesMaxAttemptsAsThirdParam() throws Exception {
- int maxAttempts = 10;
+ public void packVaultParams_encodesDeviceIdAsThirdParam() throws Exception {
+ long deviceId = 102942158152L;
byte[] packedForm = KeySyncUtils.packVaultParams(
SecureBox.genKeyPair().getPublic(),
- /*counterId=*/ 1001L,
- maxAttempts,
- /*deviceId=*/ 1L);
+ /*counterId=*/ 10021L,
+ /*maxAttempts=*/ 10,
+ deviceId);
ByteBuffer byteBuffer = ByteBuffer.wrap(packedForm)
.order(ByteOrder.LITTLE_ENDIAN);
byteBuffer.position(PUBLIC_KEY_LENGTH_BYTES + Long.BYTES);
- assertEquals(maxAttempts, byteBuffer.getInt());
+ assertEquals(deviceId, byteBuffer.getLong());
}
@Test
- public void packVaultParams_encodesDeviceIdAsLastParam() throws Exception {
- long deviceId = 102942158152L;
+ public void packVaultParams_encodesMaxAttemptsAsLastParam() throws Exception {
+ int maxAttempts = 10;
byte[] packedForm = KeySyncUtils.packVaultParams(
SecureBox.genKeyPair().getPublic(),
- /*counterId=*/ 10021L,
- /*maxAttempts=*/ 10,
- deviceId);
+ /*counterId=*/ 1001L,
+ maxAttempts,
+ /*deviceId=*/ 1L);
ByteBuffer byteBuffer = ByteBuffer.wrap(packedForm)
.order(ByteOrder.LITTLE_ENDIAN);
- byteBuffer.position(PUBLIC_KEY_LENGTH_BYTES + Long.BYTES + Integer.BYTES);
- assertEquals(deviceId, byteBuffer.getLong());
+ byteBuffer.position(PUBLIC_KEY_LENGTH_BYTES + 2 * Long.BYTES);
+ assertEquals(maxAttempts, byteBuffer.getInt());
}
+
private static byte[] randomBytes(int n) {
byte[] bytes = new byte[n];
new Random().nextBytes(bytes);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index 6f13a9873909..97fbca2403bf 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -205,6 +205,14 @@ public class PlatformKeyManagerTest {
}
@Test
+ public void init_savesGenerationIdToDatabase() throws Exception {
+ mPlatformKeyManager.init();
+
+ assertEquals(1,
+ mRecoverableKeyStoreDb.getPlatformKeyGenerationId(USER_ID_FIXTURE));
+ }
+
+ @Test
public void init_setsGenerationIdTo1() throws Exception {
mPlatformKeyManager.init();
@@ -212,7 +220,38 @@ public class PlatformKeyManagerTest {
}
@Test
+ public void init_incrementsGenerationIdIfKeyIsUnavailable() throws Exception {
+ mPlatformKeyManager.init();
+
+ mPlatformKeyManager.init();
+
+ assertEquals(2, mPlatformKeyManager.getGenerationId());
+ }
+
+ @Test
+ public void init_doesNotIncrementGenerationIdIfKeyAvailable() throws Exception {
+ mPlatformKeyManager.init();
+ when(mKeyStoreProxy
+ .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+ + "platform/42/1/decrypt")).thenReturn(true);
+ when(mKeyStoreProxy
+ .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+ + "platform/42/1/encrypt")).thenReturn(true);
+
+ mPlatformKeyManager.init();
+
+ assertEquals(1, mPlatformKeyManager.getGenerationId());
+ }
+
+ @Test
+ public void getGenerationId_returnsMinusOneIfNotInitialized() throws Exception {
+ assertEquals(-1, mPlatformKeyManager.getGenerationId());
+ }
+
+ @Test
public void getDecryptKey_getsDecryptKeyWithCorrectAlias() throws Exception {
+ mPlatformKeyManager.init();
+
mPlatformKeyManager.getDecryptKey();
verify(mKeyStoreProxy).getKey(
@@ -222,6 +261,8 @@ public class PlatformKeyManagerTest {
@Test
public void getEncryptKey_getsDecryptKeyWithCorrectAlias() throws Exception {
+ mPlatformKeyManager.init();
+
mPlatformKeyManager.getEncryptKey();
verify(mKeyStoreProxy).getKey(
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
index f3cb98078602..212d25d42420 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
@@ -95,41 +95,6 @@ public class WatchlistSettingsTests {
}
@Test
- public void testWatchlistSettings_writeSettingsToDisk() throws Exception {
- copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
- WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
- settings.writeSettingsToDisk(Arrays.asList(TEST_NEW_CC_DOMAIN_CRC32),
- Arrays.asList(TEST_NEW_CC_DOMAIN_SHA256), Arrays.asList(TEST_NEW_CC_IP_CRC32),
- Arrays.asList(TEST_NEW_CC_IP_SHA256));
- // Ensure old watchlist is not in memory
- assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_CC_IP));
- assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
- assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
- assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
- // Ensure new watchlist is in memory
- assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
- assertTrue(settings.containsIp(TEST_NEW_CC_IP));
- // Reload settings from disk and test again
- settings = new WatchlistSettings(mTestXmlFile);
- // Ensure old watchlist is not in memory
- assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_CC_IP));
- assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
- assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
- assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
- // Ensure new watchlist is in memory
- assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
- assertTrue(settings.containsIp(TEST_NEW_CC_IP));
- }
-
- @Test
public void testWatchlistSettings_writeSettingsToMemory() throws Exception {
copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index e12a8da805f6..cdac516c9577 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -17,75 +17,93 @@
package com.android.server.pm;
import android.content.IIntentReceiver;
-
import android.os.Bundle;
+import android.support.test.runner.AndroidJUnit4;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.File;
// runtest -c com.android.server.pm.PackageManagerServiceTest frameworks-services
-
-@SmallTest
-public class PackageManagerServiceTest extends AndroidTestCase {
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+// bit FrameworksServicesTests:com.android.server.pm.PackageManagerServiceTest
+@RunWith(AndroidJUnit4.class)
+public class PackageManagerServiceTest {
+ @Before
+ public void setUp() throws Exception {
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
}
+ @Test
public void testPackageRemoval() throws Exception {
- class PackageSenderImpl implements PackageSender {
- public void sendPackageBroadcast(final String action, final String pkg,
- final Bundle extras, final int flags, final String targetPkg,
- final IIntentReceiver finishedReceiver, final int[] userIds,
- int[] instantUserIds) {
+ class PackageSenderImpl implements PackageSender {
+ public void sendPackageBroadcast(final String action, final String pkg,
+ final Bundle extras, final int flags, final String targetPkg,
+ final IIntentReceiver finishedReceiver, final int[] userIds,
+ int[] instantUserIds) {
+ }
+
+ public void sendPackageAddedForNewUsers(String packageName,
+ boolean sendBootComplete, boolean includeStopped, int appId,
+ int[] userIds, int[] instantUserIds) {
+ }
+
+ @Override
+ public void notifyPackageAdded(String packageName) {
+ }
+
+ @Override
+ public void notifyPackageRemoved(String packageName) {
+ }
}
- public void sendPackageAddedForNewUsers(String packageName,
- boolean sendBootComplete, boolean includeStopped, int appId,
- int[] userIds, int[] instantUserIds) {
- }
- }
-
- PackageSenderImpl sender = new PackageSenderImpl();
- PackageSetting setting = null;
- PackageManagerService.PackageRemovedInfo pri =
- new PackageManagerService.PackageRemovedInfo(sender);
-
- // Initial conditions: nothing there
- assertNull(pri.removedUsers);
- assertNull(pri.broadcastUsers);
-
- // populateUsers with nothing leaves nothing
- pri.populateUsers(null, setting);
- assertNull(pri.broadcastUsers);
-
- // Create a real (non-null) PackageSetting and confirm that the removed
- // users are copied properly
- setting = new PackageSetting("name", "realName", new File("codePath"),
- new File("resourcePath"), "legacyNativeLibraryPathString",
- "primaryCpuAbiString", "secondaryCpuAbiString",
- "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0,
- null, null);
- pri.populateUsers(new int[] {1, 2, 3, 4, 5}, setting);
- assertNotNull(pri.broadcastUsers);
- assertEquals(5, pri.broadcastUsers.length);
-
- // Exclude a user
- pri.broadcastUsers = null;
- final int EXCLUDED_USER_ID = 4;
- setting.setInstantApp(true, EXCLUDED_USER_ID);
- pri.populateUsers(new int[] {1, 2, 3, EXCLUDED_USER_ID, 5}, setting);
- assertNotNull(pri.broadcastUsers);
- assertEquals(5 - 1, pri.broadcastUsers.length);
-
- // TODO: test that sendApplicationHiddenForUser() actually fills in
- // broadcastUsers
+ PackageSenderImpl sender = new PackageSenderImpl();
+ PackageSetting setting = null;
+ PackageManagerService.PackageRemovedInfo pri =
+ new PackageManagerService.PackageRemovedInfo(sender);
+
+ // Initial conditions: nothing there
+ Assert.assertNull(pri.removedUsers);
+ Assert.assertNull(pri.broadcastUsers);
+
+ // populateUsers with nothing leaves nothing
+ pri.populateUsers(null, setting);
+ Assert.assertNull(pri.broadcastUsers);
+
+ // Create a real (non-null) PackageSetting and confirm that the removed
+ // users are copied properly
+ setting = new PackageSetting("name", "realName", new File("codePath"),
+ new File("resourcePath"), "legacyNativeLibraryPathString",
+ "primaryCpuAbiString", "secondaryCpuAbiString",
+ "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0,
+ null, null);
+ pri.populateUsers(new int[] {
+ 1, 2, 3, 4, 5
+ }, setting);
+ Assert.assertNotNull(pri.broadcastUsers);
+ Assert.assertEquals(5, pri.broadcastUsers.length);
+ Assert.assertNotNull(pri.instantUserIds);
+ Assert.assertEquals(0, pri.instantUserIds.length);
+
+ // Exclude a user
+ pri.broadcastUsers = null;
+ final int EXCLUDED_USER_ID = 4;
+ setting.setInstantApp(true, EXCLUDED_USER_ID);
+ pri.populateUsers(new int[] {
+ 1, 2, 3, EXCLUDED_USER_ID, 5
+ }, setting);
+ Assert.assertNotNull(pri.broadcastUsers);
+ Assert.assertEquals(4, pri.broadcastUsers.length);
+ Assert.assertNotNull(pri.instantUserIds);
+ Assert.assertEquals(1, pri.instantUserIds.length);
+
+ // TODO: test that sendApplicationHiddenForUser() actually fills in
+ // broadcastUsers
}
}
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
index 2d4bc0f8b7d0..029d9f1a8262 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
@@ -104,6 +104,15 @@ public class TestHandler extends Handler {
return new PriorityQueue<>(mMessages);
}
+ /**
+ * Optionally-overridable to allow deciphering message types
+ *
+ * @see android.util.DebugUtils#valueToString - a handy utility to use when overriding this
+ */
+ protected String messageToString(Message message) {
+ return message.toString();
+ }
+
private void dispatch(MsgInfo msg) {
int msgId = msg.message.what;
@@ -148,7 +157,7 @@ public class TestHandler extends Handler {
@Override
public String toString() {
return "MsgInfo{" +
- "message=" + message +
+ "message=" + messageToString(message) +
", sendTime=" + sendTime +
'}';
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 96ff46195002..6e57f47997fc 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -45,6 +45,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimatorTest}.
@@ -82,6 +83,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec);
+ waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
@@ -104,11 +106,13 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
// First animation was finished, but this shouldn't cancel the second animation
callbackCaptor.getValue().onAnimationFinished(mSpec);
+ waitUntilPrepareSurfaces();
assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
// Second animation was finished
verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec2);
+ waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
}
@@ -160,6 +164,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
+ waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
@@ -175,6 +180,14 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
assertNull(animatable.mSurfaceAnimator.getAnimation());
}
+ private void waitUntilPrepareSurfaces() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ synchronized (sWm.mWindowMap) {
+ sWm.mAnimator.addAfterPrepareSurfacesRunnable(latch::countDown);
+ }
+ latch.await();
+ }
+
private class MyAnimatable implements Animatable {
final SurfaceControl mParent;
@@ -233,6 +246,11 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
}
@Override
+ public SurfaceControl getAnimationLeashParent() {
+ return mParent;
+ }
+
+ @Override
public SurfaceControl getSurfaceControl() {
return mSurface;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java
new file mode 100644
index 000000000000..9cdef16194ff
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 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.wm;
+
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
+
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import android.view.animation.ClipRectAnimation;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link WindowAnimationSpec} class.
+ *
+ * atest FrameworksServicesTests:com.android.server.wm.WindowAnimationSpecTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowAnimationSpecTest {
+ private final SurfaceControl mSurfaceControl = mock(SurfaceControl.class);
+ private final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
+ private final Animation mAnimation = mock(Animation.class);
+ private final Rect mStackBounds = new Rect(0, 0, 10, 10);
+
+ @Test
+ public void testApply_clipNone() {
+ Rect windowCrop = new Rect(0, 0, 20, 20);
+ Animation a = new ClipRectAnimation(windowCrop, windowCrop);
+ WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE);
+ windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+ verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+ argThat(rect -> rect.equals(windowCrop)));
+ }
+
+ @Test
+ public void testApply_clipAfter() {
+ WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM);
+ windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+ verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
+ verify(mTransaction).setFinalCrop(eq(mSurfaceControl),
+ argThat(rect -> rect.equals(mStackBounds)));
+ }
+
+ @Test
+ public void testApply_clipBeforeNoAnimationBounds() {
+ // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 0, 0)
+ WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+ verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+ argThat(rect -> rect.equals(mStackBounds)));
+ }
+
+ @Test
+ public void testApply_clipBeforeNoStackBounds() {
+ // Stack bounds is (0, 0, 0, 0) animation clip is (0, 0, 20, 20)
+ Rect windowCrop = new Rect(0, 0, 20, 20);
+ Animation a = new ClipRectAnimation(windowCrop, windowCrop);
+ WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
+ null, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+ verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
+ }
+
+ @Test
+ public void testApply_clipBeforeSmallerAnimationClip() {
+ // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 5, 5)
+ Rect windowCrop = new Rect(0, 0, 5, 5);
+ Animation a = new ClipRectAnimation(windowCrop, windowCrop);
+ WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+ verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+ argThat(rect -> rect.equals(windowCrop)));
+ }
+
+ @Test
+ public void testApply_clipBeforeSmallerStackClip() {
+ // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 20, 20)
+ Rect windowCrop = new Rect(0, 0, 20, 20);
+ Animation a = new ClipRectAnimation(windowCrop, windowCrop);
+ WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+ verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+ argThat(rect -> rect.equals(mStackBounds)));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index c699a94db279..ff840f3aeea9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -103,6 +103,7 @@ class WindowTestsBase {
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay();
+ sWm.mAnimator.mInitialized = true;
sWm.mDisplayEnabled = true;
sWm.mDisplayReady = true;
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/provider/Telephony.java
index 942ea009f684..942ea009f684 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 973df316d280..176057ddc23e 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -15,8 +15,10 @@
*/
package android.telephony.euicc;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
@@ -29,6 +31,9 @@ import android.os.ServiceManager;
import com.android.internal.telephony.euicc.IEuiccController;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
*
@@ -167,6 +172,35 @@ public class EuiccManager {
*/
public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
+ /**
+ * Euicc OTA update status which can be got by {@link #getOtaStatus}
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EUICC_OTA_"}, value = {
+ EUICC_OTA_IN_PROGRESS,
+ EUICC_OTA_FAILED,
+ EUICC_OTA_SUCCEEDED,
+ EUICC_OTA_NOT_NEEDED,
+ EUICC_OTA_STATUS_UNAVAILABLE
+
+ })
+ public @interface OtaStatus{}
+
+ /**
+ * An OTA is in progress. During this time, the eUICC is not available and the user may lose
+ * network access.
+ */
+ public static final int EUICC_OTA_IN_PROGRESS = 1;
+ /** The OTA update failed. */
+ public static final int EUICC_OTA_FAILED = 2;
+ /** The OTA update finished successfully. */
+ public static final int EUICC_OTA_SUCCEEDED = 3;
+ /** The OTA update not needed since current eUICC OS is latest. */
+ public static final int EUICC_OTA_NOT_NEEDED = 4;
+ /** The OTA status is unavailable since eUICC service is unavailable. */
+ public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
+
private final Context mContext;
/** @hide */
@@ -211,6 +245,26 @@ public class EuiccManager {
}
/**
+ * Returns the current status of eUICC OTA.
+ *
+ * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
+ * @return the status of eUICC OTA. If {@link #isEnabled()} is false or the eUICC is not ready,
+ * {@link OtaStatus#EUICC_OTA_STATUS_UNAVAILABLE} will be returned.
+ */
+ @SystemApi
+ public int getOtaStatus() {
+ if (!isEnabled()) {
+ return EUICC_OTA_STATUS_UNAVAILABLE;
+ }
+ try {
+ return getIEuiccController().getOtaStatus();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Attempt to download the given {@link DownloadableSubscription}.
*
* <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index e2d25b8e352c..f804cb068b31 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -417,6 +417,8 @@ cat include/telephony/ril.h | \
int RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION = 141;
int RIL_REQUEST_START_NETWORK_SCAN = 142;
int RIL_REQUEST_STOP_NETWORK_SCAN = 143;
+ int RIL_REQUEST_GET_SLOT_STATUS = 144;
+ int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 145;
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
@@ -471,4 +473,5 @@ cat include/telephony/ril.h | \
int RIL_UNSOL_MODEM_RESTART = 1047;
int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1048;
int RIL_UNSOL_NETWORK_SCAN_RESULT = 1049;
+ int RIL_UNSOL_ICC_SLOT_STATUS = 1050;
}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index b3fc90db75d3..0a0ad90b5954 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -30,6 +30,7 @@ interface IEuiccController {
oneway void getDefaultDownloadableSubscriptionList(
String callingPackage, in PendingIntent callbackIntent);
String getEid();
+ int getOtaStatus();
oneway void downloadSubscription(in DownloadableSubscription subscription,
boolean switchAfterDownload, String callingPackage, in PendingIntent callbackIntent);
EuiccInfo getEuiccInfo();
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk
new file mode 100644
index 000000000000..7187a3795433
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/Android.mk
@@ -0,0 +1,49 @@
+#
+# Copyright 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build a tiny library that the test app can dynamically load
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := DexLoggerTestLibrary
+LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl)
+
+include $(BUILD_JAVA_LIBRARY)
+
+dexloggertest_jar := $(LOCAL_BUILT_MODULE)
+
+
+# Build the test app itself
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := DexLoggerIntegrationTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ truth-prebuilt \
+
+# This gets us the javalib.jar built by DexLoggerTestLibrary above.
+LOCAL_JAVA_RESOURCE_FILES := $(dexloggertest_jar)
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DexLoggerIntegrationTests/AndroidManifest.xml b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
new file mode 100644
index 000000000000..a847e8f3b921
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.dexloggertest">
+
+ <!-- Tests feature introduced in P (27) -->
+ <uses-sdk
+ android:minSdkVersion="27"
+ android:targetSdkVersion="27" />
+
+ <uses-permission android:name="android.permission.READ_LOGS" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.dexloggertest"
+ android:label="Integration test for DexLogger" />
+</manifest>
diff --git a/tests/DexLoggerIntegrationTests/AndroidTest.xml b/tests/DexLoggerIntegrationTests/AndroidTest.xml
new file mode 100644
index 000000000000..8ed19f893476
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<configuration description="Runs DexLogger Integration Tests">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="DexLoggerIntegrationTests.apk"/>
+ <option name="cleanup-apks" value="true"/>
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="DexLoggerIntegrationTests"/>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.dexloggertest"/>
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java b/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java
new file mode 100644
index 000000000000..e995a26ea5c9
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 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.
+ */
+
+package com.android.dcl;
+
+/** Dummy class which is built into a jar purely so we can pass it to DexClassLoader. */
+public final class Simple {
+ public Simple() {}
+}
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/DexLoggerIntegrationTests.java b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/DexLoggerIntegrationTests.java
new file mode 100644
index 000000000000..d9f34d589c41
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/DexLoggerIntegrationTests.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 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.
+ */
+
+package com.android.server.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.util.EventLog;
+
+import dalvik.system.DexClassLoader;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.List;
+
+/**
+ * Integration tests for {@link com.android.server.pm.dex.DexLogger}.
+ *
+ * The setup for the test dynamically loads code in a jar extracted
+ * from our assets (a secondary dex file).
+ *
+ * We then use adb to trigger secondary dex file reconcilation (and
+ * wait for it to complete). As a side-effect of this DexLogger should
+ * be notified of the file and should log the hash of the file's name
+ * and content. We verify that this message appears in the event log.
+ *
+ * Run with "atest DexLoggerIntegrationTests".
+ */
+@RunWith(JUnit4.class)
+public final class DexLoggerIntegrationTests {
+
+ private static final String TAG = DexLoggerIntegrationTests.class.getSimpleName();
+
+ private static final String PACKAGE_NAME = "com.android.frameworks.dexloggertest";
+
+ private static final int SNET_TAG = 0x534e4554;
+ private static final String DCL_SUBTAG = "dcl";
+
+ // Obtained via "echo -n copied.jar | sha256sum"
+ private static final String EXPECTED_NAME_HASH =
+ "1B6C71DB26F36582867432CCA12FB6A517470C9F9AABE9198DD4C5C030D6DC0C";
+
+ private static String expectedContentHash;
+
+ @BeforeClass
+ public static void setUpAll() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+ MessageDigest hasher = MessageDigest.getInstance("SHA-256");
+
+ // Copy the jar from our Java resources to a private data directory
+ File privateCopy = new File(context.getDir("jars", Context.MODE_PRIVATE), "copied.jar");
+ try (InputStream input = DexLoggerIntegrationTests.class.getResourceAsStream("/javalib.jar");
+ OutputStream output = new FileOutputStream(privateCopy)) {
+ byte[] buffer = new byte[1024];
+ while (true) {
+ int numRead = input.read(buffer);
+ if (numRead < 0) {
+ break;
+ }
+ output.write(buffer, 0, numRead);
+ hasher.update(buffer, 0, numRead);
+ }
+ }
+
+ // Remember the SHA-256 of the file content to check that it is the same as
+ // the value we see logged.
+ Formatter formatter = new Formatter();
+ for (byte b : hasher.digest()) {
+ formatter.format("%02X", b);
+ }
+ expectedContentHash = formatter.toString();
+
+ // Feed the jar to a class loader and make sure it contains what we expect.
+ ClassLoader loader =
+ new DexClassLoader(
+ privateCopy.toString(), null, null, context.getClass().getClassLoader());
+ loader.loadClass("com.android.dcl.Simple");
+ }
+
+ @Test
+ public void testDexLoggerReconcileGeneratesEvents() throws Exception {
+ int[] tagList = new int[] { SNET_TAG };
+ List<EventLog.Event> events = new ArrayList<>();
+
+ // There may already be events in the event log - figure out the most recent one
+ EventLog.readEvents(tagList, events);
+ long previousEventNanos = events.isEmpty() ? 0 : events.get(events.size() - 1).getTimeNanos();
+ events.clear();
+
+ Process process = Runtime.getRuntime().exec(
+ "cmd package reconcile-secondary-dex-files " + PACKAGE_NAME);
+ int exitCode = process.waitFor();
+ assertThat(exitCode).isEqualTo(0);
+
+ int myUid = android.os.Process.myUid();
+ String expectedMessage = EXPECTED_NAME_HASH + " " + expectedContentHash;
+
+ EventLog.readEvents(tagList, events);
+ boolean found = false;
+ for (EventLog.Event event : events) {
+ if (event.getTimeNanos() <= previousEventNanos) {
+ continue;
+ }
+ Object[] data = (Object[]) event.getData();
+
+ // We only care about DCL events that we generated.
+ String subTag = (String) data[0];
+ if (!DCL_SUBTAG.equals(subTag)) {
+ continue;
+ }
+ int uid = (int) data[1];
+ if (uid != myUid) {
+ continue;
+ }
+
+ String message = (String) data[2];
+ assertThat(message).isEqualTo(expectedMessage);
+ found = true;
+ }
+
+ assertThat(found).isTrue();
+ }
+}
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 765079507513..102bbf9d07d7 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -20,6 +20,7 @@
#include <map>
#include <set>
#include <string>
+#include <sstream>
using namespace android;
using namespace android::os;
@@ -482,9 +483,44 @@ static bool generateSectionListCpp(Descriptor const* descriptor) {
}
// ================================================================================
+static string replace_string(const string& str, const char replace, const char with)
+{
+ string result(str);
+ const int N = result.size();
+ for (int i=0; i<N; i++) {
+ if (result[i] == replace) {
+ result[i] = with;
+ }
+ }
+ return result;
+}
+
+static void generateCsv(Descriptor const* descriptor, const string& indent, set<string>* parents) {
+ DebugStringOptions options;
+ options.include_comments = true;
+ for (int i=0; i<descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ stringstream text;
+ if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ text << field->message_type()->name();
+ } else {
+ text << field->type_name();
+ }
+ text << " " << field->name();
+ printf("%s%s,\n", indent.c_str(), replace_string(text.str(), '\n', ' ').c_str());
+ if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
+ parents->find(field->message_type()->full_name()) == parents->end()) {
+ parents->insert(field->message_type()->full_name());
+ generateCsv(field->message_type(), indent + ",", parents);
+ parents->erase(field->message_type()->full_name());
+ }
+ }
+}
+
+// ================================================================================
int main(int argc, char const *argv[])
{
- if (argc != 2) return 1;
+ if (argc < 2) return 1;
const char* module = argv[1];
Descriptor const* descriptor = IncidentProto::descriptor();
@@ -495,7 +531,23 @@ int main(int argc, char const *argv[])
if (strcmp(module, "incidentd") == 0 ) {
return !generateSectionListCpp(descriptor);
}
-
- // return failure if not called by the whitelisted modules
+ // Generates Csv Format of proto definition for each section.
+ if (strcmp(module, "csv") == 0 && argc > 2) {
+ int sectionId = atoi(argv[2]);
+ for (int i=0; i<descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (strcmp(field->name().c_str(), argv[2]) == 0
+ || field->number() == sectionId) {
+ set<string> parents;
+ printf("%s\n", field->name().c_str());
+ generateCsv(field->message_type(), "", &parents);
+ break;
+ }
+ }
+ // Returns failure if csv is enabled to prevent Android building with it.
+ // It doesn't matter if this command runs manually.
+ return 1;
+ }
+ // Returns failure if not called by the whitelisted modules
return 1;
}
diff --git a/tools/sdkparcelables/Android.bp b/tools/sdkparcelables/Android.bp
new file mode 100644
index 000000000000..00fb8aa20b18
--- /dev/null
+++ b/tools/sdkparcelables/Android.bp
@@ -0,0 +1,22 @@
+java_binary_host {
+ name: "sdkparcelables",
+ manifest: "manifest.txt",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "asm-6.0",
+ ],
+}
+
+java_library_host {
+ name: "sdkparcelables_test",
+ manifest: "manifest.txt",
+ srcs: [
+ "tests/**/*.kt",
+ ],
+ static_libs: [
+ "sdkparcelables",
+ "junit",
+ ],
+}
diff --git a/tools/sdkparcelables/manifest.txt b/tools/sdkparcelables/manifest.txt
new file mode 100644
index 000000000000..cd5420ce0bf4
--- /dev/null
+++ b/tools/sdkparcelables/manifest.txt
@@ -0,0 +1 @@
+Main-class: com.android.sdkparcelables.MainKt
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt
new file mode 100644
index 000000000000..f278aec8eb6f
--- /dev/null
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt
@@ -0,0 +1,28 @@
+package com.android.sdkparcelables
+
+import org.objectweb.asm.ClassVisitor
+import java.util.*
+
+data class Ancestors(val superName: String?, val interfaces: List<String>?)
+
+/** A class that implements an ASM ClassVisitor that collects super class and
+ * implemented interfaces for each class that it visits.
+ */
+class AncestorCollector(api: Int, dest: ClassVisitor?) : ClassVisitor(api, dest) {
+ private val _ancestors = LinkedHashMap<String, Ancestors>()
+
+ val ancestors: Map<String, Ancestors>
+ get() = _ancestors
+
+ override fun visit(version: Int, access: Int, name: String?, signature: String?,
+ superName: String?, interfaces: Array<out String>?) {
+ name!!
+
+ val old = _ancestors.put(name, Ancestors(superName, interfaces?.toList()))
+ if (old != null) {
+ throw RuntimeException("class $name already found")
+ }
+
+ super.visit(version, access, name, signature, superName, interfaces)
+ }
+} \ No newline at end of file
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
new file mode 100644
index 000000000000..3e9d92cd978f
--- /dev/null
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
@@ -0,0 +1,56 @@
+package com.android.sdkparcelables
+
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.Opcodes
+import java.io.File
+import java.io.IOException
+import java.util.zip.ZipFile
+
+fun main(args: Array<String>) {
+ if (args.size != 2) {
+ usage()
+ }
+
+ val zipFileName = args[0]
+ val aidlFileName = args[1]
+
+ val zipFile: ZipFile
+
+ try {
+ zipFile = ZipFile(zipFileName)
+ } catch (e: IOException) {
+ System.err.println("error reading input jar: ${e.message}")
+ kotlin.system.exitProcess(2)
+ }
+
+ val ancestorCollector = AncestorCollector(Opcodes.ASM6, null)
+
+ for (entry in zipFile.entries()) {
+ if (entry.name.endsWith(".class")) {
+ val reader = ClassReader(zipFile.getInputStream(entry))
+ reader.accept(ancestorCollector,
+ ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
+ }
+ }
+
+ val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorCollector.ancestors)
+
+ try {
+ val outFile = File(aidlFileName)
+ val outWriter = outFile.bufferedWriter()
+ for (parcelable in parcelables) {
+ outWriter.write("parcelable ")
+ outWriter.write(parcelable.replace('/', '.').replace('$', '.'))
+ outWriter.write(";\n")
+ }
+ outWriter.flush()
+ } catch (e: IOException) {
+ System.err.println("error writing output aidl: ${e.message}")
+ kotlin.system.exitProcess(2)
+ }
+}
+
+fun usage() {
+ System.err.println("Usage: <input jar> <output aidl>")
+ kotlin.system.exitProcess(1)
+} \ No newline at end of file
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
new file mode 100644
index 000000000000..620f798daf48
--- /dev/null
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
@@ -0,0 +1,52 @@
+package com.android.sdkparcelables
+
+/** A class that uses an ancestor map to find all classes that
+ * implement android.os.Parcelable, including indirectly through
+ * super classes or super interfaces.
+ */
+class ParcelableDetector {
+ companion object {
+ fun ancestorsToParcelables(ancestors: Map<String, Ancestors>): List<String> {
+ val impl = Impl(ancestors)
+ impl.build()
+ return impl.parcelables
+ }
+ }
+
+ private class Impl(val ancestors: Map<String, Ancestors>) {
+ val isParcelableCache = HashMap<String, Boolean>()
+ val parcelables = ArrayList<String>()
+
+ fun build() {
+ val classList = ancestors.keys
+ classList.filterTo(parcelables, this::isParcelable)
+ parcelables.sort()
+ }
+
+ private fun isParcelable(c: String?): Boolean {
+ if (c == null) {
+ return false
+ }
+
+ if (c == "android/os/Parcelable") {
+ return true
+ }
+
+ val old = isParcelableCache[c]
+ if (old != null) {
+ return old
+ }
+
+ val cAncestors = ancestors[c] ?:
+ throw RuntimeException("class $c missing ancestor information")
+
+ val seq = (cAncestors.interfaces?.asSequence() ?: emptySequence()) +
+ cAncestors.superName
+
+ val ancestorIsParcelable = seq.any(this::isParcelable)
+
+ isParcelableCache[c] = ancestorIsParcelable
+ return ancestorIsParcelable
+ }
+ }
+}
diff --git a/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
new file mode 100644
index 000000000000..edfc8259a738
--- /dev/null
+++ b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
@@ -0,0 +1,57 @@
+package com.android.sdkparcelables
+
+import junit.framework.TestCase.assertEquals
+import org.junit.Test
+
+class ParcelableDetectorTest {
+ @Test
+ fun `detect implements`() {
+ val ancestorMap = mapOf(
+ testAncestors("android/test/Parcelable",null, "android/os/Parcelable"),
+ testAncestors("android/os/Parcelable", null))
+
+ val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
+
+ assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable"))
+ }
+
+ @Test
+ fun `detect implements in reverse order`() {
+ val ancestorMap = mapOf(
+ testAncestors("android/os/Parcelable", null),
+ testAncestors("android/test/Parcelable",null, "android/os/Parcelable"))
+
+ val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
+
+ assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable"))
+ }
+
+ @Test
+ fun `detect super implements`() {
+ val ancestorMap = mapOf(
+ testAncestors("android/test/SuperParcelable",null, "android/os/Parcelable"),
+ testAncestors("android/test/Parcelable","android/test/SuperParcelable"),
+ testAncestors("android/os/Parcelable", null))
+
+ val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
+
+ assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable", "android/test/SuperParcelable"))
+ }
+
+ @Test
+ fun `detect super interface`() {
+ val ancestorMap = mapOf(
+ testAncestors("android/test/IParcelable",null, "android/os/Parcelable"),
+ testAncestors("android/test/Parcelable",null, "android/test/IParcelable"),
+ testAncestors("android/os/Parcelable", null))
+
+ val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
+
+ assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/IParcelable", "android/test/Parcelable"))
+ }
+
+}
+
+private fun testAncestors(name: String, superName: String?, vararg interfaces: String): Pair<String, Ancestors> {
+ return Pair(name, Ancestors(superName, interfaces.toList()))
+}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index e3752ac77a5e..928a1da8b51c 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -160,6 +160,24 @@ public class WifiScanner {
*/
public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
+ /**
+ * This is used to indicate the purpose of the scan to the wifi chip in
+ * {@link ScanSettings#type}.
+ * On devices with multiple hardware radio chains (and hence different modes of scan),
+ * this type serves as an indication to the hardware on what mode of scan to perform.
+ * Only apps holding android.Manifest.permission.NETWORK_STACK permission can set this value.
+ *
+ * Note: This serves as an intent and not as a stipulation, the wifi chip
+ * might honor or ignore the indication based on the current radio conditions. Always
+ * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration used
+ * to receive the corresponding scan result.
+ */
+ /** {@hide} */
+ public static final int TYPE_LOW_LATENCY = 0;
+ /** {@hide} */
+ public static final int TYPE_LOW_POWER = 1;
+ /** {@hide} */
+ public static final int TYPE_HIGH_ACCURACY = 2;
/** {@hide} */
public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
@@ -193,7 +211,8 @@ public class WifiScanner {
* list of hidden networks to scan for. Explicit probe requests are sent out for such
* networks during scan. Only valid for single scan requests.
* {@hide}
- * */
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public HiddenNetwork[] hiddenNetworks;
/** period of background scan; in millisecond, 0 => single shot scan */
public int periodInMs;
@@ -223,6 +242,13 @@ public class WifiScanner {
* {@hide}
*/
public boolean isPnoScan;
+ /**
+ * Indicate the type of scan to be performed by the wifi chip.
+ * Default value: {@link #TYPE_LOW_LATENCY}.
+ * {@hide}
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+ public int type = TYPE_LOW_LATENCY;
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
@@ -239,6 +265,7 @@ public class WifiScanner {
dest.writeInt(maxPeriodInMs);
dest.writeInt(stepCount);
dest.writeInt(isPnoScan ? 1 : 0);
+ dest.writeInt(type);
if (channels != null) {
dest.writeInt(channels.length);
for (int i = 0; i < channels.length; i++) {
@@ -272,6 +299,7 @@ public class WifiScanner {
settings.maxPeriodInMs = in.readInt();
settings.stepCount = in.readInt();
settings.isPnoScan = in.readInt() == 1;
+ settings.type = in.readInt();
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];
for (int i = 0; i < num_channels; i++) {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index d57d1524d083..2f0c3163aa0c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -269,6 +269,10 @@ public class WifiAwareManager {
+ identityChangedListener);
}
+ if (attachCallback == null) {
+ throw new IllegalArgumentException("Null callback provided");
+ }
+
synchronized (mLock) {
Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
@@ -300,6 +304,10 @@ public class WifiAwareManager {
DiscoverySessionCallback callback) {
if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
+ if (callback == null) {
+ throw new IllegalArgumentException("Null callback provided");
+ }
+
try {
mService.publish(mContext.getOpPackageName(), clientId, publishConfig,
new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback,
@@ -333,6 +341,10 @@ public class WifiAwareManager {
}
}
+ if (callback == null) {
+ throw new IllegalArgumentException("Null callback provided");
+ }
+
try {
mService.subscribe(mContext.getOpPackageName(), clientId, subscribeConfig,
new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback,
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index 8b86cdde4a9e..2ea6e797ec93 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -26,13 +26,49 @@ import android.os.Handler;
*/
public abstract class ProvisioningCallback {
- /**
+ /**
* The reason code for Provisioning Failure due to connection failure to OSU AP.
* @hide
*/
public static final int OSU_FAILURE_AP_CONNECTION = 1;
/**
+ * The reason code for Provisioning Failure due to connection failure to OSU AP.
+ * @hide
+ */
+ public static final int OSU_FAILURE_SERVER_URL_INVALID = 2;
+
+ /**
+ * The reason code for Provisioning Failure due to connection failure to OSU AP.
+ * @hide
+ */
+ public static final int OSU_FAILURE_SERVER_CONNECTION = 3;
+
+ /**
+ * The reason code for Provisioning Failure due to connection failure to OSU AP.
+ * @hide
+ */
+ public static final int OSU_FAILURE_SERVER_VALIDATION = 4;
+
+ /**
+ * The reason code for Provisioning Failure due to connection failure to OSU AP.
+ * @hide
+ */
+ public static final int OSU_FAILURE_PROVIDER_VERIFICATION = 5;
+
+ /**
+ * The reason code for Provisioning Failure when a provisioning flow is aborted.
+ * @hide
+ */
+ public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6;
+
+ /**
+ * The reason code for Provisioning Failure when a provisioning flow is aborted.
+ * @hide
+ */
+ public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7;
+
+ /**
* The status code for Provisioning flow to indicate connecting to OSU AP
* @hide
*/
@@ -45,6 +81,24 @@ public abstract class ProvisioningCallback {
public static final int OSU_STATUS_AP_CONNECTED = 2;
/**
+ * The status code for Provisioning flow to indicate connecting to OSU AP
+ * @hide
+ */
+ public static final int OSU_STATUS_SERVER_CONNECTED = 3;
+
+ /**
+ * The status code for Provisioning flow to indicate connecting to OSU AP
+ * @hide
+ */
+ public static final int OSU_STATUS_SERVER_VALIDATED = 4;
+
+ /**
+ * The status code for Provisioning flow to indicate connecting to OSU AP
+ * @hide
+ */
+ public static final int OSU_STATUS_PROVIDER_VERIFIED = 5;
+
+ /**
* Provisioning status for OSU failure
* @param status indicates error condition
*/
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
index 8be7782d5664..c3e10074c56c 100644
--- a/wifi/java/android/net/wifi/rtt/ResponderConfig.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
@@ -37,7 +37,7 @@ import java.util.Objects;
*
* @hide (@SystemApi)
*/
-public class ResponderConfig implements Parcelable {
+public final class ResponderConfig implements Parcelable {
private static final int AWARE_BAND_2_DISCOVERY_CHANNEL = 2437;
/** @hide */
@@ -122,15 +122,14 @@ public class ResponderConfig implements Parcelable {
/**
* The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the
* peerHandle field) ise used to identify the Responder.
- * TODO: convert to MacAddress
*/
- public MacAddress macAddress;
+ public final MacAddress macAddress;
/**
* The peer identifier of a Wi-Fi Aware Responder. Will be null if a MAC Address (the macAddress
* field) is used to identify the Responder.
*/
- public PeerHandle peerHandle;
+ public final PeerHandle peerHandle;
/**
* The device type of the Responder.
@@ -171,7 +170,7 @@ public class ResponderConfig implements Parcelable {
public final int preamble;
/**
- * Constructs Responder configuration.
+ * Constructs Responder configuration, using a MAC address to identify the Responder.
*
* @param macAddress The MAC address of the Responder.
* @param responderType The type of the responder device, specified using
@@ -210,7 +209,7 @@ public class ResponderConfig implements Parcelable {
}
/**
- * Constructs Responder configuration.
+ * Constructs Responder configuration, using a Wi-Fi Aware PeerHandle to identify the Responder.
*
* @param peerHandle The Wi-Fi Aware peer identifier of the Responder.
* @param responderType The type of the responder device, specified using
@@ -245,6 +244,45 @@ public class ResponderConfig implements Parcelable {
}
/**
+ * Constructs Responder configuration. This is an internal-only constructor which specifies both
+ * a MAC address and a Wi-Fi PeerHandle to identify the Responder.
+ *
+ * @param macAddress The MAC address of the Responder.
+ * @param peerHandle The Wi-Fi Aware peer identifier of the Responder.
+ * @param responderType The type of the responder device, specified using
+ * {@link ResponderType}.
+ * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc.
+ * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}.
+ * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder.
+ * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses
+ * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the
+ * Responder uses 80 + 80 MHz, this is the center frequency of the first
+ * segment (in MHz).
+ * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the
+ * Responder
+ * uses 80 + 80 MHz, this is the center frequency of the second segment
+ * (in
+ * MHz).
+ * @param preamble The preamble used by the Responder, specified using
+ * {@link PreambleType}.
+ * @hide
+ */
+ public ResponderConfig(@NonNull MacAddress macAddress, @NonNull PeerHandle peerHandle,
+ @ResponderType int responderType, boolean supports80211mc,
+ @ChannelWidth int channelWidth, int frequency, int centerFreq0, int centerFreq1,
+ @PreambleType int preamble) {
+ this.macAddress = macAddress;
+ this.peerHandle = peerHandle;
+ this.responderType = responderType;
+ this.supports80211mc = supports80211mc;
+ this.channelWidth = channelWidth;
+ this.frequency = frequency;
+ this.centerFreq0 = centerFreq0;
+ this.centerFreq1 = centerFreq1;
+ this.preamble = preamble;
+ }
+
+ /**
* Creates a Responder configuration from a {@link ScanResult} corresponding to an Access
* Point (AP), which can be obtained from {@link android.net.wifi.WifiManager#getScanResults()}.
*/
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index b4c690f4840d..240b3c1e3b51 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -123,6 +123,10 @@ public class WifiRttManager {
+ ", callback=" + callback + ", handler=" + handler);
}
+ if (callback == null) {
+ throw new IllegalArgumentException("Null callback provided");
+ }
+
Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index e542789e01e3..a4366d454a67 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -16,19 +16,23 @@
package android.net.wifi;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Handler;
+import android.os.Parcel;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
+import android.net.wifi.WifiScanner.ScanSettings;
import com.android.internal.util.test.BidirectionalAsyncChannelServer;
import org.junit.After;
import org.junit.Before;
+import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -70,4 +74,50 @@ public class WifiScannerTest {
validateMockitoUsage();
}
+ /**
+ * Verify parcel read/write for ScanSettings.
+ */
+ @Test
+ public void verifyScanSettingsParcelWithBand() throws Exception {
+ ScanSettings writeSettings = new ScanSettings();
+ writeSettings.type = WifiScanner.TYPE_LOW_POWER;
+ writeSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
+
+ ScanSettings readSettings = parcelWriteRead(writeSettings);
+ assertEquals(readSettings.type, writeSettings.type);
+ assertEquals(readSettings.band, writeSettings.band);
+ assertEquals(0, readSettings.channels.length);
+ }
+
+ /**
+ * Verify parcel read/write for ScanSettings.
+ */
+ @Test
+ public void verifyScanSettingsParcelWithChannels() throws Exception {
+ ScanSettings writeSettings = new ScanSettings();
+ writeSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
+ writeSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
+ writeSettings.channels = new WifiScanner.ChannelSpec[] {
+ new WifiScanner.ChannelSpec(5),
+ new WifiScanner.ChannelSpec(7)
+ };
+
+ ScanSettings readSettings = parcelWriteRead(writeSettings);
+ assertEquals(writeSettings.type, readSettings.type);
+ assertEquals(writeSettings.band, readSettings.band);
+ assertEquals(2, readSettings.channels.length);
+ assertEquals(5, readSettings.channels[0].frequency);
+ assertEquals(7, readSettings.channels[1].frequency);
+ }
+
+ /**
+ * Write the provided {@link ScanSettings} to a parcel and deserialize it.
+ */
+ private static ScanSettings parcelWriteRead(ScanSettings writeSettings) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ writeSettings.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ return ScanSettings.CREATOR.createFromParcel(parcel);
+ }
+
}