summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk5
-rw-r--r--StubLibraries.bp20
-rw-r--r--apex/Android.bp18
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java10
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java10
-rw-r--r--apex/jobscheduler/service/java/com/android/server/TEST_MAPPING1
-rw-r--r--apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING1
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING2
-rw-r--r--apex/media/framework/Android.bp6
-rw-r--r--apex/permission/framework/Android.bp9
-rw-r--r--apex/sdkextensions/framework/Android.bp6
-rw-r--r--apex/statsd/framework/Android.bp30
-rw-r--r--api/current.txt15
-rw-r--r--cmds/content/src/com/android/commands/content/Content.java193
-rw-r--r--cmds/statsd/Android.bp99
-rw-r--r--cmds/statsd/benchmark/duration_metric_benchmark.cpp272
-rw-r--r--cmds/statsd/benchmark/filter_value_benchmark.cpp37
-rw-r--r--cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp35
-rw-r--r--cmds/statsd/benchmark/log_event_benchmark.cpp3
-rw-r--r--cmds/statsd/benchmark/metric_util.cpp199
-rw-r--r--cmds/statsd/benchmark/metric_util.h60
-rw-r--r--cmds/statsd/src/atom_field_options.proto2
-rw-r--r--cmds/statsd/src/atoms.proto53
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp2
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h4
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp13
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h1
-rw-r--r--cmds/statsd/src/statsd_metadata.proto63
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp35
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp52
-rw-r--r--core/java/android/app/AppOpsManager.java4
-rw-r--r--core/java/android/app/ApplicationExitInfo.java8
-rw-r--r--core/java/android/app/ContextImpl.java5
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/app/LoadedApk.java5
-rw-r--r--core/java/android/app/ResourcesManager.java24
-rw-r--r--core/java/android/bluetooth/BluetoothHearingAid.java10
-rw-r--r--core/java/android/content/ContentProvider.java19
-rw-r--r--core/java/android/content/ContentResolver.java41
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java24
-rw-r--r--core/java/android/content/pm/CrossProfileApps.java28
-rw-r--r--core/java/android/content/pm/ICrossProfileApps.aidl1
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java4
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java29
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageRead.java6
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java3
-rw-r--r--core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl4
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java1
-rw-r--r--core/java/android/net/NetworkCapabilities.java29
-rw-r--r--core/java/android/os/Process.java12
-rw-r--r--core/java/android/os/ZygoteProcess.java38
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl1
-rw-r--r--core/java/android/os/storage/StorageManager.java37
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/service/autofill/InlinePresentation.java3
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java1
-rw-r--r--core/java/android/view/SurfaceView.java14
-rw-r--r--core/java/com/android/internal/accessibility/AccessibilityShortcutController.java7
-rw-r--r--core/java/com/android/internal/os/Zygote.java29
-rw-r--r--core/java/com/android/internal/os/ZygoteArguments.java15
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java3
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp109
-rw-r--r--core/res/res/values/attrs_manifest.xml18
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/res/res/values/themes.xml2
-rw-r--r--core/tests/coretests/src/android/content/ContentResolverTest.java11
-rw-r--r--core/tests/coretests/src/android/content/FakeProviderRemote.java3
-rw-r--r--core/tests/coretests/src/android/content/res/ResourcesManagerTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java35
-rw-r--r--data/etc/hiddenapi-package-whitelist.xml3
-rw-r--r--media/java/android/media/AudioSystem.java2
-rw-r--r--media/jni/android_media_tv_Tuner.cpp42
-rw-r--r--media/jni/android_media_tv_Tuner.h1
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java16
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java32
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java19
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java13
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt33
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java370
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java450
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java312
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java11
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp7
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java52
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java86
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt262
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java12
-rw-r--r--services/Android.bp5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java11
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java3
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java133
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java23
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java32
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java21
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java74
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java47
-rw-r--r--services/core/java/com/android/server/audio/RecordingActivityMonitor.java33
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java11
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationClient.java12
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java34
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java11
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java5
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java5
-rw-r--r--services/core/java/com/android/server/incident/IncidentCompanionService.java9
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java6
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java6
-rw-r--r--services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java124
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java21
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java22
-rw-r--r--services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java12
-rw-r--r--services/core/java/com/android/server/power/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java48
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java11
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java7
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java21
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java3
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java32
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java10
-rw-r--r--services/core/java/com/android/server/wm/Task.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java81
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java40
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp63
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java5
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/Android.bp37
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidManifest.xml29
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidTest.xml29
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java57
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java2
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java4
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java30
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthCdma.java2
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthGsm.java2
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java2
-rw-r--r--tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java4
-rw-r--r--tools/stats_log_api_gen/.clang-format17
-rw-r--r--tools/stats_log_api_gen/Collation.cpp678
-rw-r--r--tools/stats_log_api_gen/Collation.h81
-rw-r--r--tools/stats_log_api_gen/atoms_info_writer.cpp64
-rw-r--r--tools/stats_log_api_gen/atoms_info_writer.h6
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp291
-rw-r--r--tools/stats_log_api_gen/java_writer.h12
-rw-r--r--tools/stats_log_api_gen/java_writer_q.cpp572
-rw-r--r--tools/stats_log_api_gen/java_writer_q.h23
-rw-r--r--tools/stats_log_api_gen/main.cpp91
-rw-r--r--tools/stats_log_api_gen/native_writer.cpp103
-rw-r--r--tools/stats_log_api_gen/native_writer.h14
-rw-r--r--tools/stats_log_api_gen/test_collation.cpp118
-rw-r--r--tools/stats_log_api_gen/utils.cpp202
-rw-r--r--tools/stats_log_api_gen/utils.h22
-rw-r--r--wifi/Android.bp9
-rw-r--r--wifi/java/android/net/wifi/SoftApConfiguration.java5
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java9
194 files changed, 4830 insertions, 2897 deletions
diff --git a/Android.mk b/Android.mk
index aea0c951052f..3b307146770e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -39,11 +39,6 @@ INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE):apistubs/android/public/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE):apistubs/android/system/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE):apistubs/android/test/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_MODULE_LIB_API_FILE):apistubs/android/module-lib/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_SERVER_API_FILE):apistubs/android/system-server/api/android.txt)
# sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
# So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 12f211df4549..ccd873352a33 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -115,6 +115,11 @@ droidstubs {
baseline_file: "api/lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android.txt",
+ },
jdiff_enabled: true,
}
@@ -156,6 +161,11 @@ droidstubs {
baseline_file: "api/system-lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android.txt",
+ },
jdiff_enabled: true,
}
@@ -179,6 +189,11 @@ droidstubs {
baseline_file: "api/test-lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
+ },
}
/////////////////////////////////////////////////////////////////////
@@ -214,6 +229,11 @@ droidstubs {
baseline_file: "api/module-lib-lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android.txt",
+ },
}
diff --git a/apex/Android.bp b/apex/Android.bp
index cd34f98690d5..e8f6e6bf2c46 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -84,6 +84,24 @@ stubs_defaults {
},
}
+java_defaults {
+ name: "framework-module-stubs-lib-defaults-publicapi",
+ installable: false,
+ sdk_version: "module_current",
+}
+
+java_defaults {
+ name: "framework-module-stubs-lib-defaults-systemapi",
+ installable: false,
+ sdk_version: "module_current",
+}
+
+java_defaults {
+ name: "framework-module-stubs-lib-defaults-module_libs_api",
+ installable: false,
+ sdk_version: "module_current",
+}
+
// The defaults for module_libs comes in two parts - defaults for API checks
// and defaults for stub generation. This is because we want the API txt
// files to *only* include the module_libs_api, but the stubs to include
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index e5a685f15df8..c8ca44b6ef74 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -116,7 +116,7 @@ class BlobMetadata {
return mUserId;
}
- void addCommitter(@NonNull Committer committer) {
+ void addOrReplaceCommitter(@NonNull Committer committer) {
synchronized (mMetadataLock) {
// We need to override the committer data, so first remove any existing
// committer before adding the new one.
@@ -139,6 +139,12 @@ class BlobMetadata {
}
}
+ void removeCommitter(@NonNull Committer committer) {
+ synchronized (mMetadataLock) {
+ mCommitters.remove(committer);
+ }
+ }
+
void removeInvalidCommitters(SparseArray<String> packages) {
synchronized (mMetadataLock) {
mCommitters.removeIf(committer ->
@@ -154,7 +160,7 @@ class BlobMetadata {
}
}
- void addLeasee(String callingPackage, int callingUid, int descriptionResId,
+ void addOrReplaceLeasee(String callingPackage, int callingUid, int descriptionResId,
CharSequence description, long leaseExpiryTimeMillis) {
synchronized (mMetadataLock) {
// We need to override the leasee data, so first remove any existing
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 65ccb997343b..6c48511a12cc 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -401,7 +401,7 @@ public class BlobStoreManagerService extends SystemService {
throw new LimitExceededException("Total amount of data with an active lease"
+ " is exceeding the max limit");
}
- blobMetadata.addLeasee(callingPackage, callingUid,
+ blobMetadata.addOrReplaceLeasee(callingPackage, callingUid,
descriptionResId, description, leaseExpiryTimeMillis);
if (LOGV) {
Slog.v(TAG, "Acquired lease on " + blobHandle
@@ -573,12 +573,16 @@ public class BlobStoreManagerService extends SystemService {
final Committer newCommitter = new Committer(session.getOwnerPackageName(),
session.getOwnerUid(), session.getBlobAccessMode());
final Committer existingCommitter = blob.getExistingCommitter(newCommitter);
- blob.addCommitter(newCommitter);
+ blob.addOrReplaceCommitter(newCommitter);
try {
writeBlobsInfoLocked();
session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS);
} catch (Exception e) {
- blob.addCommitter(existingCommitter);
+ if (existingCommitter == null) {
+ blob.removeCommitter(newCommitter);
+ } else {
+ blob.addOrReplaceCommitter(existingCommitter);
+ }
session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
index 8fbfb1daaf6f..d99830dc47c9 100644
--- a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
@@ -7,6 +7,7 @@
],
"options": [
{"include-filter": "com.android.server.DeviceIdleControllerTest"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
index bc7a7d3bef7d..b76c582cf287 100644
--- a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
@@ -4,6 +4,7 @@
"name": "FrameworksMockingServicesTests",
"options": [
{"include-filter": "com.android.server.DeviceIdleControllerTest"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index e2e118074aac..484fec31e594 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -3,6 +3,7 @@
{
"name": "CtsJobSchedulerTestCases",
"options": [
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.LargeTest"}
]
@@ -11,6 +12,7 @@
"name": "FrameworksMockingServicesTests",
"options": [
{"include-filter": "com.android.server.job"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
},
@@ -18,6 +20,7 @@
"name": "FrameworksServicesTests",
"options": [
{"include-filter": "com.android.server.job"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index ba7572a5fb44..c5dc51cc9c24 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -4,6 +4,7 @@
"name": "CtsUsageStatsTestCases",
"options": [
{"include-filter": "android.app.usage.cts.UsageStatsTest"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
},
@@ -11,6 +12,7 @@
"name": "FrameworksServicesTests",
"options": [
{"include-filter": "com.android.server.usage"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 821dd9e46c19..99e82e7a3367 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -132,19 +132,19 @@ droidstubs {
java_library {
name: "framework-media-stubs-publicapi",
srcs: [":framework-media-stubs-srcs-publicapi"],
- sdk_version: "current",
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
}
java_library {
name: "framework-media-stubs-systemapi",
srcs: [":framework-media-stubs-srcs-systemapi"],
- sdk_version: "system_current",
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
java_library {
name: "framework-media-stubs-module_libs_api",
srcs: [":framework-media-stubs-srcs-module_libs_api"],
- sdk_version: "system_current",
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
}
java_library {
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 6d962008460f..3fefeb51aa11 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -84,20 +84,17 @@ droidstubs {
java_library {
name: "framework-permission-stubs-publicapi",
srcs: [ ":framework-permission-stubs-srcs-publicapi" ],
- sdk_version: "system_current",
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
}
java_library {
name: "framework-permission-stubs-systemapi",
srcs: [ ":framework-permission-stubs-srcs-systemapi" ],
- sdk_version: "system_current",
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
java_library {
name: "framework-permission-stubs-module_libs_api",
srcs: [ ":framework-permission-stubs-srcs-module_libs_api" ],
- sdk_version: "system_current",
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
}
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 86f4ab7c1128..707113b9672c 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -86,7 +86,7 @@ droidstubs {
java_library {
name: "framework-sdkextensions-stubs-publicapi",
srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
- sdk_version: "current",
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/sdkextensions", // sdkextensions SDK
@@ -96,7 +96,7 @@ java_library {
java_library {
name: "framework-sdkextensions-stubs-systemapi",
srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
- sdk_version: "system_current",
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/sdkextensions", // sdkextensions SDK
@@ -106,7 +106,7 @@ java_library {
java_library {
name: "framework-sdkextensions-stubs-module_libs_api",
srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
- sdk_version: "system_current",
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/sdkextensions", // sdkextensions SDK
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 8185bb036b22..804eb030e795 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -46,19 +46,11 @@ filegroup {
"//frameworks/base/apex/statsd:__subpackages__",
],
}
-
-java_defaults {
- name: "framework-statsd-defaults",
- sdk_version: "module_current",
- libs: [ "framework-annotations-lib" ],
-}
-
java_library {
name: "framework-statsd",
- defaults: [
- "framework-statsd-defaults",
- ],
installable: true,
+ sdk_version: "module_current",
+ libs: [ "framework-annotations-lib" ],
srcs: [
":framework-statsd-sources",
@@ -129,39 +121,33 @@ droidstubs {
java_library {
name: "framework-statsd-stubs-publicapi",
- defaults: [
- "framework-statsd-defaults",
- ],
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
srcs: [ ":framework-statsd-stubs-srcs-publicapi" ],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
- ]
+ ],
}
java_library {
name: "framework-statsd-stubs-systemapi",
- defaults: [
- "framework-statsd-defaults",
- ],
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
- ]
+ ],
}
java_library {
name: "framework-statsd-stubs-module_libs_api",
- defaults: [
- "framework-statsd-defaults",
- ],
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
srcs: [ ":framework-statsd-stubs-srcs-module_libs_api" ],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
"//frameworks/opt/net/wifi/service" // wifi service
- ]
+ ],
}
android_test {
diff --git a/api/current.txt b/api/current.txt
index c7e2e6f9c399..ff74ce8b43dc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -278,7 +278,7 @@ package android {
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
- field public static final int actor = 16844313; // 0x1010619
+ field public static final int actor = 16844312; // 0x1010618
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -289,7 +289,6 @@ package android {
field public static final int alignmentMode = 16843642; // 0x101037a
field public static final int allContactsName = 16843468; // 0x10102cc
field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
- field public static final int allowAutoRevokePermissionsExemption = 16844309; // 0x1010615
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowEmbedded = 16843765; // 0x10103f5
@@ -329,6 +328,7 @@ package android {
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
+ field public static final int autoRevokePermissions = 16844308; // 0x1010614
field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
@@ -710,7 +710,7 @@ package android {
field public static final int gravity = 16842927; // 0x10100af
field public static final int gridViewStyle = 16842865; // 0x1010071
field public static final int groupIndicator = 16843019; // 0x101010b
- field public static final int gwpAsanMode = 16844312; // 0x1010618
+ field public static final int gwpAsanMode = 16844311; // 0x1010617
field public static final int hand_hour = 16843011; // 0x1010103
field public static final int hand_minute = 16843012; // 0x1010104
field public static final int handle = 16843354; // 0x101025a
@@ -955,7 +955,7 @@ package android {
field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
- field public static final int mimeGroup = 16844311; // 0x1010617
+ field public static final int mimeGroup = 16844310; // 0x1010616
field public static final int mimeType = 16842790; // 0x1010026
field public static final int min = 16844089; // 0x1010539
field public static final int minAspectRatio = 16844187; // 0x101059b
@@ -1084,7 +1084,7 @@ package android {
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
- field public static final int preserveLegacyExternalStorage = 16844310; // 0x1010616
+ field public static final int preserveLegacyExternalStorage = 16844309; // 0x1010615
field public static final int previewImage = 16843482; // 0x10102da
field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c
@@ -1141,7 +1141,6 @@ package android {
field public static final int reqKeyboardType = 16843304; // 0x1010228
field public static final int reqNavigation = 16843306; // 0x101022a
field public static final int reqTouchScreen = 16843303; // 0x1010227
- field public static final int requestAutoRevokePermissionsExemption = 16844308; // 0x1010614
field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
@@ -45924,13 +45923,9 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
- method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 59544a971e5f..ca1d598ee7d7 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -32,8 +32,11 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Pair;
import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
/**
* This class is a command line utility for manipulating content. A client
@@ -72,7 +75,7 @@ public class Content {
"usage: adb shell content [subcommand] [options]\n"
+ "\n"
+ "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
- + " --bind <BINDING> [--bind <BINDING>...]\n"
+ + " --bind <BINDING> [--bind <BINDING>...] [--extra <BINDING>...]\n"
+ " <URI> a content provider URI.\n"
+ " <BINDING> binds a typed value to a column and is formatted:\n"
+ " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
@@ -84,7 +87,8 @@ public class Content {
+ " adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
+ " --bind value:s:new_value\n"
+ "\n"
- + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
+ + "usage: adb shell content update --uri <URI> [--user <USER_ID>]"
+ + " [--where <WHERE>] [--extra <BINDING>...]\n"
+ " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
+ " - see example below).\n"
+ " Example:\n"
@@ -93,14 +97,15 @@ public class Content {
+ " value:s:newer_value --where \"name=\'new_setting\'\"\n"
+ "\n"
+ "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
- + " [--bind <BINDING>...] [--where <WHERE>]\n"
+ + " [--bind <BINDING>...] [--where <WHERE>] [--extra <BINDING>...]\n"
+ " Example:\n"
+ " # Remove \"new_setting\" secure setting.\n"
+ " adb shell content delete --uri content://settings/secure "
+ "--where \"name=\'new_setting\'\"\n"
+ "\n"
+ "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
- + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+ + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]"
+ + " [--extra <BINDING>...]\n"
+ " <PROJECTION> is a list of colon separated column names and is formatted:\n"
+ " <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+ " <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
@@ -196,6 +201,7 @@ public class Content {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
ContentValues values = new ContentValues();
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg()) != null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
@@ -203,6 +209,8 @@ public class Content {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_BIND.equals(argument)) {
parseBindValue(values);
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -215,20 +223,23 @@ public class Content {
throw new IllegalArgumentException("Bindings not specified."
+ " Did you specify --bind argument(s)?");
}
- return new InsertCommand(uri, userId, values);
+ return new InsertCommand(uri, userId, values, extras);
}
private DeleteCommand parseDeleteCommand() {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
- String where = null;
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
} else if (ARGUMENT_USER.equals(argument)) {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
- where = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+ argumentValueRequired(argument));
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -237,23 +248,26 @@ public class Content {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
- return new DeleteCommand(uri, userId, where);
+ return new DeleteCommand(uri, userId, extras);
}
private UpdateCommand parseUpdateCommand() {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
- String where = null;
ContentValues values = new ContentValues();
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
} else if (ARGUMENT_USER.equals(argument)) {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
- where = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+ argumentValueRequired(argument));
} else if (ARGUMENT_BIND.equals(argument)) {
parseBindValue(values);
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -266,7 +280,7 @@ public class Content {
throw new IllegalArgumentException("Bindings not specified."
+ " Did you specify --bind argument(s)?");
}
- return new UpdateCommand(uri, userId, values, where);
+ return new UpdateCommand(uri, userId, values, extras);
}
public CallCommand parseCallCommand() {
@@ -274,7 +288,7 @@ public class Content {
int userId = UserHandle.USER_SYSTEM;
String arg = null;
Uri uri = null;
- ContentValues values = new ContentValues();
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
@@ -285,11 +299,10 @@ public class Content {
} else if (ARGUMENT_ARG.equals(argument)) {
arg = argumentValueRequired(argument);
} else if (ARGUMENT_EXTRA.equals(argument)) {
- parseBindValue(values);
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
-
}
if (uri == null) {
throw new IllegalArgumentException("Content provider URI not specified."
@@ -298,7 +311,7 @@ public class Content {
if (method == null) {
throw new IllegalArgumentException("Content provider method not specified.");
}
- return new CallCommand(uri, userId, method, arg, values);
+ return new CallCommand(uri, userId, method, arg, extras);
}
private GetTypeCommand parseGetTypeCommand() {
@@ -363,19 +376,22 @@ public class Content {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
String[] projection = null;
- String sort = null;
- String where = null;
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
} else if (ARGUMENT_USER.equals(argument)) {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
- where = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+ argumentValueRequired(argument));
} else if (ARGUMENT_SORT.equals(argument)) {
- sort = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER,
+ argumentValueRequired(argument));
} else if (ARGUMENT_PROJECTION.equals(argument)) {
projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -384,40 +400,76 @@ public class Content {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
- return new QueryCommand(uri, userId, projection, where, sort);
+ return new QueryCommand(uri, userId, projection, extras);
+ }
+
+ private List<String> splitWithEscaping(String argument, char splitChar) {
+ final List<String> res = new ArrayList<>();
+ final StringBuilder cur = new StringBuilder();
+ for (int i = 0; i < argument.length(); i++) {
+ char c = argument.charAt(i);
+ if (c == '\\') {
+ if (++i == argument.length()) {
+ throw new IllegalArgumentException("Invalid escaping");
+ } else {
+ // Skip escaping char and insert next
+ c = argument.charAt(i);
+ cur.append(c);
+ }
+ } else if (c == splitChar) {
+ // Splitting char means next string
+ res.add(cur.toString());
+ cur.setLength(0);
+ } else {
+ // Copy non-escaping and non-splitting char
+ cur.append(c);
+ }
+ }
+ res.add(cur.toString());
+ return res;
}
- private void parseBindValue(ContentValues values) {
+ private Pair<String, Object> parseBindValue() {
String argument = mTokenizer.nextArg();
if (TextUtils.isEmpty(argument)) {
throw new IllegalArgumentException("Binding not well formed: " + argument);
}
- final int firstColonIndex = argument.indexOf(COLON);
- if (firstColonIndex < 0) {
+ final List<String> split = splitWithEscaping(argument, COLON.charAt(0));
+ if (split.size() != 3) {
throw new IllegalArgumentException("Binding not well formed: " + argument);
}
- final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1);
- if (secondColonIndex < 0) {
- throw new IllegalArgumentException("Binding not well formed: " + argument);
- }
- String column = argument.substring(0, firstColonIndex);
- String type = argument.substring(firstColonIndex + 1, secondColonIndex);
- String value = argument.substring(secondColonIndex + 1);
+ String column = split.get(0);
+ String type = split.get(1);
+ String value = split.get(2);
if (TYPE_STRING.equals(type)) {
- values.put(column, value);
+ return Pair.create(column, value);
} else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
- values.put(column, Boolean.parseBoolean(value));
- } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
- values.put(column, Long.parseLong(value));
- } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
- values.put(column, Double.parseDouble(value));
+ return Pair.create(column, Boolean.parseBoolean(value));
+ } else if (TYPE_INTEGER.equalsIgnoreCase(type)) {
+ return Pair.create(column, Integer.parseInt(value));
+ } else if (TYPE_LONG.equalsIgnoreCase(type)) {
+ return Pair.create(column, Long.parseLong(value));
+ } else if (TYPE_FLOAT.equalsIgnoreCase(type)) {
+ return Pair.create(column, Float.parseFloat(value));
+ } else if (TYPE_DOUBLE.equalsIgnoreCase(type)) {
+ return Pair.create(column, Double.parseDouble(value));
} else if (TYPE_NULL.equalsIgnoreCase(type)) {
- values.putNull(column);
+ return Pair.create(column, null);
} else {
throw new IllegalArgumentException("Unsupported type: " + type);
}
}
+ private void parseBindValue(ContentValues values) {
+ final Pair<String, Object> columnValue = parseBindValue();
+ values.putObject(columnValue.first, columnValue.second);
+ }
+
+ private void parseBindValue(Bundle extras) {
+ final Pair<String, Object> columnValue = parseBindValue();
+ extras.putObject(columnValue.first, columnValue.second);
+ }
+
private String argumentValueRequired(String argument) {
String value = mTokenizer.nextArg();
if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
@@ -500,60 +552,43 @@ public class Content {
private static class InsertCommand extends Command {
final ContentValues mContentValues;
+ final Bundle mExtras;
- public InsertCommand(Uri uri, int userId, ContentValues contentValues) {
+ public InsertCommand(Uri uri, int userId, ContentValues contentValues, Bundle extras) {
super(uri, userId);
mContentValues = contentValues;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.insert(resolveCallingPackage(), null, mUri, mContentValues, null);
+ provider.insert(resolveCallingPackage(), null, mUri, mContentValues, mExtras);
}
}
private static class DeleteCommand extends Command {
- final String mWhere;
+ final Bundle mExtras;
- public DeleteCommand(Uri uri, int userId, String where) {
+ public DeleteCommand(Uri uri, int userId, Bundle extras) {
super(uri, userId);
- mWhere = where;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.delete(resolveCallingPackage(), null, mUri,
- ContentResolver.createSqlQueryBundle(mWhere, null));
+ provider.delete(resolveCallingPackage(), null, mUri, mExtras);
}
}
private static class CallCommand extends Command {
final String mMethod, mArg;
- Bundle mExtras = null;
+ final Bundle mExtras;
- public CallCommand(Uri uri, int userId, String method, String arg, ContentValues values) {
+ public CallCommand(Uri uri, int userId, String method, String arg, Bundle extras) {
super(uri, userId);
mMethod = method;
mArg = arg;
- if (values != null) {
- mExtras = new Bundle();
- for (String key : values.keySet()) {
- final Object val = values.get(key);
- if (val instanceof String) {
- mExtras.putString(key, (String) val);
- } else if (val instanceof Float) {
- mExtras.putFloat(key, (Float) val);
- } else if (val instanceof Double) {
- mExtras.putDouble(key, (Double) val);
- } else if (val instanceof Boolean) {
- mExtras.putBoolean(key, (Boolean) val);
- } else if (val instanceof Integer) {
- mExtras.putInt(key, (Integer) val);
- } else if (val instanceof Long) {
- mExtras.putLong(key, (Long) val);
- }
- }
- }
+ mExtras = extras;
}
@Override
@@ -604,21 +639,20 @@ public class Content {
}
}
- private static class QueryCommand extends DeleteCommand {
+ private static class QueryCommand extends Command {
final String[] mProjection;
- final String mSortOrder;
+ final Bundle mExtras;
- public QueryCommand(
- Uri uri, int userId, String[] projection, String where, String sortOrder) {
- super(uri, userId, where);
+ public QueryCommand(Uri uri, int userId, String[] projection, Bundle extras) {
+ super(uri, userId);
mProjection = projection;
- mSortOrder = sortOrder;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
- ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null);
+ mExtras, null);
if (cursor == null) {
System.out.println("No result found.");
return;
@@ -670,18 +704,19 @@ public class Content {
}
}
- private static class UpdateCommand extends InsertCommand {
- final String mWhere;
+ private static class UpdateCommand extends Command {
+ final ContentValues mValues;
+ final Bundle mExtras;
- public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
- super(uri, userId, contentValues);
- mWhere = where;
+ public UpdateCommand(Uri uri, int userId, ContentValues values, Bundle extras) {
+ super(uri, userId);
+ mValues = values;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.update(resolveCallingPackage(), null, mUri, mContentValues,
- ContentResolver.createSqlQueryBundle(mWhere, null));
+ provider.update(resolveCallingPackage(), null, mUri, mValues, mExtras);
}
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 4529dff0dc5c..45f21ae8e3e1 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -97,6 +97,7 @@ cc_defaults {
"src/stats_log_util.cpp",
"src/statscompanion_util.cpp",
"src/statsd_config.proto",
+ "src/statsd_metadata.proto",
"src/StatsLogProcessor.cpp",
"src/StatsService.cpp",
"src/storage/StorageManager.cpp",
@@ -378,55 +379,55 @@ cc_test {
// statsd micro benchmark
//#############################
-//cc_benchmark {
-// name: "statsd_benchmark",
-// defaults: ["statsd_defaults"],
-//
-// srcs: [
-// // atom_field_options.proto needs field_options.proto, but that is
-// // not included in libprotobuf-cpp-lite, so compile it here.
-// ":libprotobuf-internal-protos",
-//
-// "benchmark/duration_metric_benchmark.cpp",
-// "benchmark/filter_value_benchmark.cpp",
-// "benchmark/get_dimensions_for_condition_benchmark.cpp",
-// "benchmark/hello_world_benchmark.cpp",
-// "benchmark/log_event_benchmark.cpp",
-// "benchmark/main.cpp",
-// "benchmark/metric_util.cpp",
-// "benchmark/stats_write_benchmark.cpp",
-// "src/atom_field_options.proto",
-// "src/atoms.proto",
-// "src/stats_log.proto",
-// ],
-//
-// proto: {
-// type: "lite",
-// include_dirs: ["external/protobuf/src"],
-// },
-//
-// cflags: [
-// "-Wall",
-// "-Werror",
-// "-Wno-unused-parameter",
-// "-Wno-unused-variable",
-// "-Wno-unused-function",
-//
-// // Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
-// "-Wno-varargs",
-// ],
-//
-// static_libs: [
-// "libplatformprotos",
-// ],
-//
-// shared_libs: [
-// "libgtest_prod",
-// "libprotobuf-cpp-lite",
-// "libstatslog",
-// "libstatssocket",
-// ],
-//}
+cc_benchmark {
+ name: "statsd_benchmark",
+ defaults: ["statsd_defaults"],
+
+ srcs: [
+ // atom_field_options.proto needs field_options.proto, but that is
+ // not included in libprotobuf-cpp-lite, so compile it here.
+ ":libprotobuf-internal-protos",
+
+ "benchmark/duration_metric_benchmark.cpp",
+ "benchmark/filter_value_benchmark.cpp",
+ "benchmark/get_dimensions_for_condition_benchmark.cpp",
+ "benchmark/hello_world_benchmark.cpp",
+ "benchmark/log_event_benchmark.cpp",
+ "benchmark/main.cpp",
+ "benchmark/metric_util.cpp",
+ "benchmark/stats_write_benchmark.cpp",
+ "src/atom_field_options.proto",
+ "src/atoms.proto",
+ "src/stats_log.proto",
+ ],
+
+ proto: {
+ type: "lite",
+ include_dirs: ["external/protobuf/src"],
+ },
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-unused-variable",
+ "-Wno-unused-function",
+
+ // Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
+ "-Wno-varargs",
+ ],
+
+ static_libs: [
+ "libplatformprotos",
+ "libstatssocket_private",
+ ],
+
+ shared_libs: [
+ "libgtest_prod",
+ "libprotobuf-cpp-lite",
+ "libstatslog",
+ ],
+}
// ==== java proto device library (for test only) ==============================
java_library {
diff --git a/cmds/statsd/benchmark/duration_metric_benchmark.cpp b/cmds/statsd/benchmark/duration_metric_benchmark.cpp
index 2631009c71f2..2d315d9395bc 100644
--- a/cmds/statsd/benchmark/duration_metric_benchmark.cpp
+++ b/cmds/statsd/benchmark/duration_metric_benchmark.cpp
@@ -137,77 +137,74 @@ static void BM_DurationMetricNoLink(benchmark::State& state) {
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
std::vector<std::unique_ptr<LogEvent>> events;
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 11));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 40));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 102));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 450));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 650));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 100));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + bucketSizeNs + 640));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 650));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 10));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 200));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 401));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
-
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 11,
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 40, android::view::DISPLAY_STATE_ON));
+
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 102,
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
+ android::view::DISPLAY_STATE_ON));
+
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 650,
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
+ android::view::DISPLAY_STATE_ON));
+
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 640,
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 650,
+ android::view::DISPLAY_STATE_ON));
+
+ vector<int> attributionUids1 = {9999};
+ vector<string> attributionTags1 = {""};
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "job0"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
+ attributionTags1, "job0"));
+
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids1,
+ attributionTags1, "job2"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids1,
+ attributionTags1, "job2"));
+
+ vector<int> attributionUids2 = {8888};
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
+ attributionTags1, "job2"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
+ attributionUids2, attributionTags1, "job2"));
+
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 600,
+ attributionUids2, attributionTags1, "job1"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
+ attributionUids2, attributionTags1, "job1"));
+
+ vector<int> attributionUids3 = {111, 222, 222};
+ vector<string> attributionTags3 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 10, attributionUids3,
+ attributionTags3, "ReadEmail"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 50, attributionUids3, attributionTags3,
+ "ReadEmail"));
+
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200, attributionUids3,
+ attributionTags3, "ReadEmail"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids3,
+ attributionTags3, "ReadEmail"));
+
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids3,
+ attributionTags3, "ReadDoc"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids3,
+ attributionTags3, "ReadDoc"));
+
+ vector<int> attributionUids4 = {333, 222, 555};
+ vector<string> attributionTags4 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 401, attributionUids4,
+ attributionTags4, "ReadEmail"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids4,
+ attributionTags4, "ReadEmail"));
sortLogEventsByTimestamp(&events);
while (state.KeepRunning()) {
@@ -230,78 +227,75 @@ static void BM_DurationMetricLink(benchmark::State& state) {
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions3 = {
- CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
std::vector<std::unique_ptr<LogEvent>> events;
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 55));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 120));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 121));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 450));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 501));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 100));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",
- bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(
- CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs - 2));
- events.push_back(
- CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 110));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 300));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
- events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 550));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 800));
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs + 700));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 55,
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 120,
+ android::view::DISPLAY_STATE_ON));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 121,
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
+ android::view::DISPLAY_STATE_ON));
+
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 501,
+ android::view::DISPLAY_STATE_OFF));
+ events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
+ android::view::DISPLAY_STATE_ON));
+
+ vector<int> attributionUids1 = {111};
+ vector<string> attributionTags1 = {"App1"};
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 1, attributionUids1,
+ attributionTags1, "job1"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
+ attributionTags1, "job1"));
+
+ vector<int> attributionUids2 = {333};
+ vector<string> attributionTags2 = {"App2"};
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids2,
+ attributionTags2, "job2"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids2,
+ attributionTags2, "job2"));
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
+ attributionTags2, "job2"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
+ attributionUids2, attributionTags2, "job2"));
+
+ vector<int> attributionUids3 = {444};
+ vector<string> attributionTags3 = {"App3"};
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs - 2,
+ attributionUids3, attributionTags3, "job3"));
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
+ attributionUids3, attributionTags3, "job3"));
+
+ vector<int> attributionUids4 = {111, 222, 222};
+ vector<string> attributionTags4 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids4,
+ attributionTags4, "ReadEmail"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 110, attributionUids4, attributionTags4,
+ "ReadEmail"));
+
+ vector<int> attributionUids5 = {333, 222, 555};
+ vector<string> attributionTags5 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 300, attributionUids5,
+ attributionTags5, "ReadEmail"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids5,
+ attributionTags5, "ReadEmail"));
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids5,
+ attributionTags5, "ReadDoc"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids5,
+ attributionTags5, "ReadDoc"));
+
+ vector<int> attributionUids6 = {444, 222, 555};
+ vector<string> attributionTags6 = {"App3", "GMSCoreModule1", "GMSCoreModule2"};
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 550, attributionUids6,
+ attributionTags6, "ReadDoc"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 800, attributionUids6, attributionTags6,
+ "ReadDoc"));
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids6,
+ attributionTags6, "ReadDoc"));
+ events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids6,
+ attributionTags6, "ReadDoc"));
sortLogEventsByTimestamp(&events);
while (state.KeepRunning()) {
diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp
index cfe477d7ca8f..28bf21ae52bf 100644
--- a/cmds/statsd/benchmark/filter_value_benchmark.cpp
+++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp
@@ -19,6 +19,7 @@
#include "HashableDimensionKey.h"
#include "logd/LogEvent.h"
#include "stats_log_util.h"
+#include "stats_event.h"
namespace android {
namespace os {
@@ -26,17 +27,31 @@ namespace statsd {
using std::vector;
-static void createLogEventAndMatcher(LogEvent* event, FieldMatcher *field_matcher) {
- AttributionNodeInternal node;
- node.set_uid(100);
- node.set_tag("LOCATION");
+static void createLogEventAndMatcher(LogEvent* event, FieldMatcher* field_matcher) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, 1);
+ AStatsEvent_overwriteTimestamp(statsEvent, 100000);
- std::vector<AttributionNodeInternal> nodes = {node, node};
- event->write(nodes);
- event->write(3.2f);
- event->write("LOCATION");
- event->write((int64_t)990);
- event->init();
+ std::vector<int> attributionUids = {100, 100};
+ std::vector<string> attributionTags = {"LOCATION", "LOCATION"};
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeFloat(statsEvent, 3.2f);
+ AStatsEvent_writeString(statsEvent, "LOCATION");
+ AStatsEvent_writeInt64(statsEvent, 990);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ event->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
field_matcher->set_field(1);
auto child = field_matcher->add_child();
@@ -46,7 +61,7 @@ static void createLogEventAndMatcher(LogEvent* event, FieldMatcher *field_matche
}
static void BM_FilterValue(benchmark::State& state) {
- LogEvent event(1, 100000);
+ LogEvent event(/*uid=*/0, /*pid=*/0);
FieldMatcher field_matcher;
createLogEventAndMatcher(&event, &field_matcher);
diff --git a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
index 2a4403ed8282..c7d01cc406fc 100644
--- a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
+++ b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
@@ -19,6 +19,7 @@
#include "HashableDimensionKey.h"
#include "logd/LogEvent.h"
#include "stats_log_util.h"
+#include "stats_event.h"
namespace android {
namespace os {
@@ -27,16 +28,30 @@ namespace statsd {
using std::vector;
static void createLogEventAndLink(LogEvent* event, Metric2Condition *link) {
- AttributionNodeInternal node;
- node.set_uid(100);
- node.set_tag("LOCATION");
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, 1);
+ AStatsEvent_overwriteTimestamp(statsEvent, 100000);
- std::vector<AttributionNodeInternal> nodes = {node, node};
- event->write(nodes);
- event->write(3.2f);
- event->write("LOCATION");
- event->write((int64_t)990);
- event->init();
+ std::vector<int> attributionUids = {100, 100};
+ std::vector<string> attributionTags = {"LOCATION", "LOCATION"};
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeFloat(statsEvent, 3.2f);
+ AStatsEvent_writeString(statsEvent, "LOCATION");
+ AStatsEvent_writeInt64(statsEvent, 990);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ event->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
link->conditionId = 1;
@@ -54,7 +69,7 @@ static void createLogEventAndLink(LogEvent* event, Metric2Condition *link) {
static void BM_GetDimensionInCondition(benchmark::State& state) {
Metric2Condition link;
- LogEvent event(1, 100000);
+ LogEvent event(/*uid=*/0, /*pid=*/0);
createLogEventAndLink(&event, &link);
while (state.KeepRunning()) {
diff --git a/cmds/statsd/benchmark/log_event_benchmark.cpp b/cmds/statsd/benchmark/log_event_benchmark.cpp
index 8b687438ca27..057e00bde202 100644
--- a/cmds/statsd/benchmark/log_event_benchmark.cpp
+++ b/cmds/statsd/benchmark/log_event_benchmark.cpp
@@ -39,7 +39,8 @@ static void BM_LogEventCreation(benchmark::State& state) {
uint8_t msg[LOGGER_ENTRY_MAX_PAYLOAD];
size_t size = createAndParseStatsEvent(msg);
while (state.KeepRunning()) {
- benchmark::DoNotOptimize(LogEvent(msg, size, /*uid=*/ 1000, /*pid=*/ 1001));
+ LogEvent event(/*uid=*/ 1000, /*pid=*/ 1001);
+ benchmark::DoNotOptimize(event.parseBuffer(msg, size));
}
}
BENCHMARK(BM_LogEventCreation);
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index cca6d525ea16..4bce89fd7f9c 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -14,6 +14,8 @@
#include "metric_util.h"
+#include "stats_event.h"
+
namespace android {
namespace os {
namespace statsd {
@@ -246,117 +248,112 @@ FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields)
}
std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
- const android::view::DisplayStateEnum state, uint64_t timestampNs) {
- auto event = std::make_unique<LogEvent>(android::util::SCREEN_STATE_CHANGED, timestampNs);
- event->write(state);
- event->init();
- return event;
-}
+ uint64_t timestampNs, const android::view::DisplayStateEnum state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
- int level, uint64_t timestampNs) {
- auto event = std::make_unique<LogEvent>(android::util::SCREEN_BRIGHTNESS_CHANGED, timestampNs);
- (event->write(level));
- event->init();
- return event;
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
}
std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& jobName,
- const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
- auto event = std::make_unique<LogEvent>(android::util::SCHEDULED_JOB_STATE_CHANGED, timestampNs);
- event->write(attributions);
- event->write(jobName);
- event->write(state);
- event->init();
- return event;
+ const vector<int>& attributionUids, const vector<string>& attributionTags,
+ const string& jobName, const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::SCHEDULED_JOB_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeString(statsEvent, jobName.c_str());
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
}
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
- const std::vector<AttributionNodeInternal>& attributions,
- const string& name, uint64_t timestampNs) {
- return CreateScheduledJobStateChangedEvent(
- attributions, name, ScheduledJobStateChanged::STARTED, timestampNs);
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName) {
+ return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
+ ScheduledJobStateChanged::STARTED, timestampNs);
}
// Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
- const std::vector<AttributionNodeInternal>& attributions,
- const string& name, uint64_t timestampNs) {
- return CreateScheduledJobStateChangedEvent(
- attributions, name, ScheduledJobStateChanged::FINISHED, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- const WakelockStateChanged::State state, uint64_t timestampNs) {
- auto event = std::make_unique<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, timestampNs);
- event->write(attributions);
- event->write(android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
- event->write(wakelockName);
- event->write(state);
- event->init();
- return event;
-}
-
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs) {
- return CreateWakelockStateChangedEvent(
- attributions, wakelockName, WakelockStateChanged::ACQUIRE, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs) {
- return CreateWakelockStateChangedEvent(
- attributions, wakelockName, WakelockStateChanged::RELEASE, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
- const int uid, const ActivityForegroundStateChanged::State state, uint64_t timestampNs) {
- auto event = std::make_unique<LogEvent>(
- android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, timestampNs);
- event->write(uid);
- event->write("pkg_name");
- event->write("class_name");
- event->write(state);
- event->init();
- return event;
-}
-
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs) {
- return CreateActivityForegroundStateChangedEvent(
- uid, ActivityForegroundStateChanged::BACKGROUND, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs) {
- return CreateActivityForegroundStateChangedEvent(
- uid, ActivityForegroundStateChanged::FOREGROUND, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- const SyncStateChanged::State state, uint64_t timestampNs) {
- auto event = std::make_unique<LogEvent>(android::util::SYNC_STATE_CHANGED, timestampNs);
- event->write(attributions);
- event->write(name);
- event->write(state);
- event->init();
- return event;
-}
-
-std::unique_ptr<LogEvent> CreateSyncStartEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- uint64_t timestampNs) {
- return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::ON, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateSyncEndEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- uint64_t timestampNs) {
- return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::OFF, timestampNs);
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName) {
+ return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
+ ScheduledJobStateChanged::FINISHED, timestampNs);
+}
+
+std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name,
+ const SyncStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, util::SYNC_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeString(statsEvent, name.c_str());
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name) {
+ return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
+ SyncStateChanged::ON);
+}
+
+std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name) {
+ return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
+ SyncStateChanged::OFF);
}
sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
diff --git a/cmds/statsd/benchmark/metric_util.h b/cmds/statsd/benchmark/metric_util.h
index 9b28d60b38c0..6199fa9dc7a1 100644
--- a/cmds/statsd/benchmark/metric_util.h
+++ b/cmds/statsd/benchmark/metric_util.h
@@ -94,55 +94,31 @@ FieldMatcher CreateAttributionUidDimensions(const int atomId,
// Create log event for screen state changed.
std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
- const android::view::DisplayStateEnum state, uint64_t timestampNs);
-
-// Create log event for screen brightness state changed.
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
- int level, uint64_t timestampNs);
+ uint64_t timestampNs, const android::view::DisplayStateEnum state);
// Create log event when scheduled job starts.
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
- const std::vector<AttributionNodeInternal>& attributions,
- const string& name, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName);
// Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
- const std::vector<AttributionNodeInternal>& attributions,
- const string& name, uint64_t timestampNs);
-
-// Create log event for app moving to background.
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs);
-
-// Create log event for app moving to foreground.
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& jobName);
// Create log event when the app sync starts.
-std::unique_ptr<LogEvent> CreateSyncStartEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- uint64_t timestampNs);
-
-// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateSyncEndEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name);
// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateAppCrashEvent(
- const int uid, uint64_t timestampNs);
-
-// Create log event for acquiring wakelock.
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs);
-
-// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs);
-
-// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
- int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name);
// Helper function to create an AttributionNodeInternal proto.
AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
@@ -158,4 +134,4 @@ int64_t StringToId(const string& str);
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 40a24dc52e52..afee79d7506b 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -117,4 +117,6 @@ extend google.protobuf.FieldOptions {
optional bool allow_from_any_uid = 50003 [default = false];
repeated string module = 50004;
+
+ optional bool truncate_timestamp = 50005 [default = false];
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b3d534a4bce1..a14c012b2da3 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -94,7 +94,8 @@ message Atom {
10 [(module) = "framework", (module) = "statsdtest"];
LongPartialWakelockStateChanged long_partial_wakelock_state_changed =
11 [(module) = "framework"];
- MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12 [(module) = "framework"];
+ MobileRadioPowerStateChanged mobile_radio_power_state_changed =
+ 12 [(module) = "framework", (truncate_timestamp) = true];
WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13 [(module) = "framework"];
ActivityManagerSleepStateChanged activity_manager_sleep_state_changed =
14 [(module) = "framework"];
@@ -107,7 +108,8 @@ message Atom {
20 [(module) = "framework", (module) = "statsdtest"];
DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"];
DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22 [(module) = "framework"];
- AudioStateChanged audio_state_changed = 23 [(module) = "framework"];
+ AudioStateChanged audio_state_changed =
+ 23 [(module) = "framework", (truncate_timestamp) = true];
MediaCodecStateChanged media_codec_state_changed = 24 [(module) = "framework"];
CameraStateChanged camera_state_changed = 25 [(module) = "framework"];
FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"];
@@ -128,7 +130,8 @@ message Atom {
WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"];
WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"];
WifiScanStateChanged wifi_scan_state_changed = 39 [(module) = "wifi"];
- PhoneSignalStrengthChanged phone_signal_strength_changed = 40 [(module) = "framework"];
+ PhoneSignalStrengthChanged phone_signal_strength_changed =
+ 40 [(module) = "framework", (truncate_timestamp) = true];
SettingChanged setting_changed = 41 [(module) = "framework"];
ActivityForegroundStateChanged activity_foreground_state_changed =
42 [(module) = "framework", (module) = "statsdtest"];
@@ -154,7 +157,8 @@ message Atom {
59 [(module) = "framework", (module) = "statsdtest"];
ForegroundServiceStateChanged foreground_service_state_changed
= 60 [(module) = "framework"];
- CallStateChanged call_state_changed = 61 [(module) = "telecom"];
+ CallStateChanged call_state_changed =
+ 61 [(module) = "telecom", (truncate_timestamp) = true];
KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"];
KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"];
KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"];
@@ -420,8 +424,10 @@ message Atom {
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
- MobileBytesTransfer mobile_bytes_transfer = 10002 [(module) = "framework"];
- MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003 [(module) = "framework"];
+ MobileBytesTransfer mobile_bytes_transfer =
+ 10002 [(module) = "framework", (truncate_timestamp) = true];
+ MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg =
+ 10003 [(module) = "framework", (truncate_timestamp) = true];
BluetoothBytesTransfer bluetooth_bytes_transfer = 10006 [(module) = "framework"];
KernelWakelock kernel_wakelock = 10004 [(module) = "framework"];
SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"];
@@ -504,6 +510,7 @@ message Atom {
VoiceCallRatUsage voice_call_rat_usage = 10077 [(module) = "telephony"];
SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
+ SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -8993,3 +9000,37 @@ message RankingSelected {
// Which of the ranked targets got picked, default starting position 0.
optional int32 position_picked = 4;
}
+
+/**
+ * Logs settings provider values.
+ *
+ * Use DeviceConfig.getProperties to get a list Setting key, query the data from content provider,
+ * then write the value to proto.
+ *
+ */
+message SettingSnapshot {
+
+ // Setting key
+ optional string name = 1;
+
+ enum SettingsValueType {
+ NOTASSIGNED = 0;
+ ASSIGNED_BOOL_TYPE = 1;
+ ASSIGNED_INT_TYPE = 2;
+ ASSIGNED_FLOAT_TYPE = 3;
+ ASSIGNED_STRING_TYPE = 4;
+ };
+ // Setting value type
+ optional SettingsValueType type = 2;
+
+ optional bool bool_value = 3;
+
+ optional int32 int_value = 4;
+
+ optional float float_value = 5;
+
+ optional string str_value = 6;
+
+ // Android user index. 0 for primary user, 10, 11 for secondary or profile user
+ optional int32 user_id = 7;
+}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6f54ea7d86c2..fca48f96f56d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -80,7 +80,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap,
- mMetricIndexesWithActivation, mNoReportMetricIds);
+ mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds);
mHashStringsInReport = config.hash_strings_in_metric_report();
mVersionStringsInReport = config.version_strings_in_metric_report();
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 6d20822fd54c..7500ec91ce30 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -230,6 +230,10 @@ private:
// Maps deactivation triggering event to MetricProducers.
std::unordered_map<int, std::vector<int>> mDeactivationAtomTrackerToMetricMap;
+ // Maps AlertIds to the index of the corresponding AnomalyTracker stored in mAllAnomalyTrackers.
+ // The map is used in LoadMetadata to more efficiently lookup AnomalyTrackers from an AlertId.
+ std::unordered_map<int64_t, int> mAlertTrackerMap;
+
std::vector<int> mMetricIndexesWithActivation;
void initLogSourceWhiteList();
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 40a313a14eab..e5fe87acc720 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -830,10 +830,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
bool initAlerts(const StatsdConfig& config,
const unordered_map<int64_t, int>& metricProducerMap,
+ unordered_map<int64_t, int>& alertTrackerMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
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_id());
@@ -858,7 +858,7 @@ bool initAlerts(const StatsdConfig& config,
// The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
return false;
}
- anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
+ alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
allAnomalyTrackers.push_back(anomalyTracker);
}
for (int i = 0; i < config.subscription_size(); ++i) {
@@ -872,8 +872,8 @@ bool initAlerts(const StatsdConfig& config,
(long long)subscription.id());
return false;
}
- const auto& itr = anomalyTrackerMap.find(subscription.rule_id());
- if (itr == anomalyTrackerMap.end()) {
+ const auto& itr = alertTrackerMap.find(subscription.rule_id());
+ if (itr == alertTrackerMap.end()) {
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
(long long)subscription.id(), (long long)subscription.rule_id());
return false;
@@ -944,6 +944,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
unordered_map<int, std::vector<int>>& trackerToConditionMap,
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+ unordered_map<int64_t, int>& alertTrackerMap,
vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds) {
unordered_map<int64_t, int> logTrackerMap;
@@ -976,8 +977,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
ALOGE("initMetricProducers failed");
return false;
}
- if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers,
- allAnomalyTrackers)) {
+ if (!initAlerts(config, metricProducerMap, alertTrackerMap, anomalyAlarmMonitor,
+ allMetricProducers, allAnomalyTrackers)) {
ALOGE("initAlerts failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 5ebb232694a4..a8ccc6289b9a 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -128,6 +128,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+ std::unordered_map<int64_t, int>& alertTrackerMap,
vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds);
diff --git a/cmds/statsd/src/statsd_metadata.proto b/cmds/statsd/src/statsd_metadata.proto
new file mode 100644
index 000000000000..e00fe33655ca
--- /dev/null
+++ b/cmds/statsd/src/statsd_metadata.proto
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.os.statsd.metadata;
+
+message ConfigKey {
+ optional int64 config_id = 1;
+ optional int32 uid = 2;
+}
+
+message Field {
+ optional int32 tag = 1;
+ optional int32 field = 2;
+}
+
+message FieldValue {
+ optional Field field = 1;
+ oneof value {
+ int32 value_int = 2;
+ int64 value_long = 3;
+ float value_float = 4;
+ double value_double = 5;
+ string value_str = 6;
+ bytes value_storage = 7;
+ }
+}
+
+message MetricDimensionKey {
+ repeated FieldValue dimension_key_in_what = 1;
+ repeated FieldValue state_values_key = 2;
+}
+
+message AlertMetadata {
+ optional int64 alert_id = 1;
+ // The earliest time the alert can be fired again in wall clock time.
+ optional int32 last_refractory_ends_sec = 2;
+ optional MetricDimensionKey dimension_key = 3;
+}
+
+// All metadata for a config in statsd
+message StatsMetadata {
+ optional ConfigKey config_key = 1;
+ repeated AlertMetadata alert_metadata = 2;
+}
+
+message StatsMetadataList {
+ repeated StatsMetadata stats_metadata = 1;
+} \ No newline at end of file
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 71adc5789d92..356e40b9b99d 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -40,6 +40,7 @@ using android::os::statsd::Predicate;
#ifdef __ANDROID__
const ConfigKey kConfigKey(0, 12345);
+const long kAlertId = 3;
const long timeBaseSec = 1000;
@@ -85,7 +86,7 @@ StatsdConfig buildGoodConfig() {
config.add_no_report_metric(3);
auto alert = config.add_alert();
- alert->set_id(3);
+ alert->set_id(kAlertId);
alert->set_metric_id(3);
alert->set_num_buckets(10);
alert->set_refractory_period_secs(100);
@@ -218,7 +219,7 @@ StatsdConfig buildDimensionMetricsWithMultiTags() {
metric->mutable_dimensions_in_what()->add_child()->set_field(1);
auto alert = config.add_alert();
- alert->set_id(103);
+ alert->set_id(kAlertId);
alert->set_metric_id(3);
alert->set_num_buckets(10);
alert->set_refractory_period_secs(100);
@@ -284,6 +285,7 @@ TEST(MetricsManagerTest, TestGoodConfig) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -293,10 +295,14 @@ TEST(MetricsManagerTest, TestGoodConfig) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
EXPECT_EQ(1u, allMetricProducers.size());
EXPECT_EQ(1u, allAnomalyTrackers.size());
EXPECT_EQ(1u, noReportMetricIds.size());
+ EXPECT_EQ(1u, alertTrackerMap.size());
+ EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end());
+ EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0);
}
TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
@@ -316,6 +322,7 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -325,7 +332,8 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -345,6 +353,7 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -354,7 +363,8 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -374,6 +384,7 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
@@ -382,7 +393,8 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -402,6 +414,7 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
@@ -410,7 +423,7 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation, noReportMetricIds));
}
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -430,6 +443,7 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -439,7 +453,8 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -459,6 +474,7 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -468,7 +484,8 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
#else
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index ae6769ee72ee..c1d4693ce01c 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1582,9 +1582,9 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- auto it = valueProducer->mCurrentSlicedBucket.begin();
- auto& interval1 = it->second[0];
- auto& baseInfo1 =
+ const auto& it = valueProducer->mCurrentSlicedBucket.begin();
+ ValueMetricProducer::Interval& interval1 = it->second[0];
+ ValueMetricProducer::BaseInfo& baseInfo1 =
valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo1.hasBase);
@@ -1611,16 +1611,9 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
break;
}
}
- // auto itBase = valueProducer->mCurrentBaseInfo.begin();
- // for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
- // if (itBase != iterBase) {
- // break;
- // }
- // }
EXPECT_TRUE(it2 != it);
- // EXPECT_TRUE(itBase != iterBase);
- auto& interval2 = it2->second[0];
- auto& baseInfo2 =
+ ValueMetricProducer::Interval& interval2 = it2->second[0];
+ ValueMetricProducer::BaseInfo& baseInfo2 =
valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
@@ -1647,23 +1640,28 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- it = valueProducer->mCurrentSlicedBucket.begin();
- it2 = std::next(valueProducer->mCurrentSlicedBucket.begin());
- interval1 = it->second[0];
- interval2 = it2->second[0];
- baseInfo1 = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
- baseInfo2 = valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
-
- EXPECT_EQ(true, baseInfo1.hasBase);
- EXPECT_EQ(5, baseInfo1.base.long_value);
- EXPECT_EQ(false, interval1.hasValue);
- EXPECT_EQ(5, interval1.value.long_value);
+ // Get new references now that entries have been deleted from the map
+ const auto& it3 = valueProducer->mCurrentSlicedBucket.begin();
+ const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin());
+ EXPECT_EQ(it3->second.size(), 1);
+ EXPECT_EQ(it4->second.size(), 1);
+ ValueMetricProducer::Interval& interval3 = it3->second[0];
+ ValueMetricProducer::Interval& interval4 = it4->second[0];
+ ValueMetricProducer::BaseInfo& baseInfo3 =
+ valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())->second[0];
+ ValueMetricProducer::BaseInfo& baseInfo4 =
+ valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())->second[0];
+
+ EXPECT_EQ(true, baseInfo3.hasBase);
+ EXPECT_EQ(5, baseInfo3.base.long_value);
+ EXPECT_EQ(false, interval3.hasValue);
+ EXPECT_EQ(5, interval3.value.long_value);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
- EXPECT_EQ(true, baseInfo2.hasBase);
- EXPECT_EQ(13, baseInfo2.base.long_value);
- EXPECT_EQ(false, interval2.hasValue);
- EXPECT_EQ(8, interval2.value.long_value);
+ EXPECT_EQ(true, baseInfo4.hasBase);
+ EXPECT_EQ(13, baseInfo4.base.long_value);
+ EXPECT_EQ(false, interval4.hasValue);
+ EXPECT_EQ(8, interval4.value.long_value);
EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 26db8f3ecb54..d4749bd8f330 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -8446,7 +8446,9 @@ public class AppOpsManager {
/**
* Pulls current AppOps access report and picks package and op to watch for next access report
- *
+ * Returns null if no reports were collected since last call. There is no guarantee of report
+ * collection, hence this method should be called periodically even if no report was collected
+ * to pick different package and op to watch.
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 61be01f9f6c0..0ecc003a33bd 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -499,9 +499,11 @@ public final class ApplicationExitInfo implements Parcelable {
/**
* Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
- * {@link #getPackageUid}, if an external service was bound with the flag
- * {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here
- * will be the kernel user identifier of the external service provider.
+ * {@link #getPackageUid}, if an external service has the
+ * {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set
+ * to <code>true<code> and was bound with the flag
+ * {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here will
+ * be the kernel user identifier of the external service provider.
*/
public int getDefiningUid() {
return mDefiningUid;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9ccfe8df14c2..17fd4efec9cc 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2414,8 +2414,7 @@ class ContextImpl extends Context {
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
final List<ResourcesLoader> loaders = mResources.getLoaders();
- // TODO(b/128338354): Rename to createTokenResources
- return mResourcesManager.createBaseActivityResources(mToken, resDir, splitResDirs,
+ return mResourcesManager.createBaseTokenResources(mToken, resDir, splitResDirs,
overlayDirs, libDirs, displayId, null /* overrideConfig */,
compatInfo, mClassLoader, loaders);
}
@@ -2684,7 +2683,7 @@ class ContextImpl extends Context {
// Create the base resources for which all configuration contexts for this Activity
// will be rebased upon.
- context.setResources(resourcesManager.createBaseActivityResources(activityToken,
+ context.setResources(resourcesManager.createBaseTokenResources(activityToken,
packageInfo.getResDir(),
splitDirs,
packageInfo.getOverlayDirs(),
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b8221b4efa2f..7fc10ed090c8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -99,6 +99,7 @@ interface IActivityManager {
void unregisterUidObserver(in IUidObserver observer);
boolean isUidActive(int uid, String callingPackage);
int getUidProcessState(int uid, in String callingPackage);
+ boolean isUidActiveOrForeground(int uid, String callingPackage);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index d650801f39ea..10f7835b3d69 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -801,6 +801,11 @@ public final class LoadedApk {
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
String libraryPermittedPath = mDataDir;
+ if (mActivityThread == null) {
+ // In a zygote context where mActivityThread is null we can't access the app data dir
+ // and including this in libraryPermittedPath would cause SELinux denials.
+ libraryPermittedPath = "";
+ }
if (isBundledApp) {
// For bundled apps, add the base directory of the app (e.g.,
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 5f756033390b..392c05ac5949 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -695,26 +695,26 @@ public class ResourcesManager {
}
/**
- * Creates base resources for an Activity. Calls to
+ * Creates base resources for a binder token. Calls to
* {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
- * CompatibilityInfo, ClassLoader, List)} with the same activityToken will have their override
+ * CompatibilityInfo, ClassLoader, List)} with the same binder token will have their override
* configurations merged with the one specified here.
*
- * @param activityToken Represents an Activity.
+ * @param token Represents an {@link Activity} or {@link WindowContext}.
* @param resDir The base resource path. Can be null (only framework resources will be loaded).
* @param splitResDirs An array of split resource paths. Can be null.
* @param overlayDirs An array of overlay paths. Can be null.
* @param libDirs An array of resource library paths. Can be null.
* @param displayId The ID of the display for which to create the resources.
* @param overrideConfig The configuration to apply on top of the base configuration. Can be
- * null. This provides the base override for this Activity.
+ * {@code null}. This provides the base override for this token.
* @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
* {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
* @param classLoader The class loader to use when inflating Resources. If null, the
* {@link ClassLoader#getSystemClassLoader()} is used.
* @return a Resources object from which to access resources.
*/
- public @Nullable Resources createBaseActivityResources(@NonNull IBinder activityToken,
+ public @Nullable Resources createBaseTokenResources(@NonNull IBinder token,
@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@@ -739,24 +739,24 @@ public class ResourcesManager {
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
if (DEBUG) {
- Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+ Slog.d(TAG, "createBaseActivityResources activity=" + token
+ " with key=" + key);
}
synchronized (this) {
// Force the creation of an ActivityResourcesStruct.
- getOrCreateActivityResourcesStructLocked(activityToken);
+ getOrCreateActivityResourcesStructLocked(token);
}
// Update any existing Activity Resources references.
- updateResourcesForActivity(activityToken, overrideConfig, displayId,
+ updateResourcesForActivity(token, overrideConfig, displayId,
false /* movedToDifferentDisplay */);
- cleanupReferences(activityToken);
- rebaseKeyForActivity(activityToken, key);
+ cleanupReferences(token);
+ rebaseKeyForActivity(token, key);
synchronized (this) {
- Resources resources = findResourcesForActivityLocked(activityToken, key,
+ Resources resources = findResourcesForActivityLocked(token, key,
classLoader);
if (resources != null) {
return resources;
@@ -764,7 +764,7 @@ public class ResourcesManager {
}
// Now request an actual Resources object.
- return createResources(activityToken, key, classLoader);
+ return createResources(token, key, classLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index e0674d75974a..fa62a02499e0 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -379,6 +379,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+ verifyDeviceNotNull(device, "setConnectionPolicy");
final IBluetoothHearingAid service = getService();
try {
if (service != null && isEnabled()
@@ -428,6 +429,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
+ verifyDeviceNotNull(device, "getConnectionPolicy");
final IBluetoothHearingAid service = getService();
try {
if (service != null && isEnabled()
@@ -504,6 +506,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
if (VDBG) {
log("getHiSyncId(" + device + ")");
}
+ verifyDeviceNotNull(device, "getConnectionPolicy");
final IBluetoothHearingAid service = getService();
try {
if (service == null) {
@@ -577,6 +580,13 @@ public final class BluetoothHearingAid implements BluetoothProfile {
return false;
}
+ private void verifyDeviceNotNull(BluetoothDevice device, String methodName) {
+ if (device == null) {
+ Log.e(TAG, methodName + ": device param is null");
+ throw new IllegalArgumentException("Device cannot be null");
+ }
+ }
+
private boolean isValidDevice(BluetoothDevice device) {
if (device == null) return false;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 65eb642369c9..31c3232f4714 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -47,6 +47,7 @@ import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.ICancellationSignal;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteCallback;
@@ -303,7 +304,23 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
@Override
public void getTypeAsync(Uri uri, RemoteCallback callback) {
final Bundle result = new Bundle();
- result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
+ try {
+ result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
+ } catch (Exception e) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ try {
+ parcel.writeException(e);
+ } catch (Exception ex) {
+ // getType threw an unparcelable exception. Wrap the message into
+ // a parcelable exception type
+ parcel.writeException(new IllegalStateException(e.getMessage()));
+ }
+ result.putByteArray(ContentResolver.REMOTE_CALLBACK_ERROR, parcel.marshall());
+ } finally {
+ parcel.recycle();
+ }
+ }
callback.sendResult(result);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7510ce73a59a..59862ae132a9 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -55,6 +55,7 @@ import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.OperationCanceledException;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -735,6 +736,9 @@ public abstract class ContentResolver implements ContentInterface {
/** @hide */
public static final String REMOTE_CALLBACK_RESULT = "result";
+ /** @hide */
+ public static final String REMOTE_CALLBACK_ERROR = "error";
+
/**
* How long we wait for an attached process to publish its content providers
* before we decide it must be hung.
@@ -874,6 +878,9 @@ public abstract class ContentResolver implements ContentInterface {
final StringResultListener resultListener = new StringResultListener();
provider.getTypeAsync(url, new RemoteCallback(resultListener));
resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ if (resultListener.exception != null) {
+ throw resultListener.exception;
+ }
return resultListener.result;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
@@ -898,6 +905,9 @@ public abstract class ContentResolver implements ContentInterface {
resolveUserId(url),
new RemoteCallback(resultListener));
resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ if (resultListener.exception != null) {
+ throw resultListener.exception;
+ }
return resultListener.result;
} catch (RemoteException e) {
// We just failed to send a oneway request to the System Server. Nothing to do.
@@ -915,15 +925,41 @@ public abstract class ContentResolver implements ContentInterface {
@GuardedBy("this")
public T result;
+ @GuardedBy("this")
+ public RuntimeException exception;
+
@Override
public void onResult(Bundle result) {
synchronized (this) {
- this.result = getResultFromBundle(result);
+ this.exception = getExceptionFromBundle(result);
+ if (this.exception == null) {
+ this.result = getResultFromBundle(result);
+ }
done = true;
notifyAll();
}
}
+ private RuntimeException getExceptionFromBundle(Bundle result) {
+ byte[] bytes = result.getByteArray(REMOTE_CALLBACK_ERROR);
+ if (bytes == null) {
+ return null;
+ }
+
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.unmarshall(bytes, 0, bytes.length);
+ parcel.setDataPosition(0);
+ parcel.readException();
+ } catch (RuntimeException ex) {
+ return ex;
+ } finally {
+ parcel.recycle();
+ }
+
+ return null;
+ }
+
protected abstract T getResultFromBundle(Bundle result);
public void waitForResult(long timeout) {
@@ -1250,6 +1286,9 @@ public abstract class ContentResolver implements ContentInterface {
provider.canonicalizeAsync(mPackageName, mAttributionTag, url,
new RemoteCallback(resultListener));
resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ if (resultListener.exception != null) {
+ throw resultListener.exception;
+ }
return resultListener.result;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7d5fca44833c..b67060111785 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -752,6 +752,30 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public @interface ApplicationInfoPrivateFlags {}
/**
+ * Constant corresponding to <code>allowed</code> in the
+ * {@link android.R.attr#autoRevokePermissions} attribute.
+ *
+ * @hide
+ */
+ public static final int AUTO_REVOKE_ALLOWED = 0;
+
+ /**
+ * Constant corresponding to <code>discouraged</code> in the
+ * {@link android.R.attr#autoRevokePermissions} attribute.
+ *
+ * @hide
+ */
+ public static final int AUTO_REVOKE_DISCOURAGED = 1;
+
+ /**
+ * Constant corresponding to <code>disallowed</code> in the
+ * {@link android.R.attr#autoRevokePermissions} attribute.
+ *
+ * @hide
+ */
+ public static final int AUTO_REVOKE_DISALLOWED = 2;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* @hide
*/
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 6ba811e077ac..7578ede2648d 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -487,6 +487,34 @@ public class CrossProfileApps {
}
}
+ /**
+ * Clears the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} back to
+ * its default value for every package on the device.
+ *
+ * <p>This method can be used to ensure that app-op state is not left around on existing users
+ * for previously-configured profiles.
+ *
+ * <p>If the caller does not have the {@link android.Manifest.permission
+ * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that
+ * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String,
+ * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}.
+ *
+ * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link
+ * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ *
+ * @hide
+ */
+ @RequiresPermission(
+ allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ public void clearInteractAcrossProfilesAppOps() {
+ try {
+ mService.clearInteractAcrossProfilesAppOps();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private void verifyCanAccessUser(UserHandle userHandle) {
if (!getTargetUserProfiles().contains(userHandle)) {
throw new SecurityException("Not allowed to access " + userHandle);
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index 9b0dae221538..e2850f111c4f 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -40,4 +40,5 @@ interface ICrossProfileApps {
boolean canConfigureInteractAcrossProfiles(in String packageName);
boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName);
void resetInteractAcrossProfilesAppOps(in List<String> packageNames);
+ void clearInteractAcrossProfilesAppOps();
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 39f285821581..4c9553249a0c 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -192,9 +192,7 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging);
- ParsingPackage setDontAutoRevokePermissions(boolean dontAutoRevokePermissions);
-
- ParsingPackage setAllowDontAutoRevokePermissions(boolean allowDontAutoRevokePermissions);
+ ParsingPackage setAutoRevokePermissions(int autoRevokePermissions);
ParsingPackage setPreserveLegacyExternalStorage(boolean preserveLegacyExternalStorage);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index f2ab60a5a602..079a47056c24 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -30,7 +30,6 @@ import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
-import android.content.pm.ProcessInfo;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedAttribution;
import android.content.pm.parsing.component.ParsedComponent;
@@ -405,8 +404,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
private boolean hasFragileUserData;
private boolean cantSaveState;
private boolean allowNativeHeapPointerTagging;
- private boolean dontAutoRevokePermissions;
- private boolean allowDontAutoRevokePermissions;
+ private int autoRevokePermissions;
private boolean preserveLegacyExternalStorage;
protected int gwpAsanMode;
@@ -1089,8 +1087,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
dest.writeBoolean(this.hasFragileUserData);
dest.writeBoolean(this.cantSaveState);
dest.writeBoolean(this.allowNativeHeapPointerTagging);
- dest.writeBoolean(this.dontAutoRevokePermissions);
- dest.writeBoolean(this.allowDontAutoRevokePermissions);
+ dest.writeInt(this.autoRevokePermissions);
dest.writeBoolean(this.preserveLegacyExternalStorage);
dest.writeArraySet(this.mimeGroups);
dest.writeInt(this.gwpAsanMode);
@@ -1249,8 +1246,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
this.hasFragileUserData = in.readBoolean();
this.cantSaveState = in.readBoolean();
this.allowNativeHeapPointerTagging = in.readBoolean();
- this.dontAutoRevokePermissions = in.readBoolean();
- this.allowDontAutoRevokePermissions = in.readBoolean();
+ this.autoRevokePermissions = in.readInt();
this.preserveLegacyExternalStorage = in.readBoolean();
this.mimeGroups = (ArraySet<String>) in.readArraySet(boot);
this.gwpAsanMode = in.readInt();
@@ -2026,13 +2022,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
- public boolean isDontAutoRevokePermmissions() {
- return dontAutoRevokePermissions;
- }
-
- @Override
- public boolean isAllowDontAutoRevokePermmissions() {
- return allowDontAutoRevokePermissions;
+ public int getAutoRevokePermissions() {
+ return autoRevokePermissions;
}
@Override
@@ -2506,14 +2497,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
- public ParsingPackageImpl setDontAutoRevokePermissions(boolean value) {
- dontAutoRevokePermissions = value;
- return this;
- }
-
- @Override
- public ParsingPackageImpl setAllowDontAutoRevokePermissions(boolean value) {
- allowDontAutoRevokePermissions = value;
+ public ParsingPackageImpl setAutoRevokePermissions(int value) {
+ autoRevokePermissions = value;
return this;
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index e700c6a5fd81..687bc235cfa7 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -771,11 +771,7 @@ public interface ParsingPackageRead extends Parcelable {
/** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING */
boolean isAllowNativeHeapPointerTagging();
- /** @see ApplicationInfo#PRIVATE_FLAG2_DONT_AUTO_REVOKE_PERMISSIONS */
- boolean isDontAutoRevokePermmissions();
-
- /** @see ApplicationInfo#PRIVATE_FLAG2_ALLOW_DONT_AUTO_REVOKE_PERMISSIONS */
- boolean isAllowDontAutoRevokePermmissions();
+ int getAutoRevokePermissions();
boolean hasPreserveLegacyExternalStorage();
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 789904aae6f9..ec771286d980 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1829,8 +1829,7 @@ public class ParsingPackageUtils {
.setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
.setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
.setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
- .setDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_requestAutoRevokePermissionsExemption, sa))
- .setAllowDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_allowAutoRevokePermissionsExemption, sa))
+ .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
// targetSdkVersion gated
.setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
.setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
index 8bcaf828be97..e7219caf6cd8 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -26,7 +26,9 @@ package android.hardware.biometrics;
oneway interface IBiometricServiceReceiverInternal {
// Notify BiometricService that authentication was successful. If user confirmation is required,
// the auth token must be submitted into KeyStore.
- void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token);
+ // TODO(b/151967372): Strength should be changed to authenticatorId
+ void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token,
+ boolean isStrongBiometric);
// Notify BiometricService authentication was rejected.
void onAuthenticationFailed();
// Notify BiometricService than an error has occured. Forward to the correct receiver depending
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7c34ddcb9287..6daded4ee641 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1249,6 +1249,7 @@ public class InputMethodService extends AbstractInputMethodService {
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
+ mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true);
// IME layout should always be inset by navigation bar, no matter its current visibility,
// unless automotive requests it, since automotive may hide the navigation bar.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 05d7860ff891..af9414c56654 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -415,6 +415,20 @@ public final class NetworkCapabilities implements Parcelable {
| (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);
/**
+ * Capabilities that are allowed for test networks. This list must be set so that it is safe
+ * for an unprivileged user to create a network with these capabilities via shell. As such,
+ * it must never contain capabilities that are generally useful to the system, such as
+ * INTERNET, IMS, SUPL, etc.
+ */
+ private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES =
+ (1 << NET_CAPABILITY_NOT_METERED)
+ | (1 << NET_CAPABILITY_NOT_RESTRICTED)
+ | (1 << NET_CAPABILITY_NOT_VPN)
+ | (1 << NET_CAPABILITY_NOT_ROAMING)
+ | (1 << NET_CAPABILITY_NOT_CONGESTED)
+ | (1 << NET_CAPABILITY_NOT_SUSPENDED);
+
+ /**
* Adds the given capability to this {@code NetworkCapability} instance.
* Note that when searching for a network to satisfy a request, all capabilities
* requested must be satisfied.
@@ -646,6 +660,21 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Test networks have strong restrictions on what capabilities they can have. Enforce these
+ * restrictions.
+ * @hide
+ */
+ public void restrictCapabilitesForTestNetwork() {
+ final long originalCapabilities = mNetworkCapabilities;
+ final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
+ clearAll();
+ // Reset the transports to only contain TRANSPORT_TEST.
+ mTransportTypes = (1 << TRANSPORT_TEST);
+ mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
+ mNetworkSpecifier = originalSpecifier;
+ }
+
+ /**
* Representing the transport type. Apps should generally not care about transport. A
* request for a fast internet connection could be satisfied by a number of different
* transports. If any are specified here it will be satisfied a Network that matches
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b7b3c4fc8add..5d2c9d18c00c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -607,6 +607,9 @@ public class Process {
* started.
* @param pkgDataInfoMap Map from related package names to private data directory
* volume UUID and inode number.
+ * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+ * volume UUID and inode number.
+ * @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
* @param zygoteArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
@@ -631,13 +634,17 @@ public class Process {
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
+ @Nullable Map<String, Pair<String, Long>>
+ whitelistedDataInfoMap,
+ boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
zygotePolicyFlags, isTopApp, disabledCompatChanges,
- pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
+ pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
+ bindMountAppStorageDirs, zygoteArgs);
}
/** @hide */
@@ -661,7 +668,8 @@ public class Process {
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, /*isTopApp=*/ false,
- disabledCompatChanges, /* pkgDataInfoMap */ null, false, zygoteArgs);
+ disabledCompatChanges, /* pkgDataInfoMap */ null,
+ /* whitelistedDataInfoMap */ null, false, false, zygoteArgs);
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 5f3f14facd75..a4c99c006d80 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -333,6 +333,9 @@ public class ZygoteProcess {
* started.
* @param pkgDataInfoMap Map from related package names to private data directory
* volume UUID and inode number.
+ * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+ * volume UUID and inode number.
+ * @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
*
* @param zygoteArgs Additional arguments to supply to the Zygote process.
@@ -355,6 +358,9 @@ public class ZygoteProcess {
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
+ @Nullable Map<String, Pair<String, Long>>
+ whitelistedDataInfoMap,
+ boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
// TODO (chriswailes): Is there a better place to check this value?
@@ -367,7 +373,8 @@ public class ZygoteProcess {
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
- pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
+ pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
+ bindMountAppStorageDirs, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -608,6 +615,9 @@ public class ZygoteProcess {
* @param disabledCompatChanges a list of disabled compat changes for the process being started.
* @param pkgDataInfoMap Map from related package names to private data directory volume UUID
* and inode number.
+ * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+ * volume UUID and inode number.
+ * @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
@@ -631,6 +641,9 @@ public class ZygoteProcess {
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
+ @Nullable Map<String, Pair<String, Long>>
+ whitelistedDataInfoMap,
+ boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
@@ -728,11 +741,33 @@ public class ZygoteProcess {
}
argsForZygote.add(sb.toString());
}
+ if (whitelistedDataInfoMap != null && whitelistedDataInfoMap.size() > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Zygote.WHITELISTED_DATA_INFO_MAP);
+ sb.append("=");
+ boolean started = false;
+ for (Map.Entry<String, Pair<String, Long>> entry : whitelistedDataInfoMap.entrySet()) {
+ if (started) {
+ sb.append(',');
+ }
+ started = true;
+ sb.append(entry.getKey());
+ sb.append(',');
+ sb.append(entry.getValue().first);
+ sb.append(',');
+ sb.append(entry.getValue().second);
+ }
+ argsForZygote.add(sb.toString());
+ }
if (bindMountAppStorageDirs) {
argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
}
+ if (bindMountAppsData) {
+ argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS);
+ }
+
if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--disabled-compat-changes=");
@@ -1291,6 +1326,7 @@ public class ZygoteProcess {
true /* startChildZygote */, null /* packageName */,
ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
+ null /* whitelistedDataInfoMap */, false /* bindMountAppsData*/,
/* bindMountAppStorageDirs */ false, extraArgs);
} catch (ZygoteStartFailedEx ex) {
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index bbc936d76e1c..99bdfd1fc103 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -194,4 +194,5 @@ interface IStorageManager {
boolean needsCheckpoint() = 86;
void abortChanges(in String message, boolean retry) = 87;
void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
+ void fixupAppDir(in String path) = 89;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 1454aac66d21..aee32ed769ac 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -162,7 +162,12 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_SETTINGS_FUSE = FeatureFlagUtils.PERSIST_PREFIX
+ FeatureFlagUtils.SETTINGS_FUSE_FLAG;
-
+ /**
+ * Property that determines whether {@link OP_LEGACY_STORAGE} is sticky for
+ * legacy apps.
+ * @hide
+ */
+ public static final String PROP_LEGACY_OP_STICKY = "persist.sys.legacy_storage_sticky";
/** {@hide} */
public static final String UUID_PRIVATE_INTERNAL = null;
@@ -2470,6 +2475,36 @@ public class StorageManager {
}
}
+ /**
+ * Asks StorageManager to fixup the permissions of an application-private directory.
+ *
+ * On devices without sdcardfs, filesystem permissions aren't magically fixed up. This
+ * is problematic mostly in application-private directories, which are owned by the
+ * application itself; if another process with elevated permissions creates a file
+ * in these directories, the UID will be wrong, and the owning package won't be able
+ * to access the files.
+ *
+ * This API can be used to recursively fix up the permissions on the passed in path.
+ * The default platform user of this API is the DownloadProvider, which can download
+ * things in application-private directories on their behalf.
+ *
+ * This API doesn't require any special permissions, because it merely changes the
+ * permissions of a directory to what they should anyway be.
+ *
+ * @param path the path for which we should fix up the permissions
+ *
+ * @hide
+ */
+ public void fixupAppDir(@NonNull File path) {
+ try {
+ mStorageManager.fixupAppDir(path.getCanonicalPath());
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to get canonical path for " + path.getPath(), e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** {@hide} */
private static void setCacheBehavior(File path, String name, boolean enabled)
throws IOException {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 60f10cd884ca..bbcb9d9249af 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6564,13 +6564,6 @@ public final class Settings {
* Setting specifying if the accessibility shortcut is enabled.
* @hide
*/
- public static final String ACCESSIBILITY_SHORTCUT_ENABLED =
- "accessibility_shortcut_enabled";
-
- /**
- * Setting specifying if the accessibility shortcut is enabled.
- * @hide
- */
public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN =
"accessibility_shortcut_on_lock_screen";
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index a9addba375af..b6a8ced29f72 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -49,7 +49,8 @@ public final class InlinePresentation implements Parcelable {
private final @NonNull InlinePresentationSpec mInlinePresentationSpec;
/**
- * Indicates whether the UI should be pinned, hence non-scrollable, in the host.
+ * Indicates whether the UI should be pinned, hence non-scrollable and non-filterable, in the
+ * host.
*/
private final boolean mPinned;
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index cd22ad6151b8..fe70ff7a1dbf 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -192,6 +192,7 @@ public class SurfaceControlViewHost {
final WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(width, height,
WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+ lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
setView(view, lp);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 59fc6e9b5ede..c89e0c9fc60e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -176,6 +176,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
boolean mUseAlpha = false;
float mSurfaceAlpha = 1f;
boolean mClipSurfaceToBounds;
+ int mBackgroundColor = Color.BLACK;
@UnsupportedAppUsage
boolean mHaveFrame = false;
@@ -828,6 +829,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
+ private Transaction updateBackgroundColor(Transaction t) {
+ final float[] colorComponents = new float[] { Color.red(mBackgroundColor) / 255.f,
+ Color.green(mBackgroundColor) / 255.f, Color.blue(mBackgroundColor) / 255.f };
+ t.setColor(mBackgroundControl, colorComponents);
+ return t;
+ }
private void releaseSurfaces() {
mSurfaceAlpha = 1f;
@@ -1000,6 +1007,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
updateBackgroundVisibility(mTmpTransaction);
+ updateBackgroundColor(mTmpTransaction);
if (mUseAlpha) {
mTmpTransaction.setAlpha(mSurfaceControl, alpha);
mSurfaceAlpha = alpha;
@@ -1399,10 +1407,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
return;
}
- final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
- Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
-
- mTmpTransaction.setColor(mBackgroundControl, colorComponents).apply();
+ mBackgroundColor = bgColor;
+ updateBackgroundColor(mTmpTransaction).apply();
}
@UnsupportedAppUsage
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 54ea57a6cae4..d64b5f1118dc 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -144,9 +144,6 @@ public class AccessibilityShortcutController {
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
false, co, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED),
- false, co, UserHandle.USER_ALL);
- mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN),
false, co, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
@@ -174,8 +171,6 @@ public class AccessibilityShortcutController {
public void onSettingsChanged() {
final boolean hasShortcutTarget = hasShortcutTarget();
final ContentResolver cr = mContext.getContentResolver();
- final boolean enabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
// Enable the shortcut from the lockscreen by default if the dialog has been shown
final int dialogAlreadyShown = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, DialogStaus.NOT_SHOWN,
@@ -183,7 +178,7 @@ public class AccessibilityShortcutController {
mEnabledOnLockScreen = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
dialogAlreadyShown, mUserId) == 1;
- mIsShortcutEnabled = enabled && hasShortcutTarget;
+ mIsShortcutEnabled = hasShortcutTarget;
}
/**
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index ff03f1a1a2ab..c75898994f3e 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -205,9 +205,15 @@ public final class Zygote {
/** List of packages with the same uid, and its app data info: volume uuid and inode. */
public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
+ /** List of whitelisted packages and its app data info: volume uuid and inode. */
+ public static final String WHITELISTED_DATA_INFO_MAP = "--whitelisted-data-info-map";
+
/** Bind mount app storage dirs to lower fs not via fuse */
public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
+ /** Bind mount app storage dirs to lower fs not via fuse */
+ public static final String BIND_MOUNT_APP_DATA_DIRS = "--bind-mount-data-dirs";
+
/**
* An extraArg passed when a zygote process is forking a child-zygote, specifying a name
* in the abstract socket namespace. This socket name is what the new child zygote
@@ -313,6 +319,8 @@ public final class Zygote {
* @param isTopApp true if the process is for top (high priority) application.
* @param pkgDataInfoList A list that stores related packages and its app data
* info: volume uuid and inode.
+ * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps.
+ * @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
*
* @return 0 if this is the child, pid of the child
@@ -321,13 +329,15 @@ public final class Zygote {
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
- boolean isTopApp, String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
+ boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
ZygoteHooks.preFork();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
- pkgDataInfoList, bindMountAppStorageDirs);
+ pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs,
+ bindMountAppStorageDirs);
if (pid == 0) {
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -344,6 +354,7 @@ public final class Zygote {
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
+ String[] whitelistedDataInfoList, boolean bindMountAppDataDirs,
boolean bindMountAppStorageDirs);
/**
@@ -371,15 +382,19 @@ public final class Zygote {
* volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
* app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
* app_b_ce_inode, ...];
+ * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps.
+ * @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
*/
private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
- String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
+ String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
- pkgDataInfoList, bindMountAppStorageDirs);
+ pkgDataInfoList, whitelistedDataInfoList,
+ bindMountAppDataDirs, bindMountAppStorageDirs);
// Note that this event ends at the end of handleChildProc.
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -399,7 +414,8 @@ public final class Zygote {
private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
- String[] pkgDataInfoList, boolean bindMountAppStorageDirs);
+ String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs);
/**
* Called to do any initialization before starting an application.
@@ -724,7 +740,8 @@ public final class Zygote {
args.mRuntimeFlags, rlimits, args.mMountExternal,
args.mSeInfo, args.mNiceName, args.mStartChildZygote,
args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
- args.mPkgDataInfoList, args.mBindMountAppStorageDirs);
+ args.mPkgDataInfoList, args.mWhitelistedDataInfoList,
+ args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 1a63765fcaa6..94c1f71a26db 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -227,11 +227,22 @@ class ZygoteArguments {
String[] mPkgDataInfoList;
/**
+ * A list that stores all whitelisted app data info: volume uuid and inode.
+ * Null if it does need to do app data isolation.
+ */
+ String[] mWhitelistedDataInfoList;
+
+ /**
* @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS
*/
boolean mBindMountAppStorageDirs;
/**
+ * @see Zygote#BIND_MOUNT_APP_DATA_DIRS
+ */
+ boolean mBindMountAppDataDirs;
+
+ /**
* Constructs instance and parses args
*
* @param args zygote command-line args
@@ -452,8 +463,12 @@ class ZygoteArguments {
}
} else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
mPkgDataInfoList = getAssignmentList(arg);
+ } else if (arg.startsWith(Zygote.WHITELISTED_DATA_INFO_MAP)) {
+ mWhitelistedDataInfoList = getAssignmentList(arg);
} else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) {
mBindMountAppStorageDirs = true;
+ } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
+ mBindMountAppDataDirs = true;
} else {
break;
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index bc8dfd4aa402..6e880d43b73e 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -258,7 +258,8 @@ class ZygoteConnection {
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
- parsedArgs.mPkgDataInfoList, parsedArgs.mBindMountAppStorageDirs);
+ parsedArgs.mPkgDataInfoList,parsedArgs.mWhitelistedDataInfoList,
+ parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
try {
if (pid == 0) {
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c83cab77dd13..31527e8dbe5d 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -227,7 +227,7 @@ public class ResolverDrawerLayout extends ViewGroup {
}
final int oldCollapsibleHeight = mCollapsibleHeight;
- mCollapsibleHeight = Math.max(mCollapsibleHeight, getMaxCollapsedHeight());
+ mCollapsibleHeight = Math.min(mCollapsibleHeight, getMaxCollapsedHeight());
if (updateCollapseOffset(oldCollapsibleHeight, !isDragging())) {
return;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index ea3c0fa9fc3c..aa2d1b5fa02b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -110,7 +110,6 @@ using android::base::StringAppendF;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
using android::base::GetBoolProperty;
-using android::base::GetProperty;
#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
append(StringPrintf(__VA_ARGS__))
@@ -170,18 +169,6 @@ static int gSystemServerSocketFd = -1;
static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751;
-/**
- * Property to control if app data isolation is enabled.
- */
-static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
- "persist.zygote.app_data_isolation";
-
-/**
- * Property to enable app data isolation for sdcard obb or data in vold.
- */
-static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
- "persist.sys.vold_app_data_isolation_enabled";
-
static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;
@@ -1319,20 +1306,13 @@ static void relabelAllDirs(const char* path, security_context_t context, fail_fn
* be decrypted after storage is decrypted.
*
*/
-static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
- uid_t uid, const char* process_name, jstring managed_nice_name,
- fail_fn_t fail_fn) {
+static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_data_info_list,
+ uid_t uid, const char* process_name,
+ jstring managed_nice_name, fail_fn_t fail_fn) {
const userid_t userId = multiuser_get_user_id(uid);
- auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
-
- int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
- // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
- if ((size % 3) != 0) {
- fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
- }
- ensureInAppMountNamespace(fail_fn);
+ int size = merged_data_info_list.size();
// Mount tmpfs on all possible data directories, so app no longer see the original apps data.
char internalCePath[PATH_MAX];
@@ -1377,14 +1357,10 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
bool legacySymlinkCreated = false;
for (int i = 0; i < size; i += 3) {
- jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
- std::string packageName = extract_fn(package_str).value();
+ std::string const & packageName = merged_data_info_list[i];
+ std::string const & volUuid = merged_data_info_list[i + 1];
+ std::string const & inode = merged_data_info_list[i + 2];
- jstring vol_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 1));
- std::string volUuid = extract_fn(vol_str).value();
-
- jstring inode_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 2));
- std::string inode = extract_fn(inode_str).value();
std::string::size_type sz;
long long ceDataInode = std::stoll(inode, &sz);
@@ -1482,6 +1458,48 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
freecon(dataDataContext);
}
+static void insertPackagesToMergedList(JNIEnv* env,
+ std::vector<std::string>& merged_data_info_list,
+ jobjectArray data_info_list, const char* process_name,
+ jstring managed_nice_name, fail_fn_t fail_fn) {
+
+ auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+
+ int size = (data_info_list != nullptr) ? env->GetArrayLength(data_info_list) : 0;
+ // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
+ if ((size % 3) != 0) {
+ fail_fn(CREATE_ERROR("Wrong data_info_list size %d", size));
+ }
+
+ for (int i = 0; i < size; i += 3) {
+ jstring package_str = (jstring) (env->GetObjectArrayElement(data_info_list, i));
+ std::string packageName = extract_fn(package_str).value();
+ merged_data_info_list.push_back(packageName);
+
+ jstring vol_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 1));
+ std::string volUuid = extract_fn(vol_str).value();
+ merged_data_info_list.push_back(volUuid);
+
+ jstring inode_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 2));
+ std::string inode = extract_fn(inode_str).value();
+ merged_data_info_list.push_back(inode);
+ }
+}
+
+static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
+ jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name,
+ jstring managed_nice_name, fail_fn_t fail_fn) {
+
+ ensureInAppMountNamespace(fail_fn);
+ std::vector<std::string> merged_data_info_list;
+ insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list,
+ process_name, managed_nice_name, fail_fn);
+ insertPackagesToMergedList(env, merged_data_info_list, whitelisted_data_info_list,
+ process_name, managed_nice_name, fail_fn);
+
+ isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+}
+
/**
* Like isolateAppData(), isolate jit profile directories, so apps don't see what
* other apps are installed by reading content inside /data/misc/profiles/cur.
@@ -1594,7 +1612,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
jstring managed_nice_name, bool is_system_server,
bool is_child_zygote, jstring managed_instruction_set,
jstring managed_app_data_dir, bool is_top_app,
- jobjectArray pkg_data_info_list, bool mount_storage_dirs) {
+ jobjectArray pkg_data_info_list,
+ jobjectArray whitelisted_data_info_list,
+ bool mount_data_dirs, bool mount_storage_dirs) {
const char* process_name = is_system_server ? "system_server" : "zygote";
auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1628,9 +1648,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
// give a null in same_uid_pkgs and private_volumes so they don't need app data isolation.
// Isolated process / webview / app zygote should be gated by SELinux and file permission
// so they can't even traverse CE / DE directories.
- if (pkg_data_info_list != nullptr
- && GetBoolProperty(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) {
- isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+ if (mount_data_dirs) {
+ isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list,
+ uid, process_name, managed_nice_name, fail_fn);
isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && mount_storage_dirs) {
@@ -2003,7 +2023,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
jint mount_external, jstring se_info, jstring nice_name,
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
- jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
+ jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
+ jboolean mount_data_dirs, jboolean mount_storage_dirs) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -2041,6 +2062,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
mount_external, se_info, nice_name, false,
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
is_top_app == JNI_TRUE, pkg_data_info_list,
+ whitelisted_data_info_list,
+ mount_data_dirs == JNI_TRUE,
mount_storage_dirs == JNI_TRUE);
}
return pid;
@@ -2076,7 +2099,8 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
permitted_capabilities, effective_capabilities,
MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, nullptr, nullptr, /* is_top_app= */ false,
- /* pkg_data_info_list */ nullptr, false);
+ /* pkg_data_info_list */ nullptr,
+ /* whitelisted_data_info_list */ nullptr, false, false);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -2206,15 +2230,16 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring nice_name,
jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
- jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
+ jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
+ jboolean mount_data_dirs, jboolean mount_storage_dirs) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
capabilities, capabilities,
mount_external, se_info, nice_name, false,
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
- is_top_app == JNI_TRUE, pkg_data_info_list,
- mount_storage_dirs == JNI_TRUE);
+ is_top_app == JNI_TRUE, pkg_data_info_list, whitelisted_data_info_list,
+ mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE);
}
/**
@@ -2408,7 +2433,7 @@ static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclas
static const JNINativeMethod gMethods[] = {
{"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
- "String;Z[Ljava/lang/String;Z)I",
+ "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I",
(void*)com_android_internal_os_Zygote_nativeForkAndSpecialize},
{"nativeForkSystemServer", "(II[II[[IJJ)I",
(void*)com_android_internal_os_Zygote_nativeForkSystemServer},
@@ -2421,7 +2446,7 @@ static const JNINativeMethod gMethods[] = {
{"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap},
{"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/"
- "String;Z[Ljava/lang/String;Z)V",
+ "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
(void*)com_android_internal_os_Zygote_nativeSpecializeAppProcess},
{"nativeInitNativeState", "(Z)V",
(void*)com_android_internal_os_Zygote_nativeInitNativeState},
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d6e200afc029..28eb98b07690 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1827,19 +1827,11 @@
<attr name="gwpAsanMode" />
- <!-- If {@code true} allow requesting that its permissions don't get automatically
- revoked when the app is unused for an extended amount of time.
-
- The default value is {@code false}. -->
- <attr name="requestAutoRevokePermissionsExemption" format="boolean" />
-
- <!-- If {@code true} its permissions shouldn't get automatically
- revoked when the app is unused for an extended amount of time.
-
- This implies {@code requestDontAutoRevokePermissions=true}
-
- The default value is {@code false}. -->
- <attr name="allowAutoRevokePermissionsExemption" format="boolean" />
+ <attr name="autoRevokePermissions">
+ <enum name="allowed" value="0" />
+ <enum name="discouraged" value="1" />
+ <enum name="disallowed" value="2" />
+ </attr>
</declare-styleable>
<!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f02d54f48d29..e694e160009e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3014,8 +3014,7 @@
<!-- @hide @SystemApi -->
<public name="minExtensionVersion" />
<public name="allowNativeHeapPointerTagging" />
- <public name="requestAutoRevokePermissionsExemption" />
- <public name="allowAutoRevokePermissionsExemption" />
+ <public name="autoRevokePermissions" />
<public name="preserveLegacyExternalStorage" />
<public name="mimeGroup" />
<public name="gwpAsanMode" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 2ef0c927cc61..88f9fc2199e5 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -702,7 +702,7 @@ please see themes_device_defaults.xml.
</style>
<style name="Theme.Dream">
- <item name="windowBackground">@null</item>
+ <item name="windowBackground">@color/black</item>
<item name="windowDisablePreview">true</item>
</style>
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 1737bd0fa20b..57e5dd8f8f20 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -236,6 +237,16 @@ public class ContentResolverTest {
}
@Test
+ public void testGetType_providerException() {
+ try {
+ mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error"));
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ @Test
public void testCanonicalize() {
Uri canonical = mResolver.canonicalize(
Uri.parse("content://android.content.FakeProviderRemote/something"));
diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java
index 1d7ba5d9be46..a32009493094 100644
--- a/core/tests/coretests/src/android/content/FakeProviderRemote.java
+++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java
@@ -37,6 +37,9 @@ public class FakeProviderRemote extends ContentProvider {
@Override
public String getType(Uri uri) {
+ if (uri.getPath() != null && uri.getPath().contains("error")) {
+ throw new IllegalArgumentException("Expected exception");
+ }
return "fake/remote";
}
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index df5c9d2df90b..4114b28a7252 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -184,7 +184,7 @@ public class ResourcesManagerTest extends TestCase {
@SmallTest
public void testThemesGetUpdatedWithNewImpl() {
Binder activity1 = new Binder();
- Resources resources1 = mResourcesManager.createBaseActivityResources(
+ Resources resources1 = mResourcesManager.createBaseTokenResources(
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
@@ -217,7 +217,7 @@ public class ResourcesManagerTest extends TestCase {
// Create a Resources for the Activity.
Configuration config1 = new Configuration();
config1.densityDpi = 280;
- Resources resources1 = mResourcesManager.createBaseActivityResources(
+ Resources resources1 = mResourcesManager.createBaseTokenResources(
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 9af0ed0ab826..4a33da680585 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -17,7 +17,6 @@
package com.android.internal.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
@@ -102,10 +101,8 @@ public class AccessibilityShortcutControllerTest {
private static final long[] VIBRATOR_PATTERN_LONG = {VIBRATOR_PATTERN_1, VIBRATOR_PATTERN_2};
// Convenience values for enabling/disabling to make code more readable
- private static final int DISABLED = 0;
private static final int ENABLED_EXCEPT_LOCK_SCREEN = 1;
private static final int ENABLED_INCLUDING_LOCK_SCREEN = 2;
- private static final int DISABLED_BUT_LOCK_SCREEN_ON = 3;
private @Mock Context mContext;
private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
@@ -225,14 +222,6 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse()
- throws Exception {
- configureValidShortcutService();
- configureShortcutEnabled(DISABLED_BUT_LOCK_SCREEN_ON);
- assertFalse(getController().isAccessibilityShortcutAvailable(false));
- }
-
- @Test
public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse()
throws Exception {
configureValidShortcutService();
@@ -285,20 +274,8 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse()
- throws Exception {
- configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
- configureValidShortcutService();
- AccessibilityShortcutController accessibilityShortcutController = getController();
- configureShortcutEnabled(DISABLED);
- accessibilityShortcutController.onSettingsChanged();
- assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
- }
-
- @Test
public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue()
throws Exception {
- configureShortcutEnabled(DISABLED);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -594,31 +571,19 @@ public class AccessibilityShortcutControllerTest {
}
private void configureShortcutEnabled(int enabledValue) {
- final boolean enabled;
final boolean lockscreen;
switch (enabledValue) {
- case DISABLED:
- enabled = false;
- lockscreen = false;
- break;
- case DISABLED_BUT_LOCK_SCREEN_ON:
- enabled = false;
- lockscreen = true;
- break;
case ENABLED_INCLUDING_LOCK_SCREEN:
- enabled = true;
lockscreen = true;
break;
case ENABLED_EXCEPT_LOCK_SCREEN:
- enabled = true;
lockscreen = false;
break;
default:
throw new IllegalArgumentException();
}
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_ENABLED, enabled ? 1 : 0);
Settings.Secure.putInt(
mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, lockscreen ? 1 : 0);
}
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index 5c89da05a68c..98f5824011ae 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -61,7 +61,6 @@ Do NOT include any apps that are updatable via Play Store!
<hidden-api-whitelisted-app package="com.android.terminal" />
<hidden-api-whitelisted-app package="com.android.wallpaper" />
<hidden-api-whitelisted-app package="jp.co.omronsoft.openwnn" />
- <!-- STOPSHIP: Remove this when fixing all @hide usage for tethering.-->
- <hidden-api-whitelisted-app package="com.android.networkstack.tethering" />
+ <!-- TODO: Remove NetworkStack whitelisting -->
<hidden-api-whitelisted-app package="com.android.networkstack" />
</config>
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8b973a177f90..0a56accd1636 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -708,6 +708,8 @@ public class AudioSystem
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
}
+ public static final String LEGACY_REMOTE_SUBMIX_ADDRESS = "0";
+
// device states, must match AudioSystem::device_connection_state
@UnsupportedAppUsage
public static final int DEVICE_STATE_UNAVAILABLE = 0;
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 29dfd730a84c..9310d38c3bd1 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -40,6 +40,7 @@ using ::android::hardware::tv::tuner::V1_0::DataFormat;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
+using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
@@ -1382,6 +1383,42 @@ jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
return dvrObj;
}
+jobject JTuner::getDemuxCaps() {
+ DemuxCapabilities caps;
+ Result res;
+ mTuner->getDemuxCaps([&](Result r, const DemuxCapabilities& demuxCaps) {
+ caps = demuxCaps;
+ res = r;
+ });
+ if (res != Result::SUCCESS) {
+ return NULL;
+ }
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass clazz = env->FindClass("android/media/tv/tuner/DemuxCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIIIIJI[IZ)V");
+
+ jint numDemux = caps.numDemux;
+ jint numRecord = caps.numRecord;
+ jint numPlayback = caps.numPlayback;
+ jint numTsFilter = caps.numTsFilter;
+ jint numSectionFilter = caps.numSectionFilter;
+ jint numAudioFilter = caps.numAudioFilter;
+ jint numVideoFilter = caps.numVideoFilter;
+ jint numPesFilter = caps.numPesFilter;
+ jint numPcrFilter = caps.numPcrFilter;
+ jlong numBytesInSectionFilter = caps.numBytesInSectionFilter;
+ jint filterCaps = static_cast<jint>(caps.filterCaps);
+ jboolean bTimeFilter = caps.bTimeFilter;
+
+ jintArray linkCaps = env->NewIntArray(caps.linkCaps.size());
+ env->SetIntArrayRegion(
+ linkCaps, 0, caps.linkCaps.size(), reinterpret_cast<jint*>(&caps.linkCaps[0]));
+
+ return env->NewObject(clazz, capsInit, numDemux, numRecord, numPlayback, numTsFilter,
+ numSectionFilter, numAudioFilter, numVideoFilter, numPesFilter, numPcrFilter,
+ numBytesInSectionFilter, filterCaps, linkCaps, bTimeFilter);
+}
+
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -2739,8 +2776,9 @@ static jobject android_media_tv_Tuner_open_dvr_playback(
return tuner->openDvr(DvrType::PLAYBACK, bufferSize);
}
-static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv*, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->getDemuxCaps();
}
static int android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 5d2bba6c8aa2..18aac285e7c0 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -185,6 +185,7 @@ struct JTuner : public RefBase {
jobject openTimeFilter();
jobject openDescrambler();
jobject openDvr(DvrType type, jlong bufferSize);
+ jobject getDemuxCaps();
protected:
Result openDemux();
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index a2fa46130076..a95677d0202f 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -406,6 +406,10 @@ public class PackageInstallerActivity extends AlertActivity {
mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);
+
+ if (!mOk.isInTouchMode()) {
+ mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
+ }
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 2b841967d4a8..59735f413f9d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -189,19 +189,6 @@ public class AccessibilityUtils {
return context.getString(R.string.config_defaultAccessibilityService);
}
- /**
- * Check if the accessibility shortcut is enabled for a user
- *
- * @param context A valid context
- * @param userId The user of interest
- * @return {@code true} if the shortcut is enabled for the user. {@code false} otherwise.
- * Note that the shortcut may be enabled, but no action associated with it.
- */
- public static boolean isShortcutEnabled(Context context, int userId) {
- return Settings.Secure.getIntForUser(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, userId) == 1;
- }
-
private static Set<ComponentName> getInstalledServices(Context context) {
final Set<ComponentName> installedServices = new HashSet<>();
installedServices.clear();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index d17f242d5d63..a1fba4a018e2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -174,7 +174,7 @@ public class HearingAidProfile implements LocalBluetoothProfile {
@Override
public boolean isEnabled(BluetoothDevice device) {
- if (mService == null) {
+ if (mService == null || device == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
@@ -182,7 +182,7 @@ public class HearingAidProfile implements LocalBluetoothProfile {
@Override
public int getConnectionPolicy(BluetoothDevice device) {
- if (mService == null) {
+ if (mService == null || device == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
@@ -191,7 +191,7 @@ public class HearingAidProfile implements LocalBluetoothProfile {
@Override
public boolean setEnabled(BluetoothDevice device, boolean enabled) {
boolean isEnabled = false;
- if (mService == null) {
+ if (mService == null || device == null) {
return false;
}
if (enabled) {
@@ -213,7 +213,7 @@ public class HearingAidProfile implements LocalBluetoothProfile {
}
public long getHiSyncId(BluetoothDevice device) {
- if (mService == null) {
+ if (mService == null || device == null) {
return BluetoothHearingAid.HI_SYNC_ID_INVALID;
}
return mService.getHiSyncId(device);
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index c34c365c1bfa..7ef080178a2f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -169,6 +169,22 @@ public class MetricsFeatureProvider {
sourceMetricsCategory);
}
+ /**
+ * Logs an event when the intent is started by Profile select dialog.
+ *
+ * @return true if the intent is loggable, otherwise false
+ */
+ public boolean logStartedIntentWithProfile(Intent intent, int sourceMetricsCategory,
+ boolean isWorkProfile) {
+ if (intent == null) {
+ return false;
+ }
+ final ComponentName cn = intent.getComponent();
+ final String key = cn != null ? cn.flattenToString() : intent.getAction();
+ return logSettingsTileClick(key + (isWorkProfile ? "/work" : "/personal"),
+ sourceMetricsCategory);
+ }
+
private boolean logSettingsTileClick(String logKey, int sourceMetricsCategory) {
if (TextUtils.isEmpty(logKey)) {
// Not loggable
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index ed0857ca21dc..204a93333d81 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -164,6 +164,38 @@ public class MetricsFeatureProviderTest {
}
@Test
+ public void logStartedIntentWithProfile_isPersonalProfile_shouldTagPersonal() {
+ final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+ final boolean loggable = mProvider.logStartedIntentWithProfile(intent,
+ MetricsEvent.SETTINGS_GESTURES, false);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).action(
+ MetricsEvent.SETTINGS_GESTURES,
+ MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ SettingsEnums.PAGE_UNKNOWN,
+ "pkg/cls/personal",
+ 0);
+ }
+
+ @Test
+ public void logStartedIntentWithProfile_isWorkProfile_shouldTagWork() {
+ final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+ final boolean loggable = mProvider.logStartedIntentWithProfile(intent,
+ MetricsEvent.SETTINGS_GESTURES, true);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).action(
+ MetricsEvent.SETTINGS_GESTURES,
+ MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ SettingsEnums.PAGE_UNKNOWN,
+ "pkg/cls/work",
+ 0);
+ }
+
+ @Test
public void getAttribution_noActivity_shouldReturnUnknown() {
assertThat(mProvider.getAttribution(null /* activity */))
.isEqualTo(SettingsEnums.PAGE_UNKNOWN);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index d350d9df37b8..d320df9c24ba 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -48,7 +48,6 @@ public class SecureSettings {
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4d33b627f4e2..8801a9c32a36 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -25,10 +25,10 @@ import static android.provider.settings.validators.SettingsValidators.COMMA_SEPA
import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.JSON_OBJECT_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
@@ -82,7 +82,6 @@ public class SecureSettingsValidators {
Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index af74121a11c9..b22caf0edc66 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1781,9 +1781,6 @@ class SettingsProtoDumpUtil {
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
SecureSettingsProto.Accessibility.LARGE_POINTER_ICON);
dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
- SecureSettingsProto.Accessibility.SHORTCUT_ENABLED);
- dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
SecureSettingsProto.Accessibility.SHORTCUT_ON_LOCK_SCREEN);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 5a9d7497b641..2fde87c08ad5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3436,7 +3436,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 188;
+ private static final int SETTINGS_VERSION = 189;
private final int mUserId;
@@ -4759,6 +4759,23 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 188;
}
+ if (currentVersion == 188) {
+ // Deprecate ACCESSIBILITY_SHORTCUT_ENABLED, and migrate it
+ // to ACCESSIBILITY_SHORTCUT_TARGET_SERVICE.
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ final Setting shortcutEnabled = secureSettings.getSettingLocked(
+ "accessibility_shortcut_enabled");
+ if ("0".equals(shortcutEnabled.getValue())) {
+ // Clear shortcut key targets list setting.
+ secureSettings.insertSettingLocked(
+ Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ "", null /* tag */, false /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ secureSettings.deleteSettingLocked("accessibility_shortcut_enabled");
+ currentVersion = 189;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 64e52376effd..0ae00e1ac8b5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1019,8 +1019,11 @@ public class BugreportProgressService extends Service {
* Wraps up bugreport generation and triggers a notification to share the bugreport.
*/
private void onBugreportFinished(BugreportInfo info) {
+ if (!TextUtils.isEmpty(info.shareTitle)) {
+ info.setTitle(info.shareTitle);
+ }
Log.d(TAG, "Bugreport finished with title: " + info.getTitle()
- + " and shareDescription: " + info.shareDescription);
+ + " and shareDescription: " + info.shareDescription);
info.finished = new AtomicBoolean(true);
synchronized (mLock) {
@@ -1795,7 +1798,9 @@ public class BugreportProgressService extends Service {
/**
* User-provided, detailed description of the bugreport; when set, will be added to the body
- * of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
+ * of the {@link Intent#ACTION_SEND_MULTIPLE} intent. This is shown in the app where the
+ * bugreport is being shared as an attachment. This is not related/dependant on
+ * {@code shareDescription}.
*/
private String description;
@@ -2130,7 +2135,6 @@ public class BugreportProgressService extends Service {
return new BugreportInfo[size];
}
};
-
}
@GuardedBy("mLock")
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 07bd3a0567e6..136935080824 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -73,14 +73,19 @@ public class QuickStepContract {
public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1 << 9;
// The search feature is disabled (either by SUW/SysUI/device policy)
public static final int SYSUI_STATE_SEARCH_DISABLED = 1 << 10;
- // The notification panel is expanded and interactive (either locked or unlocked), and the
- // quick settings is not expanded
+ // The notification panel is expanded and interactive (either locked or unlocked), and quick
+ // settings is expanded.
public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11;
// Winscope tracing is enabled
public static final int SYSUI_STATE_TRACING_ENABLED = 1 << 12;
// The Assistant gesture should be constrained. It is up to the launcher implementation to
// decide how to constrain it
public static final int SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1 << 13;
+ // The bubble stack is expanded. This means that the home gesture should be ignored, since a
+ // swipe up is an attempt to close the bubble stack, but that the back gesture should remain
+ // enabled (since it's used to navigate back within the bubbled app, or to collapse the bubble
+ // stack.
+ public static final int SYSUI_STATE_BUBBLES_EXPANDED = 1 << 14;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -96,7 +101,8 @@ public class QuickStepContract {
SYSUI_STATE_HOME_DISABLED,
SYSUI_STATE_SEARCH_DISABLED,
SYSUI_STATE_TRACING_ENABLED,
- SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED
+ SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
+ SYSUI_STATE_BUBBLES_EXPANDED
})
public @interface SystemUiStateFlags {}
@@ -118,6 +124,7 @@ public class QuickStepContract {
str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
str.add((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0
? "asst_gesture_constrain" : "");
+ str.add((flags & SYSUI_STATE_BUBBLES_EXPANDED) != 0 ? "bubbles_expanded" : "");
return str.toString();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt
new file mode 100644
index 000000000000..487c29573a14
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.graphics.drawable.Drawable
+
+import java.util.List
+
+/** State for lock screen media controls. */
+data class KeyguardMedia(
+ val foregroundColor: Int,
+ val backgroundColor: Int,
+ val app: String?,
+ val appIcon: Drawable?,
+ val artist: String?,
+ val song: String?,
+ val artwork: Drawable?,
+ val actionIcons: List<Drawable>
+)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
index 4fcacc276ac1..d1544346a25a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
@@ -32,6 +32,9 @@ import android.widget.TextView;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
import androidx.palette.graphics.Palette;
import com.android.internal.util.ContrastColorUtil;
@@ -64,39 +67,47 @@ public class KeyguardMediaPlayer {
private final Context mContext;
private final Executor mBackgroundExecutor;
- private float mAlbumArtRadius;
- private int mAlbumArtSize;
- private View mMediaNotifView;
+ private final KeyguardMediaViewModel mViewModel;
+ private KeyguardMediaObserver mObserver;
@Inject
public KeyguardMediaPlayer(Context context, @Background Executor backgroundExecutor) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
- loadDimens();
+ mViewModel = new KeyguardMediaViewModel(context);
}
/** Binds media controls to a view hierarchy. */
public void bindView(View v) {
- if (mMediaNotifView != null) {
+ if (mObserver != null) {
throw new IllegalStateException("cannot bind views, already bound");
}
- mMediaNotifView = v;
- loadDimens();
+ mViewModel.loadDimens();
+ mObserver = new KeyguardMediaObserver(v);
+ // Control buttons
+ for (int i = 0; i < ACTION_IDS.length; i++) {
+ ImageButton button = v.findViewById(ACTION_IDS[i]);
+ if (button == null) {
+ continue;
+ }
+ final int index = i;
+ button.setOnClickListener(unused -> mViewModel.onActionClick(index));
+ }
+ mViewModel.getKeyguardMedia().observeForever(mObserver);
}
/** Unbinds media controls. */
public void unbindView() {
- if (mMediaNotifView == null) {
+ if (mObserver == null) {
throw new IllegalStateException("cannot unbind views, nothing bound");
}
- mMediaNotifView = null;
+ mViewModel.getKeyguardMedia().removeObserver(mObserver);
+ mObserver = null;
}
/** Clear the media controls because there isn't an active session. */
public void clearControls() {
- if (mMediaNotifView != null) {
- mMediaNotifView.setVisibility(View.GONE);
- }
+ mBackgroundExecutor.execute(mViewModel::clearControls);
}
/**
@@ -110,159 +121,244 @@ public class KeyguardMediaPlayer {
*/
public void updateControls(NotificationEntry entry, Icon appIcon,
MediaMetadata mediaMetadata) {
- if (mMediaNotifView == null) {
+ if (mObserver == null) {
throw new IllegalStateException("cannot update controls, views not bound");
}
if (mediaMetadata == null) {
- mMediaNotifView.setVisibility(View.GONE);
- Log.d(TAG, "media metadata was null");
+ Log.d(TAG, "media metadata was null, closing media controls");
+ // Note that clearControls() executes on the same background executor, so there
+ // shouldn't be an issue with an outdated update running after clear. However, if stale
+ // controls are observed then consider removing any enqueued updates.
+ clearControls();
return;
}
- mMediaNotifView.setVisibility(View.VISIBLE);
+ mBackgroundExecutor.execute(() -> mViewModel.updateControls(entry, appIcon, mediaMetadata));
+ }
- Notification notif = entry.getSbn().getNotification();
+ /** ViewModel for KeyguardMediaControls. */
+ private static final class KeyguardMediaViewModel {
- // Computed foreground and background color based on album art.
- int fgColor = notif.color;
- int bgColor = entry.getRow() == null ? -1 : entry.getRow().getCurrentBackgroundTint();
- Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
- if (artworkBitmap == null) {
- artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- }
- if (artworkBitmap != null) {
- // If we have art, get colors from that
- Palette p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
- .generate();
- Palette.Swatch swatch = MediaNotificationProcessor.findBackgroundSwatch(p);
- bgColor = swatch.getRgb();
- fgColor = MediaNotificationProcessor.selectForegroundColor(bgColor, p);
- }
- // Make sure colors will be legible
- boolean isDark = !ContrastColorUtil.isColorLight(bgColor);
- fgColor = ContrastColorUtil.resolveContrastColor(mContext, fgColor, bgColor,
- isDark);
- fgColor = ContrastColorUtil.ensureTextContrast(fgColor, bgColor, isDark);
-
- // Album art
- ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
- if (albumView != null) {
- // Resize art in a background thread
- final Bitmap bm = artworkBitmap;
- mBackgroundExecutor.execute(() -> processAlbumArt(bm, albumView));
+ private final Context mContext;
+ private final MutableLiveData<KeyguardMedia> mMedia = new MutableLiveData<>();
+ private final Object mActionsLock = new Object();
+ private List<PendingIntent> mActions;
+ private float mAlbumArtRadius;
+ private int mAlbumArtSize;
+
+ KeyguardMediaViewModel(Context context) {
+ mContext = context;
+ loadDimens();
}
- // App icon
- ImageView appIconView = mMediaNotifView.findViewById(R.id.icon);
- if (appIconView != null) {
- Drawable iconDrawable = appIcon.loadDrawable(mContext);
- iconDrawable.setTint(fgColor);
- appIconView.setImageDrawable(iconDrawable);
+ /** Close the media player because there isn't an active session. */
+ public void clearControls() {
+ synchronized (mActionsLock) {
+ mActions = null;
+ }
+ mMedia.postValue(null);
}
- // App name
- TextView appName = mMediaNotifView.findViewById(R.id.app_name);
- if (appName != null) {
+ /** Update the media player with information about the active session. */
+ public void updateControls(NotificationEntry entry, Icon appIcon,
+ MediaMetadata mediaMetadata) {
+
+ // Foreground and Background colors computed from album art
+ Notification notif = entry.getSbn().getNotification();
+ int fgColor = notif.color;
+ int bgColor = entry.getRow() == null ? -1 : entry.getRow().getCurrentBackgroundTint();
+ Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+ if (artworkBitmap == null) {
+ artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ }
+ if (artworkBitmap != null) {
+ // If we have art, get colors from that
+ Palette p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
+ .generate();
+ Palette.Swatch swatch = MediaNotificationProcessor.findBackgroundSwatch(p);
+ bgColor = swatch.getRgb();
+ fgColor = MediaNotificationProcessor.selectForegroundColor(bgColor, p);
+ }
+ // Make sure colors will be legible
+ boolean isDark = !ContrastColorUtil.isColorLight(bgColor);
+ fgColor = ContrastColorUtil.resolveContrastColor(mContext, fgColor, bgColor,
+ isDark);
+ fgColor = ContrastColorUtil.ensureTextContrast(fgColor, bgColor, isDark);
+
+ // Album art
+ RoundedBitmapDrawable artwork = null;
+ if (artworkBitmap != null) {
+ Bitmap original = artworkBitmap.copy(Bitmap.Config.ARGB_8888, true);
+ Bitmap scaled = Bitmap.createScaledBitmap(original, mAlbumArtSize, mAlbumArtSize,
+ false);
+ artwork = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
+ artwork.setCornerRadius(mAlbumArtRadius);
+ }
+
+ // App name
Notification.Builder builder = Notification.Builder.recoverBuilder(mContext, notif);
- String appNameString = builder.loadHeaderAppName();
- appName.setText(appNameString);
- appName.setTextColor(fgColor);
- }
+ String app = builder.loadHeaderAppName();
- // Song name
- TextView titleText = mMediaNotifView.findViewById(R.id.header_title);
- if (titleText != null) {
- String songName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
- titleText.setText(songName);
- titleText.setTextColor(fgColor);
- }
+ // App Icon
+ Drawable appIconDrawable = appIcon.loadDrawable(mContext);
- // Artist name
- TextView artistText = mMediaNotifView.findViewById(R.id.header_artist);
- if (artistText != null) {
- String artistName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- artistText.setText(artistName);
- artistText.setTextColor(fgColor);
- }
+ // Song name
+ String song = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
- // Background color
- if (mMediaNotifView instanceof MediaHeaderView) {
- MediaHeaderView head = (MediaHeaderView) mMediaNotifView;
- head.setBackgroundColor(bgColor);
- }
+ // Artist name
+ String artist = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- // Control buttons
- final List<Icon> icons = new ArrayList<>();
- final List<PendingIntent> intents = new ArrayList<>();
- Notification.Action[] actions = notif.actions;
- final int[] actionsToShow = notif.extras.getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
+ // Control buttons
+ List<Drawable> actionIcons = new ArrayList<>();
+ final List<PendingIntent> intents = new ArrayList<>();
+ Notification.Action[] actions = notif.actions;
+ final int[] actionsToShow = notif.extras.getIntArray(
+ Notification.EXTRA_COMPACT_ACTIONS);
- for (int i = 0; i < ACTION_IDS.length; i++) {
- if (actionsToShow != null && actions != null && i < actionsToShow.length
- && actionsToShow[i] < actions.length) {
- final int idx = actionsToShow[i];
- icons.add(actions[idx].getIcon());
- intents.add(actions[idx].actionIntent);
- } else {
- icons.add(null);
- intents.add(null);
+ Context packageContext = entry.getSbn().getPackageContext(mContext);
+ for (int i = 0; i < ACTION_IDS.length; i++) {
+ if (actionsToShow != null && actions != null && i < actionsToShow.length
+ && actionsToShow[i] < actions.length) {
+ final int idx = actionsToShow[i];
+ actionIcons.add(actions[idx].getIcon().loadDrawable(packageContext));
+ intents.add(actions[idx].actionIntent);
+ } else {
+ actionIcons.add(null);
+ intents.add(null);
+ }
}
+ synchronized (mActionsLock) {
+ mActions = intents;
+ }
+
+ KeyguardMedia data = new KeyguardMedia(fgColor, bgColor, app, appIconDrawable, artist,
+ song, artwork, actionIcons);
+ mMedia.postValue(data);
}
- Context packageContext = entry.getSbn().getPackageContext(mContext);
- for (int i = 0; i < ACTION_IDS.length; i++) {
- ImageButton button = mMediaNotifView.findViewById(ACTION_IDS[i]);
- if (button == null) {
- continue;
+ /** Gets state for the lock screen media controls. */
+ public LiveData<KeyguardMedia> getKeyguardMedia() {
+ return mMedia;
+ }
+
+ /**
+ * Handle user clicks on media control buttons (actions).
+ *
+ * @param index position of the button that was clicked.
+ */
+ public void onActionClick(int index) {
+ PendingIntent intent = null;
+ // This might block the ui thread to wait for the lock. Currently, however, the
+ // lock is held by the bg thread to assign a member, which should be fast. An
+ // alternative could be to add the intents to the state and let the observer set
+ // the onClick listeners.
+ synchronized (mActionsLock) {
+ if (mActions != null && index < mActions.size()) {
+ intent = mActions.get(index);
+ }
}
- Icon icon = icons.get(i);
- if (icon == null) {
- button.setVisibility(View.GONE);
- } else {
- button.setVisibility(View.VISIBLE);
- button.setImageDrawable(icon.loadDrawable(packageContext));
- button.setImageTintList(ColorStateList.valueOf(fgColor));
- final PendingIntent intent = intents.get(i);
- if (intent != null) {
- button.setOnClickListener(v -> {
- try {
- intent.send();
- } catch (PendingIntent.CanceledException e) {
- Log.d(TAG, "failed to send action intent", e);
- }
- });
+ if (intent != null) {
+ try {
+ intent.send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.d(TAG, "failed to send action intent", e);
}
}
}
+
+ void loadDimens() {
+ mAlbumArtRadius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
+ mAlbumArtSize = (int) mContext.getResources().getDimension(
+ R.dimen.qs_media_album_size);
+ }
}
- /**
- * Process album art for layout
- * @param albumArt bitmap to use for album art
- * @param albumView view to hold the album art
- */
- private void processAlbumArt(Bitmap albumArt, ImageView albumView) {
- RoundedBitmapDrawable roundedDrawable = null;
- if (albumArt != null) {
- Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
- Bitmap scaled = Bitmap.createScaledBitmap(original, mAlbumArtSize, mAlbumArtSize,
- false);
- roundedDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
- roundedDrawable.setCornerRadius(mAlbumArtRadius);
- } else {
- Log.e(TAG, "No album art available");
+ /** Observer for state changes of lock screen media controls. */
+ private static final class KeyguardMediaObserver implements Observer<KeyguardMedia> {
+
+ private final View mRootView;
+ private final MediaHeaderView mMediaHeaderView;
+ private final ImageView mAlbumView;
+ private final ImageView mAppIconView;
+ private final TextView mAppNameView;
+ private final TextView mTitleView;
+ private final TextView mArtistView;
+ private final List<ImageButton> mButtonViews = new ArrayList<>();
+
+ KeyguardMediaObserver(View v) {
+ mRootView = v;
+ mMediaHeaderView = v instanceof MediaHeaderView ? (MediaHeaderView) v : null;
+ mAlbumView = v.findViewById(R.id.album_art);
+ mAppIconView = v.findViewById(R.id.icon);
+ mAppNameView = v.findViewById(R.id.app_name);
+ mTitleView = v.findViewById(R.id.header_title);
+ mArtistView = v.findViewById(R.id.header_artist);
+ for (int i = 0; i < ACTION_IDS.length; i++) {
+ mButtonViews.add(v.findViewById(ACTION_IDS[i]));
+ }
}
- // Now that it's resized, update the UI
- final RoundedBitmapDrawable result = roundedDrawable;
- albumView.post(() -> {
- albumView.setImageDrawable(result);
- albumView.setVisibility(result == null ? View.GONE : View.VISIBLE);
- });
- }
+ /** Updates lock screen media player views when state changes. */
+ @Override
+ public void onChanged(KeyguardMedia data) {
+ if (data == null) {
+ mRootView.setVisibility(View.GONE);
+ return;
+ }
+ mRootView.setVisibility(View.VISIBLE);
- private void loadDimens() {
- mAlbumArtRadius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
- mAlbumArtSize = (int) mContext.getResources().getDimension(
- R.dimen.qs_media_album_size);
+ // Background color
+ if (mMediaHeaderView != null) {
+ mMediaHeaderView.setBackgroundColor(data.getBackgroundColor());
+ }
+
+ // Album art
+ if (mAlbumView != null) {
+ mAlbumView.setImageDrawable(data.getArtwork());
+ mAlbumView.setVisibility(data.getArtwork() == null ? View.GONE : View.VISIBLE);
+ }
+
+ // App icon
+ if (mAppIconView != null) {
+ Drawable iconDrawable = data.getAppIcon();
+ iconDrawable.setTint(data.getForegroundColor());
+ mAppIconView.setImageDrawable(iconDrawable);
+ }
+
+ // App name
+ if (mAppNameView != null) {
+ String appNameString = data.getApp();
+ mAppNameView.setText(appNameString);
+ mAppNameView.setTextColor(data.getForegroundColor());
+ }
+
+ // Song name
+ if (mTitleView != null) {
+ mTitleView.setText(data.getSong());
+ mTitleView.setTextColor(data.getForegroundColor());
+ }
+
+ // Artist name
+ if (mArtistView != null) {
+ mArtistView.setText(data.getArtist());
+ mArtistView.setTextColor(data.getForegroundColor());
+ }
+
+ // Control buttons
+ for (int i = 0; i < ACTION_IDS.length; i++) {
+ ImageButton button = mButtonViews.get(i);
+ if (button == null) {
+ continue;
+ }
+ Drawable icon = data.getActionIcons().get(i);
+ if (icon == null) {
+ button.setVisibility(View.GONE);
+ button.setImageDrawable(null);
+ } else {
+ button.setVisibility(View.VISIBLE);
+ button.setImageDrawable(icon);
+ button.setImageTintList(ColorStateList.valueOf(data.getForegroundColor()));
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 31f90c6a8648..01c2faa62403 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -74,6 +74,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder;
@@ -174,6 +175,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private IStatusBarService mBarService;
+ private SysUiState mSysUiState;
// Used for determining view rect for touch interaction
private Rect mTempRect = new Rect();
@@ -290,11 +292,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
DumpManager dumpManager,
- FloatingContentCoordinator floatingContentCoordinator) {
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState) {
this(context, notificationShadeWindowController, statusBarStateController, shadeController,
data, null /* synchronizer */, configurationController, interruptionStateProvider,
zenModeController, notifUserManager, groupManager, entryManager,
- notifPipeline, featureFlags, dumpManager, floatingContentCoordinator);
+ notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState);
}
/**
@@ -315,7 +318,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
DumpManager dumpManager,
- FloatingContentCoordinator floatingContentCoordinator) {
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState) {
dumpManager.registerDumpable(TAG, this);
mContext = context;
mShadeController = shadeController;
@@ -340,6 +344,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
});
configurationController.addCallback(this /* configurationListener */);
+ mSysUiState = sysUiState;
mBubbleData = data;
mBubbleData.setListener(mBubbleDataListener);
@@ -593,7 +598,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private void ensureStackViewCreated() {
if (mStackView == null) {
mStackView = new BubbleStackView(
- mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator);
+ mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
+ mSysUiState);
ViewGroup nsv = mNotificationShadeWindowController.getNotificationShadeView();
int bubbleScrimIndex = nsv.indexOfChild(nsv.findViewById(R.id.scrim_for_bubble));
int stackIndex = bubbleScrimIndex + 1; // Show stack above bubble scrim.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 8bc35f4058e9..2bd15188b7d3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -208,7 +208,7 @@ public class BubbleData {
b -> {
notificationEntryUpdated(bubble, /* suppressFlyout */
false, /* showInShade */ true);
- setSelectedBubbleInternal(bubble);
+ setSelectedBubble(bubble);
},
mContext, stack, factory);
dispatchPendingChanges();
@@ -761,6 +761,17 @@ public class BubbleData {
}
@VisibleForTesting(visibility = PRIVATE)
+ Bubble getOverflowBubbleWithKey(String key) {
+ for (int i = 0; i < mOverflowBubbles.size(); i++) {
+ Bubble bubble = mOverflowBubbles.get(i);
+ if (bubble.getKey().equals(key)) {
+ return bubble;
+ }
+ }
+ return null;
+ }
+
+ @VisibleForTesting(visibility = PRIVATE)
void setTimeSource(TimeSource timeSource) {
mTimeSource = timeSource;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 541c8cf19943..7191a203ea8c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -80,6 +80,8 @@ import com.android.systemui.R;
import com.android.systemui.bubbles.animation.ExpandedAnimationController;
import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
import com.android.systemui.bubbles.animation.StackAnimationController;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.util.DismissCircleView;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -241,6 +243,7 @@ public class BubbleStackView extends FrameLayout {
private BubbleTouchHandler mTouchHandler;
private BubbleController.BubbleExpandListener mExpandListener;
+ private SysUiState mSysUiState;
private boolean mViewUpdatedRequested = false;
private boolean mIsExpansionAnimating = false;
@@ -437,7 +440,8 @@ public class BubbleStackView extends FrameLayout {
public BubbleStackView(Context context, BubbleData data,
@Nullable SurfaceSynchronizer synchronizer,
- FloatingContentCoordinator floatingContentCoordinator) {
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState) {
super(context);
mBubbleData = data;
@@ -445,6 +449,8 @@ public class BubbleStackView extends FrameLayout {
mTouchHandler = new BubbleTouchHandler(this, data, context);
setOnTouchListener(mTouchHandler);
+ mSysUiState = sysUiState;
+
Resources res = getResources();
mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
@@ -1055,6 +1061,11 @@ public class BubbleStackView extends FrameLayout {
if (shouldExpand == mIsExpanded) {
return;
}
+
+ mSysUiState
+ .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
+ .commitUpdate(mContext.getDisplayId());
+
if (mIsExpanded) {
animateCollapse();
logBubbleEvent(mExpandedBubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 27c9e9895324..e84e932c9e61 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -21,6 +21,7 @@ import android.content.Context;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubbleData;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -62,7 +63,8 @@ public interface BubbleModule {
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
DumpManager dumpManager,
- FloatingContentCoordinator floatingContentCoordinator) {
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState) {
return new BubbleController(
context,
notificationShadeWindowController,
@@ -79,6 +81,7 @@ public interface BubbleModule {
notifPipeline,
featureFlags,
dumpManager,
- floatingContentCoordinator);
+ floatingContentCoordinator,
+ sysUiState);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 2cc3d9e22a7d..96494cfe640f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -305,7 +305,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
oldInstance.onDestroy();
}
mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
- mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+ mPendingIntent = PendingIntent.getActivity(getContext(), 0,
+ new Intent(getContext(), KeyguardSliceProvider.class), 0);
mMediaManager.addCallback(this);
mStatusBarStateController.addCallback(this);
mNextAlarmController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 1a01cfedb82e..0b076559ae36 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -99,14 +99,14 @@ public class PipResizeGestureHandler {
mEnablePipResize = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
PIP_USER_RESIZE,
- /* defaultValue = */ false);
+ /* defaultValue = */ true);
deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor,
new DeviceConfig.OnPropertiesChangedListener() {
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
if (properties.getKeyset().contains(PIP_USER_RESIZE)) {
mEnablePipResize = properties.getBoolean(
- PIP_USER_RESIZE, /* defaultValue = */ false);
+ PIP_USER_RESIZE, /* defaultValue = */ true);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5ccf8c7e9212..33cc086a8d9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -133,6 +133,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
new LocalMediaManager.DeviceCallback() {
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
+ if (mLocalMediaManager == null) {
+ return;
+ }
MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
// Check because this can be called several times while changing devices
if (mDevice == null || !mDevice.equals(currentDevice)) {
@@ -293,14 +296,17 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mMediaPlayers.size() > 0) {
((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
- // Set up listener for device changes
- // TODO: integrate with MediaTransferManager?
- InfoMediaManager imm =
- new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
- mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm, null);
- mLocalMediaManager.startScan();
- mDevice = mLocalMediaManager.getCurrentConnectedDevice();
- mLocalMediaManager.registerCallback(mDeviceCallback);
+ if (mLocalMediaManager == null) {
+ // Set up listener for device changes
+ // TODO: integrate with MediaTransferManager?
+ InfoMediaManager imm =
+ new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
+ mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm,
+ null);
+ mLocalMediaManager.startScan();
+ mDevice = mLocalMediaManager.getCurrentConnectedDevice();
+ mLocalMediaManager.registerCallback(mDeviceCallback);
+ }
}
}
@@ -323,8 +329,11 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mMediaCarousel.removeView(player.getView());
if (mMediaPlayers.size() == 0) {
((View) mMediaCarousel.getParent()).setVisibility(View.GONE);
- mLocalMediaManager.stopScan();
- mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ if (mLocalMediaManager != null) {
+ mLocalMediaManager.stopScan();
+ mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ mLocalMediaManager = null;
+ }
}
return true;
}
@@ -397,6 +406,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mLocalMediaManager != null) {
mLocalMediaManager.stopScan();
mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ mLocalMediaManager = null;
}
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
new file mode 100644
index 000000000000..261ae079a2c8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import android.content.pm.UserInfo;
+import android.util.SparseArray;
+
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import javax.inject.Inject;
+
+/**
+ * A coordinator that filters out notifications for other users
+ *
+ * The NotifCollection contains the notifs for ALL users, so we need to remove any notifications
+ * that have been posted specifically to other users. Note that some system notifications are not
+ * posted to any particular user, and so must be shown to everyone.
+ *
+ * TODO: The NotificationLockscreenUserManager currently maintains the list of active user profiles.
+ * We should spin that off into a standalone section at some point.
+ */
+public class HideNotifsForOtherUsersCoordinator implements Coordinator {
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+
+ @Inject
+ public HideNotifsForOtherUsersCoordinator(
+ NotificationLockscreenUserManager lockscreenUserManager) {
+ mLockscreenUserManager = lockscreenUserManager;
+ }
+
+ @Override
+ public void attach(NotifPipeline pipeline) {
+ pipeline.addPreGroupFilter(mFilter);
+ mLockscreenUserManager.addUserChangedListener(mUserChangedListener);
+ }
+
+ private final NotifFilter mFilter = new NotifFilter("NotCurrentUserFilter") {
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ return !mLockscreenUserManager
+ .isCurrentProfile(entry.getSbn().getUser().getIdentifier());
+ }
+ };
+
+ private final UserChangedListener mUserChangedListener = new UserChangedListener() {
+ @Override
+ public void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {
+ mFilter.invalidateList();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index aaf71f58cb5c..b7738569ad3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -95,11 +95,6 @@ public class KeyguardCoordinator implements Coordinator {
public boolean shouldFilterOut(NotificationEntry entry, long now) {
final StatusBarNotification sbn = entry.getSbn();
- // FILTER OUT the notification when the notification isn't for the current profile
- if (!mLockscreenUserManager.isCurrentProfile(sbn.getUserId())) {
- return true;
- }
-
// FILTER OUT the notification when the keyguard is showing and...
if (mKeyguardStateController.isShowing()) {
// ... user settings or the device policy manager doesn't allow lockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 98104f84f30e..03c0ae6fde50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -49,15 +49,17 @@ public class NotifCoordinators implements Dumpable {
public NotifCoordinators(
DumpManager dumpManager,
FeatureFlags featureFlags,
- HeadsUpCoordinator headsUpCoordinator,
+ HideNotifsForOtherUsersCoordinator hideNotifsForOtherUsersCoordinator,
KeyguardCoordinator keyguardCoordinator,
RankingCoordinator rankingCoordinator,
ForegroundCoordinator foregroundCoordinator,
DeviceProvisionedCoordinator deviceProvisionedCoordinator,
BubbleCoordinator bubbleCoordinator,
+ HeadsUpCoordinator headsUpCoordinator,
PreparationCoordinator preparationCoordinator) {
dumpManager.registerDumpable(TAG, this);
mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
+ mCoordinators.add(hideNotifsForOtherUsersCoordinator);
mCoordinators.add(keyguardCoordinator);
mCoordinators.add(rankingCoordinator);
mCoordinators.add(foregroundCoordinator);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index cf9d43eeff73..d70484e9cf41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
import android.annotation.IntDef;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -30,241 +28,98 @@ import android.os.Trace;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.ViewTreeObserver;
-import android.view.accessibility.AccessibilityNodeInfo;
+import android.util.SparseArray;
+import android.view.ViewTreeObserver.OnPreDrawListener;
import com.android.internal.graphics.ColorUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.KeyguardAffordanceView;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
-import com.android.systemui.statusbar.policy.AccessibilityController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import javax.inject.Inject;
-import javax.inject.Named;
-
/**
* Manages the different states and animations of the unlock icon.
*/
-public class LockIcon extends KeyguardAffordanceView implements
- ViewTreeObserver.OnPreDrawListener {
-
- private static final int STATE_LOCKED = 0;
- private static final int STATE_LOCK_OPEN = 1;
- private static final int STATE_SCANNING_FACE = 2;
- private static final int STATE_BIOMETRICS_ERROR = 3;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final AccessibilityController mAccessibilityController;
- private final KeyguardStateController mKeyguardStateController;
- private final KeyguardBypassController mBypassController;
- private final NotificationWakeUpCoordinator mWakeUpCoordinator;
- private final HeadsUpManagerPhone mHeadsUpManager;
-
- private int mLastState = 0;
- private boolean mForceUpdate;
- private boolean mTransientBiometricsError;
- private boolean mIsFaceUnlockState;
- private boolean mSimLocked;
- private int mDensity;
+public class LockIcon extends KeyguardAffordanceView {
+
+ static final int STATE_LOCKED = 0;
+ static final int STATE_LOCK_OPEN = 1;
+ static final int STATE_SCANNING_FACE = 2;
+ static final int STATE_BIOMETRICS_ERROR = 3;
+ private float mDozeAmount;
+ private int mIconColor;
+ private StateProvider mStateProvider;
+ private int mOldState;
private boolean mPulsing;
private boolean mDozing;
- private boolean mDocked;
- private boolean mBlockUpdates;
- private int mIconColor;
- private float mDozeAmount;
- private boolean mBouncerShowingScrimmed;
- private boolean mWakeAndUnlockRunning;
- private boolean mKeyguardShowing;
- private boolean mShowingLaunchAffordance;
private boolean mKeyguardJustShown;
- private boolean mUpdatePending;
- private boolean mBouncerPreHideAnimation;
- private int mStatusBarState = StatusBarState.SHADE;
-
- private final KeyguardStateController.Callback mKeyguardMonitorCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- boolean force = false;
- boolean wasShowing = mKeyguardShowing;
- mKeyguardShowing = mKeyguardStateController.isShowing();
- if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
- mBlockUpdates = false;
- force = true;
- }
- if (!wasShowing && mKeyguardShowing) {
- mKeyguardJustShown = true;
- }
- update(force);
- }
-
- @Override
- public void onKeyguardFadingAwayChanged() {
- if (!mKeyguardStateController.isKeyguardFadingAway()) {
- mBouncerPreHideAnimation = false;
- if (mBlockUpdates) {
- mBlockUpdates = false;
- update(true /* force */);
- }
- }
- }
-
- @Override
- public void onUnlockedChanged() {
- update();
- }
- };
-
- @Inject
- public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- AccessibilityController accessibilityController,
- KeyguardBypassController bypassController,
- NotificationWakeUpCoordinator wakeUpCoordinator,
- KeyguardStateController keyguardStateController,
- HeadsUpManagerPhone headsUpManager) {
- super(context, attrs);
- mContext = context;
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
- mAccessibilityController = accessibilityController;
- mBypassController = bypassController;
- mWakeUpCoordinator = wakeUpCoordinator;
- mKeyguardStateController = keyguardStateController;
- mHeadsUpManager = headsUpManager;
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
- mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
- update();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
- }
+ private final SparseArray<Drawable> mDrawableCache = new SparseArray<>();
- /**
- * If we're currently presenting an authentication error message.
- */
- public void setTransientBiometricsError(boolean transientBiometricsError) {
- mTransientBiometricsError = transientBiometricsError;
- update();
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- final int density = newConfig.densityDpi;
- if (density != mDensity) {
- mDensity = density;
- update();
- }
- }
-
- public void update() {
- update(false /* force */);
- }
-
- public void update(boolean force) {
- if (force) {
- mForceUpdate = true;
- }
- if (!mUpdatePending) {
- mUpdatePending = true;
- getViewTreeObserver().addOnPreDrawListener(this);
- }
- }
+ private final OnPreDrawListener mOnPreDrawListener = new OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
- @Override
- public boolean onPreDraw() {
- mUpdatePending = false;
- getViewTreeObserver().removeOnPreDrawListener(this);
-
- int state = getState();
- int lastState = mLastState;
- boolean keyguardJustShown = mKeyguardJustShown;
- mIsFaceUnlockState = state == STATE_SCANNING_FACE;
- mLastState = state;
- mKeyguardJustShown = false;
-
- boolean shouldUpdate = lastState != state || mForceUpdate;
- if (mBlockUpdates && canBlockUpdates()) {
- shouldUpdate = false;
- }
- if (shouldUpdate) {
- mForceUpdate = false;
- @LockAnimIndex final int lockAnimIndex = getAnimationIndexForTransition(lastState,
- state, mPulsing, mDozing, keyguardJustShown);
- boolean isAnim = lockAnimIndex != -1;
- int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(state);
-
- Drawable icon = mContext.getDrawable(iconRes);
- final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
- ? (AnimatedVectorDrawable) icon
- : null;
+ int newState = mStateProvider.getState();
+ Drawable icon = getIcon(newState);
setImageDrawable(icon, false);
- if (mIsFaceUnlockState) {
- announceForAccessibility(getContext().getString(
+
+ if (newState == STATE_SCANNING_FACE) {
+ announceForAccessibility(getResources().getString(
R.string.accessibility_scanning_face));
}
- if (animation != null && isAnim) {
+ if (icon instanceof AnimatedVectorDrawable) {
+ final AnimatedVectorDrawable animation = (AnimatedVectorDrawable) icon;
animation.forceAnimationOnUI();
animation.clearAnimationCallbacks();
- animation.registerAnimationCallback(new Animatable2.AnimationCallback() {
- @Override
- public void onAnimationEnd(Drawable drawable) {
- if (getDrawable() == animation && state == getState()
- && doesAnimationLoop(lockAnimIndex)) {
- animation.start();
- } else {
- Trace.endAsyncSection("LockIcon#Animation", state);
- }
- }
- });
- Trace.beginAsyncSection("LockIcon#Animation", state);
+ animation.registerAnimationCallback(
+ new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ if (getDrawable() == animation
+ && newState == mStateProvider.getState()
+ && newState == STATE_SCANNING_FACE) {
+ animation.start();
+ } else {
+ Trace.endAsyncSection("LockIcon#Animation", newState);
+ }
+ }
+ });
+ Trace.beginAsyncSection("LockIcon#Animation", newState);
animation.start();
}
+
+ return true;
}
- updateDarkTint();
+ };
- updateIconVisibility();
- updateClickability();
+ public LockIcon(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- return true;
+ void setStateProvider(StateProvider stateProvider) {
+ mStateProvider = stateProvider;
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mDrawableCache.clear();
}
/**
* Update the icon visibility
* @return true if the visibility changed
*/
- boolean updateIconVisibility() {
- boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
- boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
- || mShowingLaunchAffordance;
- if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
- if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp()
- || mStatusBarState == StatusBarState.KEYGUARD)
- && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
- invisible = true;
- }
- }
- boolean wasInvisible = getVisibility() == INVISIBLE;
- if (invisible != wasInvisible) {
- setVisibility(invisible ? INVISIBLE : VISIBLE);
+ boolean updateIconVisibility(boolean visible) {
+ boolean wasVisible = getVisibility() == VISIBLE;
+ if (visible != wasVisible) {
+ setVisibility(visible ? VISIBLE : INVISIBLE);
animate().cancel();
- if (!invisible) {
+ if (visible) {
setScaleX(0);
setScaleY(0);
animate()
@@ -280,49 +135,47 @@ public class LockIcon extends KeyguardAffordanceView implements
return false;
}
- private boolean canBlockUpdates() {
- return mKeyguardShowing || mKeyguardStateController.isKeyguardFadingAway();
+ void update(int oldState, boolean pulsing, boolean dozing, boolean keyguardJustShown) {
+ mOldState = oldState;
+ mPulsing = pulsing;
+ mDozing = dozing;
+ mKeyguardJustShown = keyguardJustShown;
+
+ getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
}
- private void updateClickability() {
- if (mAccessibilityController == null) {
- return;
- }
- boolean canLock = mKeyguardStateController.isMethodSecure()
- && mKeyguardStateController.canDismissLockScreen();
- boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
- setClickable(clickToUnlock);
- setLongClickable(canLock && !clickToUnlock);
- setFocusable(mAccessibilityController.isAccessibilityEnabled());
+ void setDozeAmount(float dozeAmount) {
+ mDozeAmount = dozeAmount;
+ updateDarkTint();
}
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- boolean fingerprintRunning = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
- // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
- // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
- // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
- // check of whether non-strong biometric is allowed
- boolean unlockingAllowed = mKeyguardUpdateMonitor
- .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
- if (fingerprintRunning && unlockingAllowed) {
- AccessibilityNodeInfo.AccessibilityAction unlock
- = new AccessibilityNodeInfo.AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLICK,
- getContext().getString(R.string.accessibility_unlock_without_fingerprint));
- info.addAction(unlock);
- info.setHintText(getContext().getString(
- R.string.accessibility_waiting_for_fingerprint));
- } else if (mIsFaceUnlockState) {
- //Avoid 'button' to be spoken for scanning face
- info.setClassName(LockIcon.class.getName());
- info.setContentDescription(getContext().getString(
- R.string.accessibility_scanning_face));
+ void onThemeChange(int iconColor) {
+ mDrawableCache.clear();
+ mIconColor = iconColor;
+ updateDarkTint();
+ }
+
+ private void updateDarkTint() {
+ int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount);
+ setImageTintList(ColorStateList.valueOf(color));
+ }
+
+ private Drawable getIcon(int newState) {
+ @LockAnimIndex final int lockAnimIndex =
+ getAnimationIndexForTransition(mOldState, newState, mPulsing, mDozing,
+ mKeyguardJustShown);
+
+ boolean isAnim = lockAnimIndex != -1;
+ int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(newState);
+
+ if (!mDrawableCache.contains(iconRes)) {
+ mDrawableCache.put(iconRes, getResources().getDrawable(iconRes));
}
+
+ return mDrawableCache.get(iconRes);
}
- private int getIconForState(int state) {
+ static int getIconForState(int state) {
int iconRes;
switch (state) {
case STATE_LOCKED:
@@ -343,11 +196,7 @@ public class LockIcon extends KeyguardAffordanceView implements
return iconRes;
}
- private boolean doesAnimationLoop(@LockAnimIndex int lockAnimIndex) {
- return lockAnimIndex == SCANNING;
- }
-
- private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
+ static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
boolean dozing, boolean keyguardJustShown) {
// Never animate when screen is off
@@ -367,42 +216,10 @@ public class LockIcon extends KeyguardAffordanceView implements
return -1;
}
- public void setBouncerShowingScrimmed(boolean bouncerShowing) {
- mBouncerShowingScrimmed = bouncerShowing;
- if (mBypassController.getBypassEnabled()) {
- update();
- }
- }
-
- /**
- * Animate padlock opening when bouncer challenge is solved.
- */
- public void onBouncerPreHideAnimation() {
- mBouncerPreHideAnimation = true;
- update();
- }
-
- void setIconColor(int iconColor) {
- mIconColor = iconColor;
- updateDarkTint();
- }
-
- void setSimLocked(boolean simLocked) {
- mSimLocked = simLocked;
- }
-
- /** Set if the device is docked. */
- public void setDocked(boolean docked) {
- if (mDocked != docked) {
- mDocked = docked;
- update();
- }
- }
-
@Retention(RetentionPolicy.SOURCE)
@IntDef({ERROR, UNLOCK, LOCK, SCANNING})
@interface LockAnimIndex {}
- private static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
+ static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
private static final int[][] LOCK_ANIM_RES_IDS = new int[][] {
{
R.anim.lock_to_error,
@@ -433,7 +250,7 @@ public class LockIcon extends KeyguardAffordanceView implements
private int getThemedAnimationResId(@LockAnimIndex int lockAnimIndex) {
final String setting = TextUtils.emptyIfNull(
Settings.Secure.getString(getContext().getContentResolver(),
- Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
+ Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
if (setting.contains("com.android.theme.icon_pack.circular.android")) {
return LOCK_ANIM_RES_IDS[1][lockAnimIndex];
} else if (setting.contains("com.android.theme.icon_pack.filled.android")) {
@@ -444,83 +261,8 @@ public class LockIcon extends KeyguardAffordanceView implements
return LOCK_ANIM_RES_IDS[0][lockAnimIndex];
}
- private int getState() {
- KeyguardUpdateMonitor updateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
- if ((mKeyguardStateController.canDismissLockScreen() || !mKeyguardShowing
- || mKeyguardStateController.isKeyguardGoingAway()) && !mSimLocked) {
- return STATE_LOCK_OPEN;
- } else if (mTransientBiometricsError) {
- return STATE_BIOMETRICS_ERROR;
- } else if (updateMonitor.isFaceDetectionRunning() && !mPulsing) {
- return STATE_SCANNING_FACE;
- } else {
- return STATE_LOCKED;
- }
- }
-
- /**
- * When keyguard is in pulsing (AOD2) state.
- * @param pulsing {@code true} when pulsing.
- */
- public void setPulsing(boolean pulsing) {
- mPulsing = pulsing;
- update();
+ interface StateProvider {
+ int getState();
}
- private void updateDarkTint() {
- int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount);
- setImageTintList(ColorStateList.valueOf(color));
- }
-
- /**
- * We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
- * icon on top of the black front scrim.
- * @param wakeAndUnlock are we wake and unlocking
- * @param isUnlock are we currently unlocking
- */
- public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
- if (wakeAndUnlock) {
- mWakeAndUnlockRunning = true;
- }
- if (isUnlock && mBypassController.getBypassEnabled() && canBlockUpdates()) {
- // We don't want the icon to change while we are unlocking
- mBlockUpdates = true;
- }
- update();
- }
-
- /**
- * When we're launching an affordance, like double pressing power to open camera.
- */
- public void onShowingLaunchAffordanceChanged(boolean showing) {
- mShowingLaunchAffordance = showing;
- update();
- }
-
- /**
- * Called whenever the scrims become opaque, transparent or semi-transparent.
- */
- public void onScrimVisibilityChanged(@ScrimVisibility int scrimsVisible) {
- if (mWakeAndUnlockRunning
- && scrimsVisible == ScrimController.TRANSPARENT) {
- mWakeAndUnlockRunning = false;
- update();
- }
- }
-
- void setDozing(boolean dozing) {
- mDozing = dozing;
- update();
- }
-
- void setDozeAmount(float dozeAmount) {
- mDozeAmount = dozeAmount;
- updateDarkTint();
- }
-
- /** Set the StatusBarState. */
- public void setStatusBarState(int statusBarState) {
- mStatusBarState = statusBarState;
- updateIconVisibility();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 2b1a8a472d9e..f7c861b84a68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -16,11 +16,19 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_BIOMETRICS_ERROR;
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCKED;
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCK_OPEN;
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_SCANNING_FACE;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.hardware.biometrics.BiometricSourceType;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.Nullable;
@@ -29,15 +37,18 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.util.Optional;
@@ -59,6 +70,21 @@ public class LockscreenLockIconController {
private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
private final KeyguardBypassController mKeyguardBypassController;
private final Optional<DockManager> mDockManager;
+ private final KeyguardStateController mKeyguardStateController;
+ private final Resources mResources;
+ private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+ private boolean mKeyguardShowing;
+ private boolean mKeyguardJustShown;
+ private boolean mBlockUpdates;
+ private boolean mPulsing;
+ private boolean mDozing;
+ private boolean mSimLocked;
+ private boolean mTransientBiometricsError;
+ private boolean mDocked;
+ private boolean mWakeAndUnlockRunning;
+ private boolean mShowingLaunchAffordance;
+ private boolean mBouncerShowingScrimmed;
+ private int mStatusBarState = StatusBarState.SHADE;
private LockIcon mLockIcon;
private View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -69,10 +95,13 @@ public class LockscreenLockIconController {
mConfigurationController.addCallback(mConfigurationListener);
mNotificationWakeUpCoordinator.addListener(mWakeUpListener);
mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+ mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
mDockManager.ifPresent(dockManager -> dockManager.addListener(mDockEventListener));
+ mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
mConfigurationListener.onThemeChanged();
+ update();
}
@Override
@@ -81,7 +110,7 @@ public class LockscreenLockIconController {
mConfigurationController.removeCallback(mConfigurationListener);
mNotificationWakeUpCoordinator.removeListener(mWakeUpListener);
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
-
+ mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
mDockManager.ifPresent(dockManager -> dockManager.removeListener(mDockEventListener));
}
@@ -91,32 +120,44 @@ public class LockscreenLockIconController {
new StatusBarStateController.StateListener() {
@Override
public void onDozingChanged(boolean isDozing) {
- mLockIcon.setDozing(isDozing);
+ setDozing(isDozing);
}
@Override
public void onDozeAmountChanged(float linear, float eased) {
- mLockIcon.setDozeAmount(eased);
+ if (mLockIcon != null) {
+ mLockIcon.setDozeAmount(eased);
+ }
}
@Override
public void onStateChanged(int newState) {
- mLockIcon.setStatusBarState(newState);
+ setStatusBarState(newState);
}
};
private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+ private int mDensity;
+
@Override
public void onThemeChanged() {
+ if (mLockIcon == null) {
+ return;
+ }
+
TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
null, new int[]{ R.attr.wallpaperTextColor }, 0, 0);
int iconColor = typedArray.getColor(0, Color.WHITE);
typedArray.recycle();
- mLockIcon.setIconColor(iconColor);
+ mLockIcon.onThemeChange(iconColor);
}
@Override
public void onDensityOrFontScaleChanged() {
+ if (mLockIcon == null) {
+ return;
+ }
+
ViewGroup.LayoutParams lp = mLockIcon.getLayoutParams();
if (lp == null) {
return;
@@ -125,24 +166,41 @@ public class LockscreenLockIconController {
lp.height = mLockIcon.getResources().getDimensionPixelSize(
R.dimen.keyguard_lock_height);
mLockIcon.setLayoutParams(lp);
- mLockIcon.update(true /* force */);
+ update(true /* force */);
}
@Override
public void onLocaleListChanged() {
+ if (mLockIcon == null) {
+ return;
+ }
+
mLockIcon.setContentDescription(
mLockIcon.getResources().getText(R.string.accessibility_unlock_button));
- mLockIcon.update(true /* force */);
+ update(true /* force */);
+ }
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ final int density = newConfig.densityDpi;
+ if (density != mDensity) {
+ mDensity = density;
+ update();
+ }
}
};
private final WakeUpListener mWakeUpListener = new WakeUpListener() {
@Override
+ public void onPulseExpansionChanged(boolean expandingChanged) {
+ }
+
+ @Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
if (mKeyguardBypassController.getBypassEnabled()) {
- boolean changed = mLockIcon.updateIconVisibility();
+ boolean changed = updateIconVisibility();
if (changed) {
- mLockIcon.update();
+ update();
}
}
}
@@ -152,30 +210,103 @@ public class LockscreenLockIconController {
new KeyguardUpdateMonitorCallback() {
@Override
public void onSimStateChanged(int subId, int slotId, int simState) {
- mLockIcon.setSimLocked(mKeyguardUpdateMonitor.isSimPinSecure());
- mLockIcon.update();
+ mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
+ update();
}
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
- mLockIcon.update();
+ update();
}
@Override
public void onBiometricRunningStateChanged(boolean running,
BiometricSourceType biometricSourceType) {
- mLockIcon.update();
+ update();
}
@Override
public void onStrongAuthStateChanged(int userId) {
- mLockIcon.update();
+ update();
}
};
private final DockManager.DockEventListener mDockEventListener =
- event -> mLockIcon.setDocked(event == DockManager.STATE_DOCKED
- || event == DockManager.STATE_DOCKED_HIDE);
+ event -> {
+ boolean docked =
+ event == DockManager.STATE_DOCKED || event == DockManager.STATE_DOCKED_HIDE;
+ if (docked != mDocked) {
+ mDocked = docked;
+ update();
+ }
+ };
+
+ private final KeyguardStateController.Callback mKeyguardMonitorCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ boolean force = false;
+ boolean wasShowing = mKeyguardShowing;
+ mKeyguardShowing = mKeyguardStateController.isShowing();
+ if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
+ mBlockUpdates = false;
+ force = true;
+ }
+ if (!wasShowing && mKeyguardShowing) {
+ mKeyguardJustShown = true;
+ }
+ update(force);
+ }
+
+ @Override
+ public void onKeyguardFadingAwayChanged() {
+ if (!mKeyguardStateController.isKeyguardFadingAway()) {
+ if (mBlockUpdates) {
+ mBlockUpdates = false;
+ update(true /* force */);
+ }
+ }
+ }
+
+ @Override
+ public void onUnlockedChanged() {
+ update();
+ }
+ };
+
+ private final View.AccessibilityDelegate mAccessibilityDelegate =
+ new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ boolean fingerprintRunning =
+ mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
+ // Only checking if unlocking with Biometric is allowed (no matter strong or
+ // non-strong as long as primary auth, i.e. PIN/pattern/password, is not
+ // required), so it's ok to pass true for isStrongBiometric to
+ // isUnlockingWithBiometricAllowed() to bypass the check of whether non-strong
+ // biometric is allowed
+ boolean unlockingAllowed = mKeyguardUpdateMonitor
+ .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
+ if (fingerprintRunning && unlockingAllowed) {
+ AccessibilityNodeInfo.AccessibilityAction unlock =
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK,
+ mResources.getString(
+ R.string.accessibility_unlock_without_fingerprint));
+ info.addAction(unlock);
+ info.setHintText(mResources.getString(
+ R.string.accessibility_waiting_for_fingerprint));
+ } else if (getState() == STATE_SCANNING_FACE) {
+ //Avoid 'button' to be spoken for scanning face
+ info.setClassName(LockIcon.class.getName());
+ info.setContentDescription(mResources.getString(
+ R.string.accessibility_scanning_face));
+ }
+ }
+ };
+ private int mLastState;
@Inject
public LockscreenLockIconController(LockscreenGestureLogger lockscreenGestureLogger,
@@ -188,7 +319,10 @@ public class LockscreenLockIconController {
ConfigurationController configurationController,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
- @Nullable DockManager dockManager) {
+ @Nullable DockManager dockManager,
+ KeyguardStateController keyguardStateController,
+ @Main Resources resources,
+ HeadsUpManagerPhone headsUpManagerPhone) {
mLockscreenGestureLogger = lockscreenGestureLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -200,24 +334,31 @@ public class LockscreenLockIconController {
mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
mKeyguardBypassController = keyguardBypassController;
mDockManager = dockManager == null ? Optional.empty() : Optional.of(dockManager);
+ mKeyguardStateController = keyguardStateController;
+ mResources = resources;
+ mHeadsUpManagerPhone = headsUpManagerPhone;
mKeyguardIndicationController.setLockIconController(this);
}
/**
* Associate the controller with a {@link LockIcon}
+ *
+ * TODO: change to an init method and inject the view.
*/
public void attach(LockIcon lockIcon) {
mLockIcon = lockIcon;
mLockIcon.setOnClickListener(this::handleClick);
mLockIcon.setOnLongClickListener(this::handleLongClick);
+ mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
+ mLockIcon.setStateProvider(this::getState);
if (mLockIcon.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon);
}
mLockIcon.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
- mLockIcon.setStatusBarState(mStatusBarStateController.getState());
+ setStatusBarState(mStatusBarStateController.getState());
}
public LockIcon getView() {
@@ -228,8 +369,10 @@ public class LockscreenLockIconController {
* Called whenever the scrims become opaque, transparent or semi-transparent.
*/
public void onScrimVisibilityChanged(Integer scrimsVisible) {
- if (mLockIcon != null) {
- mLockIcon.onScrimVisibilityChanged(scrimsVisible);
+ if (mWakeAndUnlockRunning
+ && scrimsVisible == ScrimController.TRANSPARENT) {
+ mWakeAndUnlockRunning = false;
+ update();
}
}
@@ -237,55 +380,56 @@ public class LockscreenLockIconController {
* Propagate {@link StatusBar} pulsing state.
*/
public void setPulsing(boolean pulsing) {
- if (mLockIcon != null) {
- mLockIcon.setPulsing(pulsing);
- }
+ mPulsing = pulsing;
+ update();
}
/**
- * Called when the biometric authentication mode changes.
- *
- * @param wakeAndUnlock If the type is {@link BiometricUnlockController#isWakeAndUnlock()}
- * @param isUnlock If the type is {@link BiometricUnlockController#isBiometricUnlock()} ()
+ * We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
+ * icon on top of the black front scrim.
+ * @param wakeAndUnlock are we wake and unlocking
+ * @param isUnlock are we currently unlocking
*/
public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
- if (mLockIcon != null) {
- mLockIcon.onBiometricAuthModeChanged(wakeAndUnlock, isUnlock);
+ if (wakeAndUnlock) {
+ mWakeAndUnlockRunning = true;
+ }
+ if (isUnlock && mKeyguardBypassController.getBypassEnabled() && canBlockUpdates()) {
+ // We don't want the icon to change while we are unlocking
+ mBlockUpdates = true;
}
+ update();
}
/**
* When we're launching an affordance, like double pressing power to open camera.
*/
public void onShowingLaunchAffordanceChanged(Boolean showing) {
- if (mLockIcon != null) {
- mLockIcon.onShowingLaunchAffordanceChanged(showing);
- }
+ mShowingLaunchAffordance = showing;
+ update();
}
/** Sets whether the bouncer is showing. */
public void setBouncerShowingScrimmed(boolean bouncerShowing) {
- if (mLockIcon != null) {
- mLockIcon.setBouncerShowingScrimmed(bouncerShowing);
+ mBouncerShowingScrimmed = bouncerShowing;
+ if (mKeyguardBypassController.getBypassEnabled()) {
+ update();
}
}
/**
- * When {@link KeyguardBouncer} starts to be dismissed and starts to play its animation.
+ * Animate padlock opening when bouncer challenge is solved.
*/
public void onBouncerPreHideAnimation() {
- if (mLockIcon != null) {
- mLockIcon.onBouncerPreHideAnimation();
- }
+ update();
}
/**
* If we're currently presenting an authentication error message.
*/
public void setTransientBiometricsError(boolean transientBiometricsError) {
- if (mLockIcon != null) {
- mLockIcon.setTransientBiometricsError(transientBiometricsError);
- }
+ mTransientBiometricsError = transientBiometricsError;
+ update();
}
private boolean handleLongClick(View view) {
@@ -306,4 +450,90 @@ public class LockscreenLockIconController {
}
mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
}
+
+ private void update() {
+ update(false /* force */);
+ }
+
+ private void update(boolean force) {
+ int state = getState();
+ boolean shouldUpdate = mLastState != state || force;
+ if (mBlockUpdates && canBlockUpdates()) {
+ shouldUpdate = false;
+ }
+ if (shouldUpdate && mLockIcon != null) {
+ mLockIcon.update(mLastState, mPulsing, mDozing, mKeyguardJustShown);
+ }
+ mLastState = state;
+ mKeyguardJustShown = false;
+ updateIconVisibility();
+ updateClickability();
+ }
+
+ private int getState() {
+ if ((mKeyguardStateController.canDismissLockScreen() || !mKeyguardShowing
+ || mKeyguardStateController.isKeyguardGoingAway()) && !mSimLocked) {
+ return STATE_LOCK_OPEN;
+ } else if (mTransientBiometricsError) {
+ return STATE_BIOMETRICS_ERROR;
+ } else if (mKeyguardUpdateMonitor.isFaceDetectionRunning() && !mPulsing) {
+ return STATE_SCANNING_FACE;
+ } else {
+ return STATE_LOCKED;
+ }
+ }
+
+ private boolean canBlockUpdates() {
+ return mKeyguardShowing || mKeyguardStateController.isKeyguardFadingAway();
+ }
+
+ private void setDozing(boolean isDozing) {
+ mDozing = isDozing;
+ update();
+ }
+
+ /** Set the StatusBarState. */
+ private void setStatusBarState(int statusBarState) {
+ mStatusBarState = statusBarState;
+ updateIconVisibility();
+ }
+
+ /**
+ * Update the icon visibility
+ * @return true if the visibility changed
+ */
+ private boolean updateIconVisibility() {
+ boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
+ boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
+ || mShowingLaunchAffordance;
+ if (mKeyguardBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
+ if ((mHeadsUpManagerPhone.isHeadsUpGoingAway()
+ || mHeadsUpManagerPhone.hasPinnedHeadsUp()
+ || mStatusBarState == StatusBarState.KEYGUARD)
+ && !mNotificationWakeUpCoordinator.getNotificationsFullyHidden()) {
+ invisible = true;
+ }
+ }
+
+ if (mLockIcon == null) {
+ return false;
+ }
+
+ return mLockIcon.updateIconVisibility(!invisible);
+ }
+
+ private void updateClickability() {
+ if (mAccessibilityController == null) {
+ return;
+ }
+ boolean canLock = mKeyguardStateController.isMethodSecure()
+ && mKeyguardStateController.canDismissLockScreen();
+ boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
+ if (mLockIcon != null) {
+ mLockIcon.setClickable(clickToUnlock);
+ mLockIcon.setLongClickable(canLock && !clickToUnlock);
+ mLockIcon.setFocusable(mAccessibilityController.isAccessibilityEnabled());
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index 56aae17f451e..c63712389a80 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -34,7 +34,6 @@ import com.android.systemui.qs.QuickStatusBarHeader;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.phone.LockIcon;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -148,11 +147,6 @@ public class InjectionInflationController {
KeyguardMessageArea createKeyguardMessageArea();
/**
- * Creates the keyguard LockIcon.
- */
- LockIcon createLockIcon();
-
- /**
* Creates the QSPanel.
*/
QSPanel createQSPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 54118390325c..bae5bb41aa5a 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Slog;
@@ -97,7 +98,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()
!= pd.mRotation && isImeShowing(displayId)) {
- pd.startAnimation(true);
+ pd.startAnimation(true, false /* forceRestart */);
}
}
@@ -200,7 +201,15 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
continue;
}
if (activeControl.getType() == InsetsState.ITYPE_IME) {
- mImeSourceControl = activeControl;
+ mHandler.post(() -> {
+ final Point lastSurfacePosition = mImeSourceControl != null
+ ? mImeSourceControl.getSurfacePosition() : null;
+ mImeSourceControl = activeControl;
+ if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
+ && mAnimation != null) {
+ startAnimation(mImeShowing, true /* forceRestart */);
+ }
+ });
}
}
}
@@ -212,7 +221,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return;
}
if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
- startAnimation(true /* show */);
+ startAnimation(true /* show */, false /* forceRestart */);
}
@Override
@@ -221,7 +230,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return;
}
if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
- startAnimation(false /* show */);
+ startAnimation(false /* show */, false /* forceRestart */);
}
/**
@@ -239,7 +248,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return imeSource.getFrame().top + (int) surfaceOffset;
}
- private void startAnimation(final boolean show) {
+ private void startAnimation(final boolean show, final boolean forceRestart) {
final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
if (imeSource == null || mImeSourceControl == null) {
return;
@@ -250,7 +259,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
+ (mAnimationDirection == DIRECTION_SHOW ? "SHOW"
: (mAnimationDirection == DIRECTION_HIDE ? "HIDE" : "NONE")));
}
- if ((mAnimationDirection == DIRECTION_SHOW && show)
+ if (!forceRestart && (mAnimationDirection == DIRECTION_SHOW && show)
|| (mAnimationDirection == DIRECTION_HIDE && !show)) {
return;
}
@@ -270,11 +279,6 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
final float shownY = defaultY;
final float startY = show ? hiddenY : shownY;
final float endY = show ? shownY : hiddenY;
- if (mImeShowing && show) {
- // IME is already showing, so set seek to end
- seekValue = shownY;
- seek = true;
- }
mImeShowing = show;
mAnimation = ValueAnimator.ofFloat(startY, endY);
mAnimation.setDuration(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
index 464a740c931c..072bc446fd21 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
@@ -22,6 +22,8 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.widget.TextView
+import androidx.arch.core.executor.ArchTaskExecutor
+import androidx.arch.core.executor.TaskExecutor
import androidx.test.filters.SmallTest
import com.android.systemui.R
@@ -50,25 +52,46 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() {
private lateinit var mediaMetadata: MediaMetadata.Builder
private lateinit var entry: NotificationEntryBuilder
@Mock private lateinit var mockView: View
- private lateinit var textView: TextView
+ private lateinit var songView: TextView
+ private lateinit var artistView: TextView
@Mock private lateinit var mockIcon: Icon
+ private val taskExecutor: TaskExecutor = object : TaskExecutor() {
+ public override fun executeOnDiskIO(runnable: Runnable) {
+ runnable.run()
+ }
+ public override fun postToMainThread(runnable: Runnable) {
+ runnable.run()
+ }
+ public override fun isMainThread(): Boolean {
+ return true
+ }
+ }
+
@Before
public fun setup() {
fakeExecutor = FakeExecutor(FakeSystemClock())
keyguardMediaPlayer = KeyguardMediaPlayer(context, fakeExecutor)
- mockView = mock(View::class.java)
- textView = TextView(context)
mockIcon = mock(Icon::class.java)
+
+ mockView = mock(View::class.java)
+ songView = TextView(context)
+ artistView = TextView(context)
+ whenever<TextView>(mockView.findViewById(R.id.header_title)).thenReturn(songView)
+ whenever<TextView>(mockView.findViewById(R.id.header_artist)).thenReturn(artistView)
+
mediaMetadata = MediaMetadata.Builder()
entry = NotificationEntryBuilder()
+ ArchTaskExecutor.getInstance().setDelegate(taskExecutor)
+
keyguardMediaPlayer.bindView(mockView)
}
@After
public fun tearDown() {
keyguardMediaPlayer.unbindView()
+ ArchTaskExecutor.getInstance().setDelegate(null)
}
@Test
@@ -87,34 +110,36 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() {
@Test
public fun testUpdateControls() {
keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
+ FakeExecutor.exhaustExecutors(fakeExecutor)
verify(mockView).setVisibility(View.VISIBLE)
}
@Test
public fun testClearControls() {
keyguardMediaPlayer.clearControls()
+ FakeExecutor.exhaustExecutors(fakeExecutor)
verify(mockView).setVisibility(View.GONE)
}
@Test
public fun testSongName() {
- whenever<TextView>(mockView.findViewById(R.id.header_title)).thenReturn(textView)
val song: String = "Song"
mediaMetadata.putText(MediaMetadata.METADATA_KEY_TITLE, song)
keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
- assertThat(textView.getText()).isEqualTo(song)
+ assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
+ assertThat(songView.getText()).isEqualTo(song)
}
@Test
public fun testArtistName() {
- whenever<TextView>(mockView.findViewById(R.id.header_artist)).thenReturn(textView)
val artist: String = "Artist"
mediaMetadata.putText(MediaMetadata.METADATA_KEY_ARTIST, artist)
keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
- assertThat(textView.getText()).isEqualTo(artist)
+ assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
+ assertThat(artistView.getText()).isEqualTo(artist)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 6e612d7124ed..6f3fbb9cbd2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -62,7 +62,9 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -90,6 +92,8 @@ import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.InjectionInflationController;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -136,6 +140,9 @@ public class BubbleControllerTest extends SysuiTestCase {
@Mock
private FloatingContentCoordinator mFloatingContentCoordinator;
+ private SysUiState mSysUiState;
+ private boolean mSysUiStateBubblesExpanded;
+
@Captor
private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
@Captor
@@ -229,6 +236,11 @@ public class BubbleControllerTest extends SysuiTestCase {
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
+ mSysUiState = new SysUiState();
+ mSysUiState.addCallback(sysUiFlags ->
+ mSysUiStateBubblesExpanded =
+ (sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0);
+
TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
mock(PowerManager.class),
@@ -257,7 +269,8 @@ public class BubbleControllerTest extends SysuiTestCase {
mNotifPipeline,
mFeatureFlagsOldPipeline,
mDumpManager,
- mFloatingContentCoordinator);
+ mFloatingContentCoordinator,
+ mSysUiState);
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -277,6 +290,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.hasBubbles());
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -284,6 +298,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertFalse(mBubbleController.hasBubbles());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -300,6 +315,25 @@ public class BubbleControllerTest extends SysuiTestCase {
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
+
+ assertFalse(mSysUiStateBubblesExpanded);
+ }
+
+ @Test
+ public void testPromoteBubble_autoExpand() {
+ mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+
+ Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
+ assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
+
+ Bubble b2 = mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey());
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2);
+
+ mBubbleController.promoteBubbleFromOverflow(b);
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b);
}
@Test
@@ -323,6 +357,8 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
eq(mRow.getEntry().getSbn()), anyInt());
assertFalse(mBubbleController.hasBubbles());
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -340,6 +376,8 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -363,6 +401,8 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
+ assertTrue(mSysUiStateBubblesExpanded);
+
// Make sure the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -372,6 +412,8 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
assertFalse(mBubbleController.isStackExpanded());
assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -395,6 +437,8 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isStackExpanded());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
+ assertTrue(mSysUiStateBubblesExpanded);
+
// Last added is the one that is expanded
assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
@@ -416,6 +460,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// Collapse
mBubbleController.collapseStack();
assertFalse(mBubbleController.isStackExpanded());
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -437,6 +483,8 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isStackExpanded());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+ assertTrue(mSysUiStateBubblesExpanded);
+
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -463,6 +511,8 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.isStackExpanded());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+ assertTrue(mSysUiStateBubblesExpanded);
+
// Notif is suppressed after expansion
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -493,6 +543,8 @@ public class BubbleControllerTest extends SysuiTestCase {
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleController.expandStack();
+ assertTrue(mSysUiStateBubblesExpanded);
+
assertTrue(mBubbleController.isStackExpanded());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
@@ -522,6 +574,8 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
assertFalse(mBubbleController.hasBubbles());
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -541,6 +595,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -559,6 +615,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+ assertTrue(mSysUiStateBubblesExpanded);
}
@Test
@@ -579,6 +637,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -605,6 +665,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// # of bubbles should change
verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+ assertFalse(mSysUiStateBubblesExpanded);
}
@Test
@@ -619,6 +681,8 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
mBubbleController.expandStackAndSelectBubble(key);
+
+ assertTrue(mSysUiStateBubblesExpanded);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 624464401a4a..a31e3f8d7cc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -58,6 +58,7 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -132,6 +133,9 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
private KeyguardBypassController mKeyguardBypassController;
@Mock
private FloatingContentCoordinator mFloatingContentCoordinator;
+
+ private SysUiState mSysUiState = new SysUiState();
+
@Captor
private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
private TestableBubbleController mBubbleController;
@@ -242,7 +246,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mNotifPipeline,
mFeatureFlagsNewPipeline,
mDumpManager,
- mFloatingContentCoordinator);
+ mFloatingContentCoordinator,
+ mSysUiState);
mBubbleController.addNotifCallback(mNotifCallback);
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index d3d90c408468..f4861028e81a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -19,6 +19,7 @@ package com.android.systemui.bubbles;
import android.content.Context;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -52,12 +53,13 @@ public class TestableBubbleController extends BubbleController {
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
DumpManager dumpManager,
- FloatingContentCoordinator floatingContentCoordinator) {
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState) {
super(context,
notificationShadeWindowController, statusBarStateController, shadeController,
data, Runnable::run, configurationController, interruptionStateProvider,
zenModeController, lockscreenUserManager, groupManager, entryManager,
- notifPipeline, featureFlags, dumpManager, floatingContentCoordinator);
+ notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState);
setInflateSynchronously(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
new file mode 100644
index 000000000000..87fc02062ad4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable.PluggableListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class HideNotifsForOtherUsersCoordinatorTest extends SysuiTestCase {
+
+ @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+ @Mock private NotifPipeline mNotifPipeline;
+ @Mock private PluggableListener<NotifFilter> mInvalidationListener;
+
+ @Captor private ArgumentCaptor<UserChangedListener> mUserChangedListenerCaptor;
+ @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor;
+
+ private UserChangedListener mCapturedUserChangeListener;
+ private NotifFilter mCapturedNotifFilter;
+
+ private NotificationEntry mEntry = new NotificationEntryBuilder().build();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ HideNotifsForOtherUsersCoordinator coordinator =
+ new HideNotifsForOtherUsersCoordinator(mLockscreenUserManager);
+ coordinator.attach(mNotifPipeline);
+
+ verify(mLockscreenUserManager).addUserChangedListener(mUserChangedListenerCaptor.capture());
+ verify(mNotifPipeline).addPreGroupFilter(mNotifFilterCaptor.capture());
+
+ mCapturedUserChangeListener = mUserChangedListenerCaptor.getValue();
+ mCapturedNotifFilter = mNotifFilterCaptor.getValue();
+
+ mCapturedNotifFilter.setInvalidationListener(mInvalidationListener);
+ }
+
+ @Test
+ public void testFilterOutNotifsFromOtherProfiles() {
+ // GIVEN that all notifs are NOT for the current user
+ when(mLockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false);
+
+ // THEN they should all be filtered out
+ assertTrue(mCapturedNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void testPreserveNotifsFromThisProfile() {
+ // GIVEN that all notifs ARE for the current user
+ when(mLockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(true);
+
+ // THEN none should be filtered out
+ assertFalse(mCapturedNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void testFilterIsInvalidatedWhenProfilesChange() {
+ // WHEN the current user profiles change
+ mCapturedUserChangeListener.onCurrentProfilesChanged(new SparseArray<>());
+
+ // THEN the filter is invalidated
+ verify(mInvalidationListener).onPluggableInvalidated(mCapturedNotifFilter);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index c4f3a1611afc..4f481081855f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -102,16 +102,6 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
}
@Test
- public void notificationNotForCurrentProfile() {
- // GIVEN the notification isn't for the given user
- setupUnfilteredState(mEntry);
- when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(false);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
public void keyguardNotShowing() {
// GIVEN the lockscreen isn't showing
setupUnfilteredState(mEntry);
@@ -229,9 +219,6 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
* KeyguardNotificationCoordinator when the keyguard is showing.
*/
private void setupUnfilteredState(NotificationEntry entry) {
- // notification is for current profile
- when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(true);
-
// keyguard is showing
when(mKeyguardStateController.isShowing()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 487885ac244e..85b5d70c883c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.res.Resources;
import android.view.View;
import androidx.test.filters.SmallTest;
@@ -35,6 +36,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Test;
@@ -71,6 +73,12 @@ public class LockscreenIconControllerTest extends SysuiTestCase {
private KeyguardBypassController mKeyguardBypassController;
@Mock
private DockManager mDockManager;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private HeadsUpManagerPhone mHeadsUpManagerPhone;
@Before
@@ -81,7 +89,8 @@ public class LockscreenIconControllerTest extends SysuiTestCase {
mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
mShadeController, mAccessibilityController, mKeyguardIndicationController,
mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
- mKeyguardBypassController, mDockManager);
+ mKeyguardBypassController, mDockManager, mKeyguardStateController, mResources,
+ mHeadsUpManagerPhone);
mLockIconController.attach(mLockIcon);
}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 2fbba68f1e03..6af5fe54f281 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -60,6 +60,7 @@ java_library {
hostdex: true, // for hiddenapi check
visibility: ["//frameworks/base/packages/Tethering:__subpackages__"],
apex_available: ["com.android.tethering"],
+ permitted_packages: ["android.net"],
}
stubs_defaults {
@@ -125,17 +126,17 @@ droidstubs {
java_library {
name: "framework-tethering-stubs-publicapi",
srcs: [":framework-tethering-stubs-srcs-publicapi"],
- sdk_version: "current",
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
}
java_library {
name: "framework-tethering-stubs-systemapi",
srcs: [":framework-tethering-stubs-srcs-systemapi"],
- sdk_version: "system_current",
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
java_library {
name: "framework-tethering-stubs-module_libs_api",
srcs: [":framework-tethering-stubs-srcs-module_libs_api"],
- sdk_version: "module_current",
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 36113acf97d3..c84892d675f9 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -303,7 +303,8 @@ public class Tethering {
final UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
- mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
+ mTetheringRestriction = new UserRestrictionActionListener(
+ userManager, this, mNotificationUpdater);
mExecutor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
@@ -369,9 +370,10 @@ public class Tethering {
mActiveDataSubId = subId;
updateConfiguration();
+ mNotificationUpdater.onActiveDataSubscriptionIdChanged(subId);
// To avoid launching unexpected provisioning checks, ignore re-provisioning
// when no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning()
- // ill be triggered again when CarrierConfig is loaded.
+ // will be triggered again when CarrierConfig is loaded.
if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
} else {
@@ -431,9 +433,7 @@ public class Tethering {
// Called by wifi when the number of soft AP clients changed.
@Override
public void onConnectedClientsChanged(final List<WifiClient> clients) {
- if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, clients)) {
- reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
- }
+ updateConnectedClients(clients);
}
}
@@ -635,7 +635,10 @@ public class Tethering {
Context.ETHERNET_SERVICE);
synchronized (mPublicSync) {
if (enable) {
- if (mEthernetCallback != null) return TETHER_ERROR_NO_ERROR;
+ if (mEthernetCallback != null) {
+ Log.d(TAG, "Ethernet tethering already started");
+ return TETHER_ERROR_NO_ERROR;
+ }
mEthernetCallback = new EthernetCallback();
mEthernetIfaceRequest = em.requestTetheredInterface(mExecutor, mEthernetCallback);
@@ -996,11 +999,14 @@ public class Tethering {
protected static class UserRestrictionActionListener {
private final UserManager mUserManager;
private final Tethering mWrapper;
+ private final TetheringNotificationUpdater mNotificationUpdater;
public boolean mDisallowTethering;
- public UserRestrictionActionListener(UserManager um, Tethering wrapper) {
+ public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
+ @NonNull TetheringNotificationUpdater updater) {
mUserManager = um;
mWrapper = wrapper;
+ mNotificationUpdater = updater;
mDisallowTethering = false;
}
@@ -1019,13 +1025,21 @@ public class Tethering {
return;
}
- // TODO: Add user restrictions notification.
- final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
-
- if (newlyDisallowed && isTetheringActiveOnDevice) {
- mWrapper.untetherAll();
- // TODO(b/148139325): send tetheringSupported on restriction change
+ if (!newlyDisallowed) {
+ // Clear the restricted notification when user is allowed to have tethering
+ // function.
+ mNotificationUpdater.tetheringRestrictionLifted();
+ return;
}
+
+ // Restricted notification is shown when tethering function is disallowed on
+ // user's device.
+ mNotificationUpdater.notifyTetheringDisabledByRestriction();
+
+ // Untether from all downstreams since tethering is disallowed.
+ mWrapper.untetherAll();
+
+ // TODO(b/148139325): send tetheringSupported on restriction change
}
}
@@ -1559,6 +1573,7 @@ public class Tethering {
mIPv6TetheringCoordinator.removeActiveDownstream(who);
mOffload.excludeDownstreamInterface(who.interfaceName());
mForwardedDownstreams.remove(who);
+ updateConnectedClients(null /* wifiClients */);
// If this is a Wi-Fi interface, tell WifiManager of any errors
// or the inactive serving state.
@@ -2141,6 +2156,12 @@ public class Tethering {
return false;
}
+ private void updateConnectedClients(final List<WifiClient> wifiClients) {
+ if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, wifiClients)) {
+ reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
+ }
+ }
+
private IpServer.Callback makeControlCallback() {
return new IpServer.Callback() {
@Override
@@ -2155,10 +2176,7 @@ public class Tethering {
@Override
public void dhcpLeasesChanged() {
- if (mConnectedClientsTracker.updateConnectedClients(
- mForwardedDownstreams, null /* wifiClients */)) {
- reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
- }
+ updateConnectedClients(null /* wifiClients */);
}
};
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
index b97f75268a3b..992cdd8de6a7 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
@@ -29,12 +29,14 @@ import android.content.Intent;
import android.content.res.Resources;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.ArrayRes;
import androidx.annotation.DrawableRes;
+import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
@@ -54,10 +56,15 @@ import com.android.networkstack.tethering.R;
public class TetheringNotificationUpdater {
private static final String TAG = TetheringNotificationUpdater.class.getSimpleName();
private static final String CHANNEL_ID = "TETHERING_STATUS";
+ private static final String WIFI_DOWNSTREAM = "WIFI";
+ private static final String USB_DOWNSTREAM = "USB";
+ private static final String BLUETOOTH_DOWNSTREAM = "BT";
private static final boolean NOTIFY_DONE = true;
private static final boolean NO_NOTIFY = false;
// Id to update and cancel tethering notification. Must be unique within the tethering app.
- private static final int NOTIFY_ID = 20191115;
+ private static final int ENABLE_NOTIFICATION_ID = 1000;
+ // Id to update and cancel restricted notification. Must be unique within the tethering app.
+ private static final int RESTRICTED_NOTIFICATION_ID = 1001;
@VisibleForTesting
static final int NO_ICON_ID = 0;
@VisibleForTesting
@@ -65,14 +72,25 @@ public class TetheringNotificationUpdater {
private final Context mContext;
private final NotificationManager mNotificationManager;
private final NotificationChannel mChannel;
- // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2.
- // This value has to be made 1 2 and 4, and OR'd with the others.
+
// WARNING : the constructor is called on a different thread. Thread safety therefore
// relies on this value being initialized to 0, and not any other value. If you need
// to change this, you will need to change the thread where the constructor is invoked,
// or to introduce synchronization.
+ // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2.
+ // This value has to be made 1 2 and 4, and OR'd with the others.
private int mDownstreamTypesMask = DOWNSTREAM_NONE;
+ // WARNING : this value is not able to being initialized to 0 and must have volatile because
+ // telephony service is not guaranteed that is up before tethering service starts. If telephony
+ // is up later than tethering, TetheringNotificationUpdater will use incorrect and valid
+ // subscription id(0) to query resources. Therefore, initialized subscription id must be
+ // INVALID_SUBSCRIPTION_ID.
+ private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+ @IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID})
+ @interface NotificationId {}
+
public TetheringNotificationUpdater(@NonNull final Context context) {
mContext = context;
mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0)
@@ -88,19 +106,46 @@ public class TetheringNotificationUpdater {
public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) {
if (mDownstreamTypesMask == downstreamTypesMask) return;
mDownstreamTypesMask = downstreamTypesMask;
- updateNotification();
+ updateEnableNotification();
+ }
+
+ /** Called when active data subscription id changed */
+ public void onActiveDataSubscriptionIdChanged(final int subId) {
+ if (mActiveDataSubId == subId) return;
+ mActiveDataSubId = subId;
+ updateEnableNotification();
}
- private void updateNotification() {
+ @VisibleForTesting
+ Resources getResourcesForSubId(@NonNull final Context c, final int subId) {
+ return SubscriptionManager.getResourcesForSubId(c, subId);
+ }
+
+ private void updateEnableNotification() {
final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE;
if (tetheringInactive || setupNotification() == NO_NOTIFY) {
- clearNotification();
+ clearNotification(ENABLE_NOTIFICATION_ID);
}
}
- private void clearNotification() {
- mNotificationManager.cancel(null /* tag */, NOTIFY_ID);
+ @VisibleForTesting
+ void tetheringRestrictionLifted() {
+ clearNotification(RESTRICTED_NOTIFICATION_ID);
+ }
+
+ private void clearNotification(@NotificationId final int id) {
+ mNotificationManager.cancel(null /* tag */, id);
+ }
+
+ @VisibleForTesting
+ void notifyTetheringDisabledByRestriction() {
+ final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
+ final String title = res.getString(R.string.disable_tether_notification_title);
+ final String message = res.getString(R.string.disable_tether_notification_message);
+
+ showNotification(R.drawable.stat_sys_tether_general, title, message,
+ RESTRICTED_NOTIFICATION_ID);
}
/**
@@ -110,16 +155,17 @@ public class TetheringNotificationUpdater {
*
* @return downstream types mask value.
*/
+ @VisibleForTesting
@IntRange(from = 0, to = 7)
- private int getDownstreamTypesMask(@NonNull final String types) {
+ int getDownstreamTypesMask(@NonNull final String types) {
int downstreamTypesMask = DOWNSTREAM_NONE;
final String[] downstreams = types.split("\\|");
for (String downstream : downstreams) {
- if ("USB".equals(downstream.trim())) {
+ if (USB_DOWNSTREAM.equals(downstream.trim())) {
downstreamTypesMask |= (1 << TETHERING_USB);
- } else if ("WIFI".equals(downstream.trim())) {
+ } else if (WIFI_DOWNSTREAM.equals(downstream.trim())) {
downstreamTypesMask |= (1 << TETHERING_WIFI);
- } else if ("BT".equals(downstream.trim())) {
+ } else if (BLUETOOTH_DOWNSTREAM.equals(downstream.trim())) {
downstreamTypesMask |= (1 << TETHERING_BLUETOOTH);
}
}
@@ -134,9 +180,8 @@ public class TetheringNotificationUpdater {
*
* @return {@link android.util.SparseArray} with downstream types and icon id info.
*/
- @NonNull
- private SparseArray<Integer> getIcons(@ArrayRes int id) {
- final Resources res = mContext.getResources();
+ @VisibleForTesting
+ SparseArray<Integer> getIcons(@ArrayRes int id, @NonNull Resources res) {
final String[] array = res.getStringArray(id);
final SparseArray<Integer> icons = new SparseArray<>();
for (String config : array) {
@@ -161,8 +206,9 @@ public class TetheringNotificationUpdater {
}
private boolean setupNotification() {
- final Resources res = mContext.getResources();
- final SparseArray<Integer> downstreamIcons = getIcons(R.array.tethering_notification_icons);
+ final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
+ final SparseArray<Integer> downstreamIcons =
+ getIcons(R.array.tethering_notification_icons, res);
final int iconId = downstreamIcons.get(mDownstreamTypesMask, NO_ICON_ID);
if (iconId == NO_ICON_ID) return NO_NOTIFY;
@@ -170,12 +216,12 @@ public class TetheringNotificationUpdater {
final String title = res.getString(R.string.tethering_notification_title);
final String message = res.getString(R.string.tethering_notification_message);
- showNotification(iconId, title, message);
+ showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID);
return NOTIFY_DONE;
}
private void showNotification(@DrawableRes final int iconId, @NonNull final String title,
- @NonNull final String message) {
+ @NonNull final String message, @NotificationId final int id) {
final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS);
final PendingIntent pi = PendingIntent.getActivity(
mContext.createContextAsUser(UserHandle.CURRENT, 0),
@@ -193,6 +239,6 @@ public class TetheringNotificationUpdater {
.setContentIntent(pi)
.build();
- mNotificationManager.notify(null /* tag */, NOTIFY_ID, notification);
+ mNotificationManager.notify(null /* tag */, id, notification);
}
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt
new file mode 100644
index 000000000000..b86949185c69
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.Context
+import android.content.res.Resources
+import android.net.ConnectivityManager.TETHERING_BLUETOOTH
+import android.net.ConnectivityManager.TETHERING_USB
+import android.net.ConnectivityManager.TETHERING_WIFI
+import android.os.UserHandle
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.util.test.BroadcastInterceptingContext
+import com.android.networkstack.tethering.R
+import com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+const val TEST_SUBID = 1
+const val WIFI_ICON_ID = 1
+const val USB_ICON_ID = 2
+const val BT_ICON_ID = 3
+const val GENERAL_ICON_ID = 4
+const val WIFI_MASK = 1 shl TETHERING_WIFI
+const val USB_MASK = 1 shl TETHERING_USB
+const val BT_MASK = 1 shl TETHERING_BLUETOOTH
+const val TITTLE = "Tethering active"
+const val MESSAGE = "Tap here to set up."
+const val TEST_TITTLE = "Hotspot active"
+const val TEST_MESSAGE = "Tap to set up hotspot."
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TetheringNotificationUpdaterTest {
+ // lateinit used here for mocks as they need to be reinitialized between each test and the test
+ // should crash if they are used before being initialized.
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var notificationManager: NotificationManager
+ @Mock private lateinit var defaultResources: Resources
+ @Mock private lateinit var testResources: Resources
+
+ // lateinit for this class under test, as it should be reset to a different instance for every
+ // tests but should always be initialized before use (or the test should crash).
+ private lateinit var notificationUpdater: TetheringNotificationUpdater
+
+ private val ENABLE_ICON_CONFIGS = arrayOf(
+ "USB;android.test:drawable/usb", "BT;android.test:drawable/bluetooth",
+ "WIFI|BT;android.test:drawable/general", "WIFI|USB;android.test:drawable/general",
+ "USB|BT;android.test:drawable/general", "WIFI|USB|BT;android.test:drawable/general")
+
+ private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) {
+ override fun createContextAsUser(user: UserHandle, flags: Int) =
+ if (user == UserHandle.ALL) mockContext else this
+ }
+
+ private inner class WrappedNotificationUpdater(c: Context) : TetheringNotificationUpdater(c) {
+ override fun getResourcesForSubId(context: Context, subId: Int) =
+ if (subId == TEST_SUBID) testResources else defaultResources
+ }
+
+ private fun setupResources() {
+ doReturn(ENABLE_ICON_CONFIGS).`when`(defaultResources)
+ .getStringArray(R.array.tethering_notification_icons)
+ doReturn(arrayOf("WIFI;android.test:drawable/wifi")).`when`(testResources)
+ .getStringArray(R.array.tethering_notification_icons)
+ doReturn(TITTLE).`when`(defaultResources).getString(R.string.tethering_notification_title)
+ doReturn(MESSAGE).`when`(defaultResources)
+ .getString(R.string.tethering_notification_message)
+ doReturn(TEST_TITTLE).`when`(testResources).getString(R.string.tethering_notification_title)
+ doReturn(TEST_MESSAGE).`when`(testResources)
+ .getString(R.string.tethering_notification_message)
+ doReturn(USB_ICON_ID).`when`(defaultResources)
+ .getIdentifier(eq("android.test:drawable/usb"), any(), any())
+ doReturn(BT_ICON_ID).`when`(defaultResources)
+ .getIdentifier(eq("android.test:drawable/bluetooth"), any(), any())
+ doReturn(GENERAL_ICON_ID).`when`(defaultResources)
+ .getIdentifier(eq("android.test:drawable/general"), any(), any())
+ doReturn(WIFI_ICON_ID).`when`(testResources)
+ .getIdentifier(eq("android.test:drawable/wifi"), any(), any())
+ }
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ val context = TestContext(InstrumentationRegistry.getInstrumentation().context)
+ doReturn(notificationManager).`when`(mockContext)
+ .getSystemService(Context.NOTIFICATION_SERVICE)
+ notificationUpdater = WrappedNotificationUpdater(context)
+ setupResources()
+ }
+
+ private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE)
+ private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT)
+
+ private fun verifyNotification(iconId: Int = 0, title: String = "", text: String = "") {
+ verify(notificationManager, never()).cancel(any(), anyInt())
+
+ val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
+ verify(notificationManager, times(1))
+ .notify(any(), anyInt(), notificationCaptor.capture())
+
+ val notification = notificationCaptor.getValue()
+ assertEquals(iconId, notification.smallIcon.resId)
+ assertEquals(title, notification.title())
+ assertEquals(text, notification.text())
+
+ reset(notificationManager)
+ }
+
+ private fun verifyNoNotification() {
+ verify(notificationManager, times(1)).cancel(any(), anyInt())
+ verify(notificationManager, never()).notify(any(), anyInt(), any())
+
+ reset(notificationManager)
+ }
+
+ @Test
+ fun testNotificationWithDownstreamChanged() {
+ // Wifi downstream. No notification.
+ notificationUpdater.onDownstreamChanged(WIFI_MASK)
+ verifyNoNotification()
+
+ // Same downstream changed. Nothing happened.
+ notificationUpdater.onDownstreamChanged(WIFI_MASK)
+ verifyZeroInteractions(notificationManager)
+
+ // Wifi and usb downstreams. Show enable notification
+ notificationUpdater.onDownstreamChanged(WIFI_MASK or USB_MASK)
+ verifyNotification(GENERAL_ICON_ID, TITTLE, MESSAGE)
+
+ // Usb downstream. Still show enable notification.
+ notificationUpdater.onDownstreamChanged(USB_MASK)
+ verifyNotification(USB_ICON_ID, TITTLE, MESSAGE)
+
+ // No downstream. No notification.
+ notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
+ verifyNoNotification()
+ }
+
+ @Test
+ fun testNotificationWithActiveDataSubscriptionIdChanged() {
+ // Usb downstream. Showed enable notification with default resource.
+ notificationUpdater.onDownstreamChanged(USB_MASK)
+ verifyNotification(USB_ICON_ID, TITTLE, MESSAGE)
+
+ // Same subId changed. Nothing happened.
+ notificationUpdater.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
+ verifyZeroInteractions(notificationManager)
+
+ // Set test sub id. Clear notification with test resource.
+ notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
+ verifyNoNotification()
+
+ // Wifi downstream. Show enable notification with test resource.
+ notificationUpdater.onDownstreamChanged(WIFI_MASK)
+ verifyNotification(WIFI_ICON_ID, TEST_TITTLE, TEST_MESSAGE)
+
+ // No downstream. No notification.
+ notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
+ verifyNoNotification()
+ }
+
+ private fun assertIconNumbers(number: Int, configs: Array<String?>) {
+ doReturn(configs).`when`(defaultResources)
+ .getStringArray(R.array.tethering_notification_icons)
+ assertEquals(number, notificationUpdater.getIcons(
+ R.array.tethering_notification_icons, defaultResources).size())
+ }
+
+ @Test
+ fun testGetIcons() {
+ assertIconNumbers(0, arrayOfNulls<String>(0))
+ assertIconNumbers(0, arrayOf(null, ""))
+ assertIconNumbers(3, arrayOf(
+ // These configurations are invalid with wrong strings or symbols.
+ ";", ",", "|", "|,;", "WIFI", "1;2", " U SB; ", "bt;", "WIFI;USB;BT", "WIFI|USB|BT",
+ "WIFI,BT,USB", " WIFI| | | USB, test:drawable/test",
+ // This configuration is valid with two downstream types (USB, BT).
+ "USB|,,,,,|BT;drawable/test ",
+ // This configuration is valid with one downstream types (WIFI).
+ " WIFI ; android.test:drawable/xxx "))
+ }
+
+ @Test
+ fun testGetDownstreamTypesMask() {
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask(""))
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("1"))
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("WIFI_P2P"))
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("usb"))
+ assertEquals(WIFI_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI "))
+ assertEquals(USB_MASK, notificationUpdater.getDownstreamTypesMask("USB | B T"))
+ assertEquals(BT_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI: | BT"))
+ assertEquals(WIFI_MASK or USB_MASK,
+ notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||"))
+ }
+
+ @Test
+ fun testSetupRestrictedNotification() {
+ val title = InstrumentationRegistry.getInstrumentation().context.resources
+ .getString(R.string.disable_tether_notification_title)
+ val message = InstrumentationRegistry.getInstrumentation().context.resources
+ .getString(R.string.disable_tether_notification_message)
+ val disallowTitle = "Tether function is disallowed"
+ val disallowMessage = "Please contact your admin"
+ doReturn(title).`when`(defaultResources)
+ .getString(R.string.disable_tether_notification_title)
+ doReturn(message).`when`(defaultResources)
+ .getString(R.string.disable_tether_notification_message)
+ doReturn(disallowTitle).`when`(testResources)
+ .getString(R.string.disable_tether_notification_title)
+ doReturn(disallowMessage).`when`(testResources)
+ .getString(R.string.disable_tether_notification_message)
+
+ // User restrictions on. Show restricted notification.
+ notificationUpdater.notifyTetheringDisabledByRestriction()
+ verifyNotification(R.drawable.stat_sys_tether_general, title, message)
+
+ // User restrictions off. Clear notification.
+ notificationUpdater.tetheringRestrictionLifted()
+ verifyNoNotification()
+
+ // Set test sub id. No notification.
+ notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
+ verifyNoNotification()
+
+ // User restrictions on again. Show restricted notification with test resource.
+ notificationUpdater.notifyTetheringDisabledByRestriction()
+ verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage)
+ }
+} \ No newline at end of file
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 60d7ad1c5b1e..5ead1106d75a 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -210,7 +210,6 @@ public class TetheringTest {
private PhoneStateListener mPhoneStateListener;
private InterfaceConfigurationParcel mInterfaceConfiguration;
-
private class TestContext extends BroadcastInterceptingContext {
TestContext(Context base) {
super(base);
@@ -1073,13 +1072,15 @@ public class TetheringTest {
when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
final Tethering.UserRestrictionActionListener ural =
- new Tethering.UserRestrictionActionListener(mUserManager, mockTethering);
+ new Tethering.UserRestrictionActionListener(
+ mUserManager, mockTethering, mNotificationUpdater);
ural.mDisallowTethering = currentDisallow;
ural.onUserRestrictionsChanged();
- verify(mockTethering, times(expectedInteractionsWithShowNotification))
- .untetherAll();
+ verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification))
+ .notifyTetheringDisabledByRestriction();
+ verify(mockTethering, times(expectedInteractionsWithShowNotification)).untetherAll();
}
@Test
@@ -1087,7 +1088,7 @@ public class TetheringTest {
final String[] emptyActiveIfacesList = new String[]{};
final boolean currDisallow = false;
final boolean nextDisallow = true;
- final int expectedInteractionsWithShowNotification = 0;
+ final int expectedInteractionsWithShowNotification = 1;
runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,
expectedInteractionsWithShowNotification);
@@ -1399,6 +1400,7 @@ public class TetheringTest {
mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration();
assertEquals(fakeSubId, newConfig.activeDataSubId);
+ verify(mNotificationUpdater, times(1)).onActiveDataSubscriptionIdChanged(eq(fakeSubId));
}
@Test
diff --git a/services/Android.bp b/services/Android.bp
index 490481c7e5a2..52c5993a2862 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -142,6 +142,11 @@ droidstubs {
baseline_file: "api/lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android.txt",
+ },
}
java_library {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 60c3d7859984..1b180e3357d7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2001,17 +2001,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
userState.mUserId, currentTargets, str -> str);
scheduleNotifyClientsOfServicesStateChangeLocked(userState);
-
- // Disable accessibility shortcut key if there's no shortcut installed.
- if (currentTargets.isEmpty()) {
- final long identity = Binder.clearCallingIdentity();
- try {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
}
private boolean canRequestAndRequestsTouchExplorationLocked(
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index c39e93a84b48..2306329e689c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -165,7 +165,8 @@ public final class InlineSuggestionFactory {
Slog.w(TAG, "InlinePresentation not found in dataset");
continue;
}
- if (!includeDataset(dataset, fieldIndex, filterText)) {
+ if (!inlinePresentation.isPinned() // don't filter pinned suggestions
+ && !includeDataset(dataset, fieldIndex, filterText)) {
continue;
}
InlineSuggestion inlineSuggestion = createInlineSuggestion(isAugmented, dataset,
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 03ca1c610f82..1bf559a17021 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -112,9 +112,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int USER_SWITCHED_TIME_MS = 200;
// Delay for the addProxy function in msec
private static final int ADD_PROXY_DELAY_MS = 100;
+ // Delay for retrying enable and disable in msec
+ private static final int ENABLE_DISABLE_DELAY_MS = 300;
private static final int MESSAGE_ENABLE = 1;
private static final int MESSAGE_DISABLE = 2;
+ private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3;
+ private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
private static final int MESSAGE_REGISTER_ADAPTER = 20;
private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
@@ -136,6 +140,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int RESTORE_SETTING_TO_OFF = 0;
private static final int MAX_ERROR_RESTART_RETRIES = 6;
+ private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10;
// Bluetooth persisted setting is off
private static final int BLUETOOTH_OFF = 0;
@@ -166,6 +171,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
private boolean mBinding;
private boolean mUnbinding;
+ private int mWaitForEnableRetry;
+ private int mWaitForDisableRetry;
private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
@@ -1678,8 +1685,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
break;
case MESSAGE_ENABLE:
+ int quietEnable = msg.arg1;
+ if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
+ || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
+ // We are handling enable or disable right now, wait for it.
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE,
+ quietEnable, 0), ENABLE_DISABLE_DELAY_MS);
+ break;
+ }
+
if (DBG) {
- Slog.d(TAG, "MESSAGE_ENABLE(" + msg.arg1 + "): mBluetooth = " + mBluetooth);
+ Slog.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mBluetooth = "
+ + mBluetooth);
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
@@ -1702,7 +1719,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mBluetoothLock.readLock().unlock();
}
- mQuietEnable = (msg.arg1 == 1);
+ mQuietEnable = (quietEnable == 1);
if (mBluetooth == null) {
handleEnable(mQuietEnable);
} else {
@@ -1711,8 +1728,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// the previous Bluetooth process has exited. The
// waiting period has three components:
// (a) Wait until the local state is STATE_OFF. This
- // is accomplished by
- // "waitForState(Set.of(BluetoothAdapter.STATE_OFF))".
+ // is accomplished by sending delay a message
+ // MESSAGE_HANDLE_ENABLE_DELAYED
// (b) Wait until the STATE_OFF state is updated to
// all components.
// (c) Wait until the Bluetooth process exits, and
@@ -1722,33 +1739,108 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// message. The delay time is backed off if Bluetooth
// continuously failed to turn on itself.
//
- waitForState(Set.of(BluetoothAdapter.STATE_OFF));
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
+ mWaitForEnableRetry = 0;
+ Message enableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
+ mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
}
break;
case MESSAGE_DISABLE:
+ if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mBinding
+ || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
+ // We are handling enable or disable right now, wait for it.
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_DISABLE),
+ ENABLE_DISABLE_DELAY_MS);
+ break;
+ }
+
if (DBG) {
- Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth);
+ Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth
+ + ", mBinding = " + mBinding);
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+
if (mEnable && mBluetooth != null) {
- waitForState(Set.of(BluetoothAdapter.STATE_ON));
+ mWaitForDisableRetry = 0;
+ Message disableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+ } else {
mEnable = false;
handleDisable();
- waitForState(Set.of(BluetoothAdapter.STATE_OFF,
- BluetoothAdapter.STATE_TURNING_ON,
- BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_BLE_TURNING_ON,
- BluetoothAdapter.STATE_BLE_ON,
- BluetoothAdapter.STATE_BLE_TURNING_OFF));
- } else {
+ }
+ break;
+
+ case MESSAGE_HANDLE_ENABLE_DELAYED: {
+ // The Bluetooth is turning off, wait for STATE_OFF
+ if (mState != BluetoothAdapter.STATE_OFF) {
+ if (mWaitForEnableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+ mWaitForEnableRetry++;
+ Message enableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
+ mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+ break;
+ } else {
+ Slog.e(TAG, "Wait for STATE_OFF timeout");
+ }
+ }
+ // Either state is changed to STATE_OFF or reaches the maximum retry, we
+ // should move forward to the next step.
+ mWaitForEnableRetry = 0;
+ Message restartMsg =
+ mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
+ Slog.d(TAG, "Handle enable is finished");
+ break;
+ }
+
+ case MESSAGE_HANDLE_DISABLE_DELAYED: {
+ boolean disabling = (msg.arg1 == 1);
+ Slog.d(TAG, "MESSAGE_HANDLE_DISABLE_DELAYED: disabling:" + disabling);
+ if (!disabling) {
+ // The Bluetooth is turning on, wait for STATE_ON
+ if (mState != BluetoothAdapter.STATE_ON) {
+ if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+ mWaitForDisableRetry++;
+ Message disableDelayedMsg = mHandler.obtainMessage(
+ MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg,
+ ENABLE_DISABLE_DELAY_MS);
+ break;
+ } else {
+ Slog.e(TAG, "Wait for STATE_ON timeout");
+ }
+ }
+ // Either state is changed to STATE_ON or reaches the maximum retry, we
+ // should move forward to the next step.
+ mWaitForDisableRetry = 0;
mEnable = false;
handleDisable();
+ // Wait for state exiting STATE_ON
+ Message disableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+ } else {
+ // The Bluetooth is turning off, wait for exiting STATE_ON
+ if (mState == BluetoothAdapter.STATE_ON) {
+ if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+ mWaitForDisableRetry++;
+ Message disableDelayedMsg = mHandler.obtainMessage(
+ MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg,
+ ENABLE_DISABLE_DELAY_MS);
+ break;
+ } else {
+ Slog.e(TAG, "Wait for exiting STATE_ON timeout");
+ }
+ }
+ // Either state is exited from STATE_ON or reaches the maximum retry, we
+ // should move forward to the next step.
+ Slog.d(TAG, "Handle disable is finished");
}
break;
+ }
case MESSAGE_RESTORE_USER_SETTING:
if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
@@ -2124,6 +2216,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
try {
mBluetoothLock.writeLock().lock();
if ((mBluetooth == null) && (!mBinding)) {
+ Slog.d(TAG, "binding Bluetooth service");
//Start bind timeout and bind
Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
@@ -2493,6 +2586,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
writer.println(" " + app.getPackageName());
}
+ writer.println("\nBluetoothManagerService:");
+ writer.println(" mEnable:" + mEnable);
+ writer.println(" mQuietEnable:" + mQuietEnable);
+ writer.println(" mEnableExternal:" + mEnableExternal);
+ writer.println(" mQuietEnableExternal:" + mQuietEnableExternal);
+
writer.println("");
writer.flush();
if (args.length == 0) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ec84ae73d655..76a8e1474a95 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -40,6 +40,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.uidRulesToString;
@@ -50,6 +51,7 @@ import static android.system.OsConstants.IPPROTO_UDP;
import static java.util.Map.Entry;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
@@ -2702,10 +2704,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
switch (msg.what) {
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
- final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
+ NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
if (networkCapabilities.hasConnectivityManagedCapability()) {
Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
}
+ if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
+ // Make sure the original object is not mutated. NetworkAgent normally
+ // makes a copy of the capabilities when sending the message through
+ // the Messenger, but if this ever changes, not making a defensive copy
+ // here will give attack vectors to clients using this code path.
+ networkCapabilities = new NetworkCapabilities(networkCapabilities);
+ networkCapabilities.restrictCapabilitesForTestNetwork();
+ }
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
}
@@ -5778,7 +5788,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
- enforceNetworkFactoryPermission();
+ if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
+ enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
+ // Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
+ // the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
+ // sees capabilities that may be malicious, which might prevent mistakes in the future.
+ networkCapabilities = new NetworkCapabilities(networkCapabilities);
+ networkCapabilities.restrictCapabilitesForTestNetwork();
+ } else {
+ enforceNetworkFactoryPermission();
+ }
LinkProperties lp = new LinkProperties(linkProperties);
lp.ensureDirectlyConnectedRoutes();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 0bf81e0678dc..4d8c86c87e9e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -43,6 +43,7 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIE
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
import static android.os.storage.StorageManager.PROP_FUSE;
+import static android.os.storage.StorageManager.PROP_LEGACY_OP_STICKY;
import static android.os.storage.StorageManager.PROP_SETTINGS_FUSE;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -155,6 +156,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.pm.Installer;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.storage.AppFuseBridge;
import com.android.server.storage.StorageSessionController;
import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
@@ -902,6 +904,7 @@ class StorageManagerService extends IStorageManager.Stub
refreshIsolatedStorageSettings();
}
});
+ updateLegacyStorageOpSticky();
// For now, simply clone property when it changes
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
mContext.getMainExecutor(), (properties) -> {
@@ -1778,6 +1781,13 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ private void updateLegacyStorageOpSticky() {
+ final boolean propertyValue = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "legacy_storage_op_sticky", true);
+ SystemProperties.set(PROP_LEGACY_OP_STICKY, propertyValue ? "true" : "false");
+ }
+
private void start() {
connectStoraged();
connectVold();
@@ -3268,6 +3278,25 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ @Override
+ public void fixupAppDir(String path) {
+ final Matcher matcher = KNOWN_APP_DIR_PATHS.matcher(path);
+ if (matcher.matches()) {
+ AndroidPackage pkg = mPmInternal.getPackage(matcher.group(3));
+ if (pkg != null) {
+ try {
+ mVold.fixupAppDir(path + "/", pkg.getUid());
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.e(TAG, "Failed to fixup app dir for " + pkg.getPackageName(), e);
+ }
+ } else {
+ Log.e(TAG, "Can't find package belonging to " + path);
+ }
+ } else {
+ Log.e(TAG, "Path " + path + " is not a valid application-specific directory");
+ }
+ }
+
/** Not thread safe */
class AppFuseMountScope extends AppFuseBridge.MountScope {
private boolean mMounted = false;
@@ -4430,9 +4459,8 @@ class StorageManagerService extends IStorageManager.Stub
String.format("/storage/emulated/%d/Android/data/%s/",
userId, pkg);
- int appUid =
- UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
// Create package obb and data dir if it doesn't exist.
+ int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
File file = new File(packageObbDir);
if (!file.exists()) {
vold.setupAppDir(packageObbDir, appUid);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4cfcd2b218d1..8b2976d0e878 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8780,6 +8780,27 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public boolean isUidActiveOrForeground(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "isUidActiveOrForeground");
+ }
+ synchronized (this) {
+ final boolean isActive = isUidActiveLocked(uid);
+ if (isActive) {
+ return true;
+ }
+ }
+ final boolean isForeground = mAtmInternal.isUidForeground(uid);
+ if (isForeground) {
+ Slog.wtf(TAG, "isUidActiveOrForeground: isUidActive false but "
+ + " isUidForeground true, uid:" + uid
+ + " callingPackage:" + callingPackage);
+ }
+ return isForeground;
+ }
+
+ @Override
public void setPersistentVrThread(int tid) {
mActivityTaskManager.setPersistentVrThread(tid);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4d08bd2e0ed7..bee0e055cf3f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -98,6 +98,7 @@ import android.provider.DeviceConfig;
import android.system.Os;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -138,6 +139,7 @@ import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Activity manager code dealing with processes.
@@ -2155,15 +2157,6 @@ public final class ProcessList {
result.put(packageName, Pair.create(volumeUuid, inode));
}
}
- if (mAppDataIsolationWhitelistedApps != null) {
- for (String packageName : mAppDataIsolationWhitelistedApps) {
- String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid();
- long inode = pmInt.getCeDataInode(packageName, userId);
- if (inode != 0) {
- result.put(packageName, Pair.create(volumeUuid, inode));
- }
- }
- }
return result;
}
@@ -2184,34 +2177,42 @@ public final class ProcessList {
app.setHasForegroundActivities(true);
}
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
final Map<String, Pair<String, Long>> pkgDataInfoMap;
+ final Map<String, Pair<String, Long>> whitelistedAppDataInfoMap;
boolean bindMountAppStorageDirs = false;
-
- if (shouldIsolateAppData(app)) {
- // Get all packages belongs to the same shared uid. sharedPackages is empty array
- // if it doesn't have shared uid.
- final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
- final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
- app.info.packageName, app.userId);
- pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0
- ? new String[]{app.info.packageName} : sharedPackages, uid);
-
- int userId = UserHandle.getUserId(uid);
- if (mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) &&
- !storageManagerInternal.isExternalStorageService(uid)) {
- bindMountAppStorageDirs = true;
- if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
- app.processName)) {
- // Cannot prepare Android/app and Android/obb directory,
- // so we won't mount it in zygote.
- app.bindMountPending = true;
- bindMountAppStorageDirs = false;
- }
+ boolean bindMountAppsData = shouldIsolateAppData(app);
+
+ // Get all packages belongs to the same shared uid. sharedPackages is empty array
+ // if it doesn't have shared uid.
+ final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
+ final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
+ app.info.packageName, app.userId);
+ final String[] targetPackagesList = sharedPackages.length == 0
+ ? new String[]{app.info.packageName} : sharedPackages;
+ pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
+
+ // Remove all packages in pkgDataInfoMap from mAppDataIsolationWhitelistedApps, so
+ // it won't be mounted twice.
+ final Set<String> whitelistedApps = new ArraySet<>(mAppDataIsolationWhitelistedApps);
+ for (String pkg : targetPackagesList) {
+ whitelistedApps.remove(pkg);
+ }
+ whitelistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
+ whitelistedApps.toArray(new String[0]), uid);
+
+ int userId = UserHandle.getUserId(uid);
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ if (mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) &&
+ !storageManagerInternal.isExternalStorageService(uid)) {
+ bindMountAppStorageDirs = true;
+ if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
+ app.processName)) {
+ // Cannot prepare Android/app and Android/obb directory,
+ // so we won't mount it in zygote.
+ app.bindMountPending = true;
+ bindMountAppStorageDirs = false;
}
- } else {
- pkgDataInfoMap = null;
}
final Process.ProcessStartResult startResult;
@@ -2229,7 +2230,8 @@ public final class ProcessList {
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
- app.mDisabledCompatChanges, pkgDataInfoMap, bindMountAppStorageDirs,
+ app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
+ bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
@@ -2237,7 +2239,7 @@ public final class ProcessList {
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
- bindMountAppStorageDirs,
+ whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
}
checkSlow(startTime, "startProcess: returned from zygote!");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ada3e4269f6a..071058c113b2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -776,6 +776,8 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker = new AudioDeviceBroker(mContext, this);
+ mRecordMonitor = new RecordingActivityMonitor(mContext);
+
// must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
// array initialized by updateStreamVolumeAlias()
updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
@@ -797,8 +799,6 @@ public class AudioService extends IAudioService.Stub
mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
- mRecordMonitor = new RecordingActivityMonitor(mContext);
-
readAndSetLowRamDevice();
mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported();
@@ -1981,8 +1981,7 @@ public class AudioService extends IAudioService.Stub
}
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
- if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- mFixedVolumeDevices.contains(device)) {
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// Always toggle between max safe volume and 0 for fixed volume devices where safe
@@ -2059,7 +2058,7 @@ public class AudioService extends IAudioService.Stub
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
mVolumeController.postDisplaySafeVolumeWarning(flags);
- } else if (!mFullVolumeDevices.contains(device)
+ } else if (!isFullVolumeDevice(device)
&& (streamState.adjustIndex(direction * step, device, caller)
|| streamState.mIsMuted)) {
// Post message to set system volume (it in turn will post a
@@ -2121,7 +2120,7 @@ public class AudioService extends IAudioService.Stub
if (mHdmiCecSink
&& streamTypeAlias == AudioSystem.STREAM_MUSIC
// vol change on a full volume device
- && mFullVolumeDevices.contains(device)) {
+ && isFullVolumeDevice(device)) {
int keyCode = KeyEvent.KEYCODE_UNKNOWN;
switch (direction) {
case AudioManager.ADJUST_RAISE:
@@ -2590,8 +2589,7 @@ public class AudioService extends IAudioService.Stub
}
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
- if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- mFixedVolumeDevices.contains(device)) {
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// volume is either 0 or max allowed for fixed volume devices
@@ -2780,7 +2778,7 @@ public class AudioService extends IAudioService.Stub
if (streamType == AudioSystem.STREAM_MUSIC) {
flags = updateFlagsForTvPlatform(flags);
- if (mFullVolumeDevices.contains(device)) {
+ if (isFullVolumeDevice(device)) {
flags &= ~AudioManager.FLAG_SHOW_UI;
}
}
@@ -2826,7 +2824,7 @@ public class AudioService extends IAudioService.Stub
int device,
boolean force,
String caller) {
- if (mFullVolumeDevices.contains(device)) {
+ if (isFullVolumeDevice(device)) {
return;
}
VolumeStreamState streamState = mStreamStates[streamType];
@@ -3036,7 +3034,7 @@ public class AudioService extends IAudioService.Stub
index = 0;
}
if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
- mFixedVolumeDevices.contains(device)) {
+ isFixedVolumeDevice(device)) {
index = mStreamStates[streamType].getMaxIndex();
}
return (index + 5) / 10;
@@ -5166,7 +5164,7 @@ public class AudioService extends IAudioService.Stub
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
- } else if (mFullVolumeDevices.contains(device)) {
+ } else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
@@ -5189,7 +5187,7 @@ public class AudioService extends IAudioService.Stub
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
- } else if (mFullVolumeDevices.contains(device)) {
+ } else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
@@ -5390,8 +5388,8 @@ public class AudioService extends IAudioService.Stub
for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i);
int index = mIndexMap.valueAt(i);
- if (mFullVolumeDevices.contains(device)
- || (mFixedVolumeDevices.contains(device) && index != 0)) {
+ if (isFullVolumeDevice(device)
+ || (isFixedVolumeDevice(device) && index != 0)) {
mIndexMap.put(device, mIndexMax);
}
applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);
@@ -8236,4 +8234,23 @@ public class AudioService extends IAudioService.Stub
new HashMap<IBinder, AudioPolicyProxy>();
@GuardedBy("mAudioPolicies")
private int mAudioPolicyCounter = 0;
+
+ //======================
+ // Helper functions for full and fixed volume device
+ //======================
+ private boolean isFixedVolumeDevice(int deviceType) {
+ if (deviceType == AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
+ && mRecordMonitor.isLegacyRemoteSubmixActive()) {
+ return false;
+ }
+ return mFixedVolumeDevices.contains(deviceType);
+ }
+
+ private boolean isFullVolumeDevice(int deviceType) {
+ if (deviceType == AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
+ && mRecordMonitor.isLegacyRemoteSubmixActive()) {
+ return false;
+ }
+ return mFullVolumeDevices.contains(deviceType);
+ }
}
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 5c5096251e79..65f221899818 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -18,6 +18,7 @@ package com.android.server.audio;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
@@ -35,6 +36,8 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Class to receive and dispatch updates from AudioSystem about recording configurations.
@@ -49,6 +52,16 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
// playback configurations that do not contain uid/package name information.
private boolean mHasPublicClients = false;
+
+ // When legacy remote submix device is active, remote submix device should not be fixed and
+ // full volume device. When legacy remote submix device is active, there will be a recording
+ // activity using device with type as {@link AudioSystem.DEVICE_OUT_REMOTE_SUBMIX} and address
+ // as {@link AudioSystem.LEGACY_REMOTE_SUBMIX_ADDRESS}. Cache riid of legacy remote submix
+ // since remote submix state is not cached in mRecordStates.
+ private AtomicInteger mLegacyRemoteSubmixRiid =
+ new AtomicInteger(AudioManager.RECORD_RIID_INVALID);
+ private AtomicBoolean mLegacyRemoteSubmixActive = new AtomicBoolean(false);
+
static final class RecordingState {
private final int mRiid;
private final RecorderDeathHandler mDeathHandler;
@@ -137,6 +150,16 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
final AudioRecordingConfiguration config = createRecordingConfiguration(
uid, session, source, recordingInfo,
portId, silenced, activeSource, clientEffects, effects);
+ if (source == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
+ final AudioDeviceInfo device = config.getAudioDevice();
+ if (AudioSystem.LEGACY_REMOTE_SUBMIX_ADDRESS.equals(device.getAddress())) {
+ mLegacyRemoteSubmixRiid.set(riid);
+ if (event == AudioManager.RECORD_CONFIG_EVENT_START
+ || event == AudioManager.RECORD_CONFIG_EVENT_UPDATE) {
+ mLegacyRemoteSubmixActive.set(true);
+ }
+ }
+ }
if (MediaRecorder.isSystemOnlyAudioSource(source)) {
// still want to log event, it just won't appear in recording configurations;
sEventLogger.log(new RecordingEvent(event, riid, config).printLog(TAG));
@@ -170,6 +193,9 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
* Receive an event from the client about a tracked recorder
*/
public void recorderEvent(int riid, int event) {
+ if (mLegacyRemoteSubmixRiid.get() == riid) {
+ mLegacyRemoteSubmixActive.set(event == AudioManager.RECORDER_STATE_STARTED);
+ }
int configEvent = event == AudioManager.RECORDER_STATE_STARTED
? AudioManager.RECORD_CONFIG_EVENT_START :
event == AudioManager.RECORDER_STATE_STOPPED
@@ -323,6 +349,13 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
}
/**
+ * Return true if legacy remote submix device is active. Otherwise, return false.
+ */
+ boolean isLegacyRemoteSubmixActive() {
+ return mLegacyRemoteSubmixActive.get();
+ }
+
+ /**
* Create a recording configuration from the provided parameters
* @param uid
* @param session
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index d45ffd9918e4..ff8e3a973641 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -202,8 +202,7 @@ public class AuthService extends SystemService {
// Only allow internal clients to call canAuthenticate with a different userId.
final int callingUserId = UserHandle.getCallingUserId();
- Slog.d(TAG, "canAuthenticate, userId: " + userId + ", callingUserId: " + callingUserId
- + ", authenticators: " + authenticators);
+
if (userId != callingUserId) {
checkInternalPermission();
} else {
@@ -212,8 +211,14 @@ public class AuthService extends SystemService {
final long identity = Binder.clearCallingIdentity();
try {
- return mBiometricService.canAuthenticate(
+ final int result = mBiometricService.canAuthenticate(
opPackageName, userId, callingUserId, authenticators);
+ Slog.d(TAG, "canAuthenticate"
+ + ", userId: " + userId
+ + ", callingUserId: " + callingUserId
+ + ", authenticators: " + authenticators
+ + ", result: " + result);
+ return result;
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 766e5c4d638f..5d334c22f2db 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -66,6 +66,8 @@ public abstract class AuthenticationClient extends ClientMonitor {
public abstract boolean wasUserDetected();
+ public abstract boolean isStrongBiometric();
+
public AuthenticationClient(Context context, Constants constants,
BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId,
@@ -167,9 +169,15 @@ public abstract class AuthenticationClient extends ClientMonitor {
}
if (isBiometricPrompt() && listener != null) {
// BiometricService will add the token to keystore
- listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken);
+ listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken,
+ isStrongBiometric());
} else if (!isBiometricPrompt() && listener != null) {
- KeyStore.getInstance().addAuthToken(byteToken);
+ if (isStrongBiometric()) {
+ KeyStore.getInstance().addAuthToken(byteToken);
+ } else {
+ Slog.d(getLogTag(), "Skipping addAuthToken");
+ }
+
try {
// Explicitly have if/else here to make it super obvious in case the code is
// touched in the future.
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index e7c09baf3aeb..233416d663d9 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -266,7 +266,8 @@ public class BiometricService extends SystemService {
SomeArgs args = (SomeArgs) msg.obj;
handleAuthenticationSucceeded(
(boolean) args.arg1 /* requireConfirmation */,
- (byte[]) args.arg2 /* token */);
+ (byte[]) args.arg2 /* token */,
+ (boolean) args.arg3 /* isStrongBiometric */);
args.recycle();
break;
}
@@ -568,10 +569,12 @@ public class BiometricService extends SystemService {
final IBiometricServiceReceiverInternal mInternalReceiver =
new IBiometricServiceReceiverInternal.Stub() {
@Override
- public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+ public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = requireConfirmation;
args.arg2 = token;
+ args.arg3 = isStrongBiometric;
mHandler.obtainMessage(MSG_ON_AUTHENTICATION_SUCCEEDED, args).sendToTarget();
}
@@ -761,8 +764,13 @@ public class BiometricService extends SystemService {
+ " config_biometric_sensors?");
}
+ // Note that we allow BIOMETRIC_CONVENIENCE to register because BiometricService
+ // also does / will do other things such as keep track of lock screen timeout, etc.
+ // Just because a biometric is registered does not mean it can participate in
+ // the android.hardware.biometrics APIs.
if (strength != Authenticators.BIOMETRIC_STRONG
- && strength != Authenticators.BIOMETRIC_WEAK) {
+ && strength != Authenticators.BIOMETRIC_WEAK
+ && strength != Authenticators.BIOMETRIC_CONVENIENCE) {
throw new IllegalStateException("Unsupported strength");
}
@@ -1189,8 +1197,10 @@ public class BiometricService extends SystemService {
BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL);
}
} else {
+ // This should not be possible via the public API surface and is here mainly for
+ // "correctness". An exception should have been thrown before getting here.
Slog.e(TAG, "No authenticators requested");
- return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
+ return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT);
}
}
@@ -1286,7 +1296,8 @@ public class BiometricService extends SystemService {
return modality;
}
- private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+ private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) {
try {
// Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
// after user dismissed/canceled dialog).
@@ -1295,9 +1306,16 @@ public class BiometricService extends SystemService {
return;
}
- // Store the auth token and submit it to keystore after the dialog is confirmed /
- // animating away.
- mCurrentAuthSession.mTokenEscrow = token;
+ if (isStrongBiometric) {
+ // Store the auth token and submit it to keystore after the dialog is confirmed /
+ // animating away.
+ mCurrentAuthSession.mTokenEscrow = token;
+ } else {
+ if (token != null) {
+ Slog.w(TAG, "Dropping authToken for non-strong biometric");
+ }
+ }
+
if (!requireConfirmation) {
mCurrentAuthSession.mState = STATE_AUTHENTICATED_PENDING_SYSUI;
} else {
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ebd407d0e981..45b93834c1e2 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -413,8 +413,8 @@ public abstract class BiometricServiceBase extends SystemService
throw new UnsupportedOperationException("Stub!");
}
- default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
- throws RemoteException {
+ default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) throws RemoteException {
throw new UnsupportedOperationException("Stub!");
}
@@ -451,10 +451,11 @@ public abstract class BiometricServiceBase extends SystemService
}
@Override
- public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
- throws RemoteException {
+ public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) throws RemoteException {
if (getWrapperReceiver() != null) {
- getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token);
+ getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token,
+ isStrongBiometric);
}
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index fd54129a3263..3ecf87c6860f 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -236,6 +236,11 @@ public class FaceService extends BiometricServiceBase {
}
@Override
+ public boolean isStrongBiometric() {
+ return FaceService.this.isStrongBiometric();
+ }
+
+ @Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
final boolean result = super.onAuthenticated(identifier, authenticated, token);
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index acb1a2ffb754..8520f5aa0632 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -161,6 +161,11 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override
+ public boolean isStrongBiometric() {
+ return FingerprintService.this.isStrongBiometric();
+ }
+
+ @Override
public int handleFailedAttempt() {
final int currentUser = ActivityManager.getCurrentUser();
mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 87fe785ca614..ad08663a7d76 100644
--- a/services/core/java/com/android/server/incident/IncidentCompanionService.java
+++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java
@@ -50,6 +50,9 @@ import java.util.List;
*/
public class IncidentCompanionService extends SystemService {
static final String TAG = "IncidentCompanionService";
+ // TODO(b/152289743): Expose below intent.
+ private static final String INTENT_CHECK_USER_CONSENT =
+ "com.android.internal.intent.action.CHECK_USER_CONSENT";
/**
* Dump argument for proxying restricted image dumps to the services
@@ -89,6 +92,12 @@ public class IncidentCompanionService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
+ Intent intent = new Intent(INTENT_CHECK_USER_CONSENT);
+ intent.setPackage(callingPackage);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ getContext().sendBroadcast(intent, android.Manifest.permission.DUMP);
+
mPendingReports.authorizeReport(callingUid, callingPackage,
receiverClass, reportId, flags, listener);
} finally {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 0b22586bb373..e6129b9b1f32 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -76,7 +76,6 @@ import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputMonitor;
-import android.view.InputWindowHandle;
import android.view.KeyEvent;
import android.view.PointerIcon;
import android.view.Surface;
@@ -221,8 +220,7 @@ public class InputManagerService extends IInputManager.Stub
int policyFlags);
private static native VerifiedInputEvent nativeVerifyInputEvent(long ptr, InputEvent event);
private static native void nativeToggleCapsLock(long ptr, int deviceId);
- private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles,
- int displayId);
+ private static native void nativeDisplayRemoved(long ptr, int displayId);
private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
private static native void nativeSetFocusedApplication(long ptr,
@@ -1536,7 +1534,7 @@ public class InputManagerService extends IInputManager.Stub
/** Clean up input window handles of the given display. */
public void onDisplayRemoved(int displayId) {
- nativeSetInputWindows(mPtr, null /* windowHandles */, displayId);
+ nativeDisplayRemoved(mPtr, displayId);
}
@Override
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 58e332ab6d1d..c1fbcfba864a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -653,9 +653,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
- mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
- GnssLocationProvider.this::onNetworkAvailable, mLooper);
-
// App ops service to keep track of who is accessing the GPS
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -677,6 +674,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mNIHandler = new GpsNetInitiatedHandler(context,
mNetInitiatedListener,
mSuplEsEnabled);
+ mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
+ GnssLocationProvider.this::onNetworkAvailable, mLooper, mNIHandler);
+
sendMessage(INITIALIZE_HANDLER, 0, null);
mGnssStatusListenerHelper = new GnssStatusListenerHelper(mContext, mHandler) {
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index 93227bd78a81..5d6474bdbccc 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -29,12 +29,22 @@ import android.os.PowerManager;
import android.provider.Telephony.Carriers;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.PreciseCallState;
+import android.telephony.PhoneStateListener;
import android.util.Log;
+import com.android.internal.location.GpsNetInitiatedHandler;
+
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
+import java.util.Map;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Iterator;
/**
* Handles network connection requests and network state change updates for AGPS data download.
@@ -86,6 +96,9 @@ class GnssNetworkConnectivityHandler {
private HashMap<Network, NetworkAttributes> mAvailableNetworkAttributes =
new HashMap<>(HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS);
+ // Phone State Listeners to track all the active sub IDs
+ private HashMap<Integer, SubIdPhoneStateListener> mPhoneStateListeners;
+
private final ConnectivityManager mConnMgr;
private final Handler mHandler;
@@ -94,6 +107,9 @@ class GnssNetworkConnectivityHandler {
private int mAGpsDataConnectionState;
private InetAddress mAGpsDataConnectionIpAddr;
private int mAGpsType;
+ private int mActiveSubId = -1;
+ private final GpsNetInitiatedHandler mNiHandler;
+
private final Context mContext;
@@ -166,18 +182,109 @@ class GnssNetworkConnectivityHandler {
GnssNetworkConnectivityHandler(Context context,
GnssNetworkListener gnssNetworkListener,
- Looper looper) {
+ Looper looper,
+ GpsNetInitiatedHandler niHandler) {
mContext = context;
mGnssNetworkListener = gnssNetworkListener;
+ SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class);
+ if (subManager != null) {
+ subManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
+ }
+
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
mHandler = new Handler(looper);
+ mNiHandler = niHandler;
mConnMgr = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
mSuplConnectivityCallback = createSuplConnectivityCallback();
}
+ /**
+ * SubId Phone State Listener is used cache the last active Sub ID when a call is made,
+ * which will be used during an emergency call to set the Network Specifier to the particular
+ * sub when an emergency supl connection is requested
+ */
+ private final class SubIdPhoneStateListener extends PhoneStateListener {
+ private Integer mSubId;
+ SubIdPhoneStateListener(Integer subId) {
+ mSubId = subId;
+ }
+ @Override
+ public void onPreciseCallStateChanged(PreciseCallState state) {
+ if (state.PRECISE_CALL_STATE_ACTIVE == state.getForegroundCallState()) {
+ mActiveSubId = mSubId;
+ if (DEBUG) Log.d(TAG, "mActiveSubId: " + mActiveSubId);
+ }
+ }
+ };
+
+ /**
+ * Subscription Changed Listener is used to get all active subscriptions and create a
+ * Phone State Listener for each Sub ID that we find in the active subscription list
+ */
+ private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
+ = new SubscriptionManager.OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ if (mPhoneStateListeners == null) {
+ // Capacity=2 Load-Factor=1.0, as typically no more than 2 SIMs
+ mPhoneStateListeners = new HashMap<Integer, SubIdPhoneStateListener>(2,1);
+ }
+ SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class);
+ TelephonyManager telManager = mContext.getSystemService(TelephonyManager.class);
+ if (subManager != null && telManager != null) {
+ List<SubscriptionInfo> subscriptionInfoList =
+ subManager.getActiveSubscriptionInfoList();
+ HashSet<Integer> activeSubIds = new HashSet<Integer>();
+ if (subscriptionInfoList != null) {
+ if (DEBUG) Log.d(TAG, "Active Sub List size: " + subscriptionInfoList.size());
+ // populate phone state listeners with all new active subs
+ for (SubscriptionInfo subInfo : subscriptionInfoList) {
+ activeSubIds.add(subInfo.getSubscriptionId());
+ if (!mPhoneStateListeners.containsKey(subInfo.getSubscriptionId())) {
+ TelephonyManager subIdTelManager =
+ telManager.createForSubscriptionId(subInfo.getSubscriptionId());
+ if (subIdTelManager != null) {
+ if (DEBUG) Log.d(TAG, "Listener sub" + subInfo.getSubscriptionId());
+ SubIdPhoneStateListener subIdPhoneStateListener =
+ new SubIdPhoneStateListener(subInfo.getSubscriptionId());
+ mPhoneStateListeners.put(subInfo.getSubscriptionId(),
+ subIdPhoneStateListener);
+ subIdTelManager.listen(subIdPhoneStateListener,
+ PhoneStateListener.LISTEN_PRECISE_CALL_STATE);
+ }
+ }
+ }
+ }
+ // clean up phone state listeners than no longer have active subs
+ Iterator<Map.Entry<Integer, SubIdPhoneStateListener> > iterator =
+ mPhoneStateListeners.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry<Integer, SubIdPhoneStateListener> element = iterator.next();
+ if (!activeSubIds.contains(element.getKey())) {
+ TelephonyManager subIdTelManager =
+ telManager.createForSubscriptionId(element.getKey());
+ if (subIdTelManager != null) {
+ if (DEBUG) Log.d(TAG, "unregister listener sub " + element.getKey());
+ subIdTelManager.listen(element.getValue(),
+ PhoneStateListener.LISTEN_NONE);
+ // removes the element from mPhoneStateListeners
+ iterator.remove();
+ } else {
+ Log.e(TAG, "Telephony Manager for Sub " + element.getKey() + " null");
+ }
+ }
+ }
+ // clean up cached active phone call sub if it is no longer an active sub
+ if (!activeSubIds.contains(mActiveSubId)) {
+ mActiveSubId = -1;
+ }
+ }
+ }
+ };
+
void registerNetworkCallbacks() {
// register for connectivity change events.
NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
@@ -467,6 +574,12 @@ class GnssNetworkConnectivityHandler {
NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
networkRequestBuilder.addCapability(getNetworkCapability(mAGpsType));
networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ // During an emergency call, and when we have cached the Active Sub Id, we set the
+ // Network Specifier so that the network request goes to the correct Sub Id
+ if (mNiHandler.getInEmergency() && mActiveSubId >= 0) {
+ if (DEBUG) Log.d(TAG, "Adding Network Specifier: " + Integer.toString(mActiveSubId));
+ networkRequestBuilder.setNetworkSpecifier(Integer.toString(mActiveSubId));
+ }
NetworkRequest networkRequest = networkRequestBuilder.build();
mConnMgr.requestNetwork(
networkRequest,
@@ -598,6 +711,15 @@ class GnssNetworkConnectivityHandler {
}
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ // During an emergency call with an active sub id, get the Telephony Manager specific
+ // to the active sub to get the correct value from getServiceState and getNetworkType
+ if (mNiHandler.getInEmergency() && mActiveSubId >= 0) {
+ TelephonyManager subIdTelManager =
+ phone.createForSubscriptionId(mActiveSubId);
+ if (subIdTelManager != null) {
+ phone = subIdTelManager;
+ }
+ }
ServiceState serviceState = phone.getServiceState();
String projection = null;
String selection = null;
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 7069818e3894..40876754eae8 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -64,6 +64,7 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
private static final String TAG = "CrossProfileAppsService";
@@ -447,7 +448,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
final int uid = mInjector.getPackageManager()
.getPackageUidAsUser(packageName, /* flags= */ 0, userId);
if (currentModeEquals(newMode, packageName, uid)) {
- Slog.w(TAG, "Attempt to set mode to existing value of " + newMode + " for "
+ Slog.i(TAG, "Attempt to set mode to existing value of " + newMode + " for "
+ packageName + " on user ID " + userId);
return;
}
@@ -577,6 +578,24 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op));
}
+ @Override
+ public void clearInteractAcrossProfilesAppOps() {
+ final int defaultMode =
+ AppOpsManager.opToDefaultMode(
+ AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES));
+ findAllPackageNames()
+ .forEach(packageName -> setInteractAcrossProfilesAppOp(packageName, defaultMode));
+ }
+
+ private List<String> findAllPackageNames() {
+ return mInjector.getPackageManagerInternal()
+ .getInstalledApplications(
+ /* flags= */ 0, mInjector.getCallingUserId(), mInjector.getCallingUid())
+ .stream()
+ .map(applicationInfo -> applicationInfo.packageName)
+ .collect(Collectors.toList());
+ }
+
CrossProfileAppsInternal getLocalService() {
return mLocalService;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e605eeba4d98..58a9d9c5f6bf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24487,7 +24487,8 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
synchronized (mLock) {
boolean manifestWhitelisted =
- mPackages.get(packageName).isAllowDontAutoRevokePermmissions();
+ mPackages.get(packageName).getAutoRevokePermissions()
+ == ApplicationInfo.AUTO_REVOKE_DISALLOWED;
return manifestWhitelisted;
}
}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 3cc10d194dec..5a1e8e2661b8 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -230,6 +230,10 @@ public class PackageInfoUtils {
info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
}
+ info.seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting);
+ info.primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
+ info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting);
+
info.flags |= appInfoFlags(pkg, pkgSetting);
info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting);
return info;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 79d0c2db4448..04c965e69588 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -21,6 +21,8 @@ import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED;
+import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
@@ -3238,31 +3240,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public List<String> getAutoRevokeExemptionRequestedPackages(int userId) {
- mContext.enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
- "Must hold " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
-
- List<String> result = new ArrayList<>();
- mPackageManagerInt.forEachInstalledPackage(pkg -> {
- if (pkg.isDontAutoRevokePermmissions()) {
- result.add(pkg.getPackageName());
- }
- }, userId);
-
- return result;
+ return getPackagesWithAutoRevokePolicy(AUTO_REVOKE_DISCOURAGED, userId);
}
@Override
public List<String> getAutoRevokeExemptionGrantedPackages(int userId) {
+ return getPackagesWithAutoRevokePolicy(AUTO_REVOKE_DISALLOWED, userId);
+ }
+
+ @NonNull
+ private List<String> getPackagesWithAutoRevokePolicy(int autoRevokePolicy, int userId) {
mContext.enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
"Must hold " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
List<String> result = new ArrayList<>();
mPackageManagerInt.forEachInstalledPackage(pkg -> {
- if (pkg.isAllowDontAutoRevokePermmissions()) {
+ if (pkg.getAutoRevokePermissions() == autoRevokePolicy) {
result.add(pkg.getPackageName());
}
}, userId);
-
return result;
}
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 39aeafc345ea..d6c48a00d33d 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -26,6 +26,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INST
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.storage.StorageManager.PROP_LEGACY_OP_STICKY;
import static java.lang.Integer.min;
@@ -36,6 +37,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManagerInternal;
@@ -63,6 +65,9 @@ public abstract class SoftRestrictedPermissionPolicy {
}
};
+ private static final boolean isLegacyStorageAppOpStickyGlobal = SystemProperties.getBoolean(
+ PROP_LEGACY_OP_STICKY, /*defaultValue*/true);
+
/**
* TargetSDK is per package. To make sure two apps int the same shared UID do not fight over
* what to set, always compute the combined targetSDK.
@@ -136,9 +141,12 @@ public abstract class SoftRestrictedPermissionPolicy {
shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage()
&& smInternal.hasLegacyExternalStorage(appInfo.uid);
targetSDK = getMinimumTargetSDK(context, appInfo, user);
+ // LEGACY_STORAGE op is normally sticky for apps targetig <= Q.
+ // However, this device can be configured to make it non-sticky.
+ boolean isLegacyAppOpSticky = isLegacyStorageAppOpStickyGlobal
+ && targetSDK <= Build.VERSION_CODES.Q;
shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
- || (targetSDK > Build.VERSION_CODES.Q
- && !shouldPreserveLegacyExternalStorage);
+ || (!isLegacyAppOpSticky && !shouldPreserveLegacyExternalStorage);
} else {
isWhiteListed = false;
shouldApplyRestriction = false;
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index acf3f79e3626..74958b692eb2 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -3,6 +3,7 @@
{
"name": "CtsBatterySavingTestCases",
"options": [
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
@@ -11,6 +12,7 @@
"name": "FrameworksMockingServicesTests",
"options": [
{"include-filter": "com.android.server.power"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
},
@@ -18,6 +20,7 @@
"name": "FrameworksServicesTests",
"options": [
{"include-filter": "com.android.server.power"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{
"exclude-filter": "com.android.server.power.PowerManagerServiceTest#testWakefulnessAwake_ShouldWakeUpWhenPluggedIn"
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 74c3a9ec375b..2783d0b83254 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -767,7 +767,7 @@ public class ThermalManagerService extends SystemService {
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
- mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService();
+ mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService(true);
mThermalHal10.linkToDeath(new DeathRecipient(),
THERMAL_HAL_DEATH_COOKIE);
Slog.i(TAG,
@@ -902,7 +902,7 @@ public class ThermalManagerService extends SystemService {
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
- mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
+ mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService(true);
mThermalHal11.linkToDeath(new DeathRecipient(),
THERMAL_HAL_DEATH_COOKIE);
mThermalHal11.registerThermalCallback(mThermalCallback11);
@@ -1046,7 +1046,7 @@ public class ThermalManagerService extends SystemService {
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
- mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
+ mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService(true);
mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
0 /* not used */);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6d53786ddf41..3477d82f4d71 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4618,6 +4618,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
}
+ // The activity may be waiting for stop, but that is no longer appropriate if we are
+ // starting the activity again
+ mStackSupervisor.mStoppingActivities.remove(this);
}
return false;
}
@@ -4667,7 +4670,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* and {@link #shouldPauseActivity(ActivityRecord)}.
*/
private boolean shouldStartActivity() {
- return mVisibleRequested && isState(STOPPED);
+ return mVisibleRequested && (isState(STOPPED) || isState(STOPPING));
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index c6f375ea5d18..fa0ad505f1a9 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2572,6 +2572,13 @@ class ActivityStack extends Task {
if (r == null || r.app != app) {
return null;
}
+ if (r.isActivityTypeHome() && mAtmService.mHomeProcess == app) {
+ // Home activities should not be force-finished as we have nothing else to go
+ // back to. AppErrors will get to it after two crashes in MIN_CRASH_INTERVAL.
+ Slog.w(TAG, " Not force finishing home activity "
+ + r.intent.getComponent().flattenToShortString());
+ return null;
+ }
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
Task finishedTask = r.getTask();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ede456949116..a90016afcc49 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -659,6 +659,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// When non-null, new tasks get put into this root task.
Task mLaunchRootTask = null;
+ // Used in performing layout
+ private boolean mTmpWindowsBehindIme;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
@@ -750,6 +753,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
+ " parentHidden=" + w.isParentWindowHidden());
}
+ // Sets mBehindIme for each window. Windows behind IME can get IME insets.
+ w.mBehindIme = mTmpWindowsBehindIme;
+ if (w == mInputMethodWindow) {
+ mTmpWindowsBehindIme = true;
+ }
+
// If this view is GONE, then skip it -- keep the current frame, and let the caller know
// so they can ignore it if they want. (We do the normal layout for INVISIBLE windows,
// since that means "perform layout as normal, just don't display").
@@ -1308,8 +1317,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (mDisplayRotation.isWaitingForRemoteRotation()) {
return;
}
- // Clear the record because the display will sync to current rotation.
- mFixedRotationLaunchingApp = null;
final boolean configUpdated = updateDisplayOverrideConfigurationLocked();
if (configUpdated) {
@@ -1500,7 +1507,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
startFixedRotationTransform(r, rotation);
mAppTransition.registerListenerLocked(new WindowManagerInternal.AppTransitionListener() {
void done() {
- r.clearFixedRotationTransform();
+ r.finishFixedRotationTransform();
mAppTransition.unregisterListener(this);
}
@@ -1529,7 +1536,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (token != mFixedRotationLaunchingApp) {
return false;
}
- if (updateOrientation()) {
+ // Update directly because the app which will change the orientation of display is ready.
+ if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) {
sendNewConfiguration();
return true;
}
@@ -1575,7 +1583,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* @param oldRotation the rotation we are coming from.
* @param rotation the rotation to apply.
*/
- void applyRotationLocked(final int oldRotation, final int rotation) {
+ private void applyRotation(final int oldRotation, final int rotation) {
mDisplayRotation.applyCurrentRotation(rotation);
final boolean rotateSeamlessly = mDisplayRotation.isRotatingSeamlessly();
final Transaction transaction = getPendingTransaction();
@@ -4016,6 +4024,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mTmpWindow = null;
mTmpInitial = initial;
+ // Used to indicate that we have processed the IME window.
+ mTmpWindowsBehindIme = false;
+
// First perform layout of any root windows (not attached to another window).
forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
@@ -4420,6 +4431,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
position = findPositionForStack(position, stack, true /* adding */);
super.addChild(stack, position);
+ mAtmService.updateSleepIfNeededLocked();
// The reparenting case is handled in WindowContainer.
if (!stack.mReparenting) {
@@ -4431,6 +4443,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
protected void removeChild(ActivityStack stack) {
super.removeChild(stack);
mDisplayContent.onStackRemoved(stack);
+ mAtmService.updateSleepIfNeededLocked();
removeStackReferenceIfNeeded(stack);
}
@@ -5636,7 +5649,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
void addStack(ActivityStack stack, int position) {
setStackOnDisplay(stack, position);
positionStackAt(stack, position);
- mAtmService.updateSleepIfNeededLocked();
}
void addStackReferenceIfNeeded(ActivityStack stack) {
@@ -5655,7 +5667,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mPreferredTopFocusableStack = null;
}
releaseSelfIfNeeded();
- mAtmService.updateSleepIfNeededLocked();
onStackOrderChanged(stack);
}
@@ -6481,15 +6492,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@Override
public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- final int currRotation =
- getRequestedOverrideConfiguration().windowConfiguration.getRotation();
- if (currRotation != ROTATION_UNDEFINED
- && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
- applyRotationLocked(currRotation,
- overrideConfiguration.windowConfiguration.getRotation());
- }
- mCurrentOverrideConfigurationChanges =
- getRequestedOverrideConfiguration().diff(overrideConfiguration);
+ final Configuration currOverrideConfig = getRequestedOverrideConfiguration();
+ final int currRotation = currOverrideConfig.windowConfiguration.getRotation();
+ final int overrideRotation = overrideConfiguration.windowConfiguration.getRotation();
+ if (currRotation != ROTATION_UNDEFINED && currRotation != overrideRotation) {
+ if (mFixedRotationLaunchingApp != null) {
+ mFixedRotationLaunchingApp.clearFixedRotationTransform(
+ () -> applyRotation(currRotation, overrideRotation));
+ // Clear the record because the display will sync to current rotation.
+ mFixedRotationLaunchingApp = null;
+ } else {
+ applyRotation(currRotation, overrideRotation);
+ }
+ }
+ mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);
super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
mCurrentOverrideConfigurationChanges = 0;
mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4da4a79cfd83..f593393eecfb 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -29,7 +29,6 @@ import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
-import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -1493,14 +1492,8 @@ public class DisplayPolicy {
*/
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
displayFrames.onBeginLayout();
- final InsetsState insetsState =
- mDisplayContent.getInsetsStateController().getRawInsetsState();
-
- // Reset the frame of IME so that the layout of windows above IME won't get influenced.
- // Once we layout the IME, frames will be set again on the source.
- insetsState.getSource(ITYPE_IME).setFrame(0, 0, 0, 0);
-
- updateInsetsStateForDisplayCutout(displayFrames, insetsState);
+ updateInsetsStateForDisplayCutout(displayFrames,
+ mDisplayContent.getInsetsStateController().getRawInsetsState());
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 60b817c13236..af89a05bfa62 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -484,11 +484,8 @@ public class DisplayRotation {
prepareNormalRotationAnimation();
}
- // TODO(b/147469351): Remove the restriction.
- if (mDisplayContent.mFixedRotationLaunchingApp == null) {
- // Give a remote handler (system ui) some time to reposition things.
- startRemoteRotation(oldRotation, mRotation);
- }
+ // Give a remote handler (system ui) some time to reposition things.
+ startRemoteRotation(oldRotation, mRotation);
return true;
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 88cdd1781aee..18332b9484c0 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -62,7 +62,7 @@ final class InputMonitor {
// When true, need to call updateInputWindowsLw().
private boolean mUpdateInputWindowsNeeded = true;
private boolean mUpdateInputWindowsPending;
- private boolean mApplyImmediately;
+ private boolean mUpdateInputWindowsImmediately;
// Currently focused input window handle.
private InputWindowHandle mFocusedInputWindowHandle;
@@ -347,14 +347,20 @@ final class InputMonitor {
}
}
- void updateInputWindowsImmediately() {
+ /**
+ * Immediately update the input transaction and merge into the passing Transaction that could be
+ * collected and applied later.
+ */
+ void updateInputWindowsImmediately(SurfaceControl.Transaction t) {
mHandler.removeCallbacks(mUpdateInputWindows);
- mApplyImmediately = true;
+ mUpdateInputWindowsImmediately = true;
mUpdateInputWindows.run();
- mApplyImmediately = false;
+ mUpdateInputWindowsImmediately = false;
+ t.merge(mInputTransaction);
}
- /* Called when the current input focus changes.
+ /**
+ * Called when the current input focus changes.
* Layer assignment is assumed to be complete by the time this is called.
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
@@ -465,10 +471,7 @@ final class InputMonitor {
if (mAddWallpaperInputConsumerHandle) {
mWallpaperInputConsumer.show(mInputTransaction, 0);
}
-
- if (mApplyImmediately) {
- mInputTransaction.apply();
- } else {
+ if (!mUpdateInputWindowsImmediately) {
mDisplayContent.getPendingTransaction().merge(mInputTransaction);
mDisplayContent.scheduleAnimation();
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index ac6e75c717ff..fda70d14db2b 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -97,7 +97,8 @@ class InsetsPolicy {
private void updateHideNavInputEventReceiver() {
mPolicy.updateHideNavInputEventReceiver(!isHidden(ITYPE_NAVIGATION_BAR),
- mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH);
+ mFocusedWin != null
+ && mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH);
}
boolean isHidden(@InternalInsetsType int type) {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a4bdfb351c1f..04454a5b33ec 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -88,8 +88,8 @@ class InsetsStateController {
final InsetsSourceProvider provider = target.getControllableInsetProvider();
final @InternalInsetsType int type = provider != null
? provider.getSource().getType() : ITYPE_INVALID;
- return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode(),
- target.isAlwaysOnTop());
+ return getInsetsForDispatchInner(type, target.getWindowingMode(), target.isAlwaysOnTop(),
+ isAboveIme(target));
}
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
@@ -97,13 +97,24 @@ class InsetsStateController {
final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
final @WindowingMode int windowingMode = token != null
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
- final boolean alwaysOnTop = token != null
- ? token.isAlwaysOnTop() : false;
- return getInsetsForTypeAndWindowingMode(type, windowingMode, alwaysOnTop);
+ final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
+ return getInsetsForDispatchInner(type, windowingMode, alwaysOnTop, isAboveIme(token));
+ }
+
+ private boolean isAboveIme(WindowContainer target) {
+ final WindowState imeWindow = mDisplayContent.mInputMethodWindow;
+ if (target == null || imeWindow == null) {
+ return false;
+ }
+ if (target instanceof WindowState) {
+ final WindowState win = (WindowState) target;
+ return win.needsRelativeLayeringToIme() || !win.mBehindIme;
+ }
+ return false;
}
private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
- switch(type) {
+ switch (type) {
case TYPE_STATUS_BAR:
return ITYPE_STATUS_BAR;
case TYPE_NAVIGATION_BAR:
@@ -116,8 +127,8 @@ class InsetsStateController {
}
/** @see #getInsetsForDispatch */
- private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
- @WindowingMode int windowingMode, boolean isAlwaysOnTop) {
+ private InsetsState getInsetsForDispatchInner(@InternalInsetsType int type,
+ @WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
InsetsState state = mState;
if (type != ITYPE_INVALID) {
@@ -158,6 +169,11 @@ class InsetsStateController {
state.removeSource(ITYPE_NAVIGATION_BAR);
}
+ if (aboveIme) {
+ state = new InsetsState(state);
+ state.removeSource(ITYPE_IME);
+ }
+
return state;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 3e5cb50d6101..a30b70de267d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -667,7 +667,7 @@ public class RecentsAnimationController implements DeathRecipient {
mTargetActivityRecord.token);
}
if (mTargetActivityRecord.hasFixedRotationTransform()) {
- mTargetActivityRecord.clearFixedRotationTransform();
+ mTargetActivityRecord.finishFixedRotationTransform();
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b2920ee1d4aa..6e56bf4dafd7 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2852,7 +2852,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @param candidateTask The possible task the activity might be put in.
* @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
*/
- private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
+ @VisibleForTesting
+ ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
@Nullable Task candidateTask, @Nullable ActivityOptions options,
@Nullable LaunchParamsController.LaunchParams launchParams) {
final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
@@ -2873,6 +2874,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (attachedDisplayId == INVALID_DISPLAY || attachedDisplayId == displayId) {
return candidateTask.getStack();
}
+ // Or the candidate task is already a root task that can be reused by reparenting
+ // it to the target display.
+ if (candidateTask.isRootTask()) {
+ final ActivityStack stack = candidateTask.getStack();
+ displayContent.moveStackToDisplay(stack, true /* onTop */);
+ return stack;
+ }
}
int windowingMode;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f19c10637c9b..7a41ea57610d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4111,8 +4111,7 @@ class Task extends WindowContainer<WindowContainer> {
return true;
}
- // Called on Binder death.
- void taskOrganizerDied() {
+ void taskOrganizerUnregistered() {
mTaskOrganizer = null;
mLastTaskOrganizerWindowingMode = -1;
onTaskOrganizerChanged();
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 05b721b8ee81..4382e9d578ad 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -34,6 +34,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.util.SparseArray;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.IWindowContainer;
@@ -42,6 +43,7 @@ import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.WeakHashMap;
@@ -51,6 +53,7 @@ import java.util.WeakHashMap;
*/
class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
+ private static final LinkedList<TaskOrganizerState> EMPTY_LIST = new LinkedList<>();
/**
* Masks specifying which configurations are important to report back to an organizer when
@@ -73,32 +76,20 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
@Override
public void binderDied() {
synchronized (mGlobalLock) {
- final TaskOrganizerState state =
- mTaskOrganizerStates.get(mTaskOrganizer.asBinder());
- state.releaseTasks();
- mTaskOrganizerStates.remove(mTaskOrganizer.asBinder());
- if (mTaskOrganizersForWindowingMode.get(mWindowingMode) == mTaskOrganizer) {
- mTaskOrganizersForWindowingMode.remove(mWindowingMode);
- }
+ final TaskOrganizerState state = mTaskOrganizerStates.remove(
+ mTaskOrganizer.asBinder());
+ state.dispose();
}
}
};
- class TaskOrganizerState {
- ITaskOrganizer mOrganizer;
- DeathRecipient mDeathRecipient;
- int mWindowingMode;
-
- ArrayList<Task> mOrganizedTasks = new ArrayList<>();
-
- // Save the TaskOrganizer which we replaced registration for
- // so it can be re-registered if we unregister.
- TaskOrganizerState mReplacementFor;
- boolean mDisposed = false;
+ private class TaskOrganizerState {
+ private final ITaskOrganizer mOrganizer;
+ private final DeathRecipient mDeathRecipient;
+ private final int mWindowingMode;
+ private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
-
- TaskOrganizerState(ITaskOrganizer organizer, int windowingMode,
- @Nullable TaskOrganizerState replacing) {
+ TaskOrganizerState(ITaskOrganizer organizer, int windowingMode) {
mOrganizer = organizer;
mDeathRecipient = new DeathRecipient(organizer, windowingMode);
try {
@@ -107,7 +98,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
Slog.e(TAG, "TaskOrganizer failed to register death recipient");
}
mWindowingMode = windowingMode;
- mReplacementFor = replacing;
}
void addTask(Task t) {
@@ -129,35 +119,26 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void dispose() {
- mDisposed = true;
releaseTasks();
- handleReplacement();
+ mTaskOrganizersForWindowingMode.get(mWindowingMode).remove(this);
}
- void releaseTasks() {
+ private void releaseTasks() {
for (int i = mOrganizedTasks.size() - 1; i >= 0; i--) {
final Task t = mOrganizedTasks.get(i);
- t.taskOrganizerDied();
removeTask(t);
- }
- }
-
- void handleReplacement() {
- if (mReplacementFor != null && !mReplacementFor.mDisposed) {
- mTaskOrganizersForWindowingMode.put(mWindowingMode, mReplacementFor);
+ t.taskOrganizerUnregistered();
}
}
void unlinkDeath() {
- mDisposed = true;
mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
}
- };
-
-
- final HashMap<Integer, TaskOrganizerState> mTaskOrganizersForWindowingMode = new HashMap();
- final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap();
+ }
+ private final SparseArray<LinkedList<TaskOrganizerState>> mTaskOrganizersForWindowingMode =
+ new SparseArray<>();
+ private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
@@ -196,11 +177,17 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
Slog.w(TAG, "Task organizer already exists for windowing mode: "
+ windowingMode);
}
- final TaskOrganizerState previousState =
- mTaskOrganizersForWindowingMode.get(windowingMode);
- final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode,
- previousState);
- mTaskOrganizersForWindowingMode.put(windowingMode, state);
+
+ LinkedList<TaskOrganizerState> states;
+ if (mTaskOrganizersForWindowingMode.contains(windowingMode)) {
+ states = mTaskOrganizersForWindowingMode.get(windowingMode);
+ } else {
+ states = new LinkedList<>();
+ mTaskOrganizersForWindowingMode.put(windowingMode, states);
+ }
+ final TaskOrganizerState previousState = states.peekLast();
+ final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode);
+ states.add(state);
mTaskOrganizerStates.put(organizer.asBinder(), state);
if (previousState == null) {
@@ -221,16 +208,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
@Override
public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
+ final TaskOrganizerState state = mTaskOrganizerStates.remove(organizer.asBinder());
state.unlinkDeath();
- if (mTaskOrganizersForWindowingMode.get(state.mWindowingMode) == state) {
- mTaskOrganizersForWindowingMode.remove(state.mWindowingMode);
- }
state.dispose();
}
ITaskOrganizer getTaskOrganizer(int windowingMode) {
- final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode);
+ final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode,
+ EMPTY_LIST).peekLast();
if (state == null) {
return null;
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f046e8adc478..be0d6f8a0b9f 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -268,8 +268,9 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDisplayContent.getDisplayRotation().pause();
// Notify InputMonitor to take mDragWindowHandle.
- mDisplayContent.getInputMonitor().updateInputWindowsImmediately();
- new SurfaceControl.Transaction().syncInputWindows().apply(true);
+ final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
+ mDisplayContent.getInputMonitor().updateInputWindowsImmediately(t);
+ t.syncInputWindows().apply();
final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 23ba528b6aee..075772566d56 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7746,19 +7746,23 @@ public class WindowManagerService extends IWindowManager.Stub
public void syncInputTransactions() {
waitForAnimationsToComplete();
+ // Collect all input transactions from all displays to make sure we could sync all input
+ // windows at same time.
+ final SurfaceControl.Transaction t = mTransactionFactory.get();
synchronized (mGlobalLock) {
mWindowPlacerLocked.performSurfacePlacementIfScheduled();
mRoot.forAllDisplays(displayContent ->
- displayContent.getInputMonitor().updateInputWindowsImmediately());
+ displayContent.getInputMonitor().updateInputWindowsImmediately(t));
}
- mTransactionFactory.get().syncInputWindows().apply(true);
+ t.syncInputWindows().apply();
}
private void waitForAnimationsToComplete() {
synchronized (mGlobalLock) {
long timeoutRemaining = ANIMATION_COMPLETED_TIMEOUT_MS;
- while (mRoot.isAnimating(TRANSITION | CHILDREN) && timeoutRemaining > 0) {
+ while ((mAnimator.isAnimationScheduled()
+ || mRoot.isAnimating(TRANSITION | CHILDREN)) && timeoutRemaining > 0) {
long startTime = System.currentTimeMillis();
try {
mGlobalLock.wait(timeoutRemaining);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0338cc3096ea..c4d700c9aca3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -608,6 +608,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
boolean mSeamlesslyRotated = false;
/**
+ * Indicates if this window is behind IME. Only windows behind IME can get insets from IME.
+ */
+ boolean mBehindIme = false;
+
+ /**
* Surface insets from the previous call to relayout(), used to track
* if we are changing the Surface insets.
*/
@@ -2270,9 +2275,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return false;
}
- if (PixelFormat.formatHasAlpha(mAttrs.format) && mAttrs.alpha == 0) {
- // Support legacy use cases where completely transparent windows can still be ime target
- // with FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
+ if (PixelFormat.formatHasAlpha(mAttrs.format)) {
+ // Support legacy use cases where transparent windows can still be ime target with
+ // FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
// Certain apps listen for IME insets using transparent windows and ADJUST_NOTHING to
// manually synchronize app content to IME animation b/144619551.
// TODO(b/145812508): remove this once new focus management is complete b/141738570
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 850c36238513..3c2b6ec9711d 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -480,26 +480,42 @@ class WindowToken extends WindowContainer<WindowState> {
}
/**
- * Clears the transformation and continue updating the orientation change of display. Only the
- * state owner can clear the transform state.
+ * Finishes the transform and continue updating the orientation change of display. Only the
+ * state owner can finish the transform state.
*/
- void clearFixedRotationTransform() {
+ void finishFixedRotationTransform() {
+ if (mFixedRotationTransformState == null || mFixedRotationTransformState.mOwner != this) {
+ return;
+ }
+ final boolean changed =
+ mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(this);
+ // If it is not the launching app or the display is not rotated, make sure the transform is
+ // cleared and the configuration is restored from parent.
+ if (!changed) {
+ clearFixedRotationTransform(null /* applyDisplayRotation */);
+ onConfigurationChanged(getParent().getConfiguration());
+ }
+ }
+
+ /**
+ * Clears the transform and apply display rotation if the action is given. The caller needs to
+ * refresh the configuration of this container after this method call.
+ */
+ void clearFixedRotationTransform(Runnable applyDisplayRotation) {
final FixedRotationTransformState state = mFixedRotationTransformState;
- if (state == null || state.mOwner != this) {
+ if (state == null) {
return;
}
+
state.resetTransform();
// Clear the flag so if the display will be updated to the same orientation, the transform
- // won't take effect. The state is cleared at the end, because it is used to indicate that
- // other windows can use seamless rotation when applying rotation to display.
+ // won't take effect.
state.mIsTransforming = false;
- final boolean changed =
- mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(this);
- // If it is not the launching app or the display is not rotated, make sure the merged
- // override configuration is restored from parent.
- if (!changed) {
- onMergedOverrideConfigurationChanged();
+ if (applyDisplayRotation != null) {
+ applyDisplayRotation.run();
}
+ // The state is cleared at the end, because it is used to indicate that other windows can
+ // use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
state.mAssociatedTokens.get(i).mFixedRotationTransformState = null;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e3f9ae8969b3..9bc5d34c11af 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -206,7 +206,7 @@ public:
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
status_t pilferPointers(const sp<IBinder>& token);
- void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
+ void displayRemoved(JNIEnv* env, int32_t displayId);
void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
void setFocusedDisplay(JNIEnv* env, int32_t displayId);
void setInputDispatchMode(bool enabled, bool frozen);
@@ -771,55 +771,10 @@ void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration
}
}
-void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray,
- int32_t displayId) {
- std::vector<sp<InputWindowHandle> > windowHandles;
-
- if (windowHandleObjArray) {
- jsize length = env->GetArrayLength(windowHandleObjArray);
- for (jsize i = 0; i < length; i++) {
- jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
- if (! windowHandleObj) {
- break; // found null element indicating end of used portion of the array
- }
-
- sp<InputWindowHandle> windowHandle =
- android_view_InputWindowHandle_getHandle(env, windowHandleObj);
- if (windowHandle != nullptr) {
- windowHandles.push_back(windowHandle);
- }
- env->DeleteLocalRef(windowHandleObj);
- }
- }
-
- mInputManager->getDispatcher()->setInputWindows(windowHandles, displayId);
-
- // Do this after the dispatcher has updated the window handle state.
- bool newPointerGesturesEnabled = true;
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- const sp<InputWindowHandle>& windowHandle = windowHandles[i];
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
- if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
- & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
- newPointerGesturesEnabled = false;
- }
- }
-
- bool pointerGesturesEnabledChanged = false;
- { // acquire lock
- AutoMutex _l(mLock);
-
- if (mLocked.pointerGesturesEnabled != newPointerGesturesEnabled) {
- mLocked.pointerGesturesEnabled = newPointerGesturesEnabled;
- pointerGesturesEnabledChanged = true;
- }
- } // release lock
-
- if (pointerGesturesEnabledChanged) {
- mInputManager->getReader()->requestRefreshConfiguration(
- InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT);
- }
+void NativeInputManager::displayRemoved(JNIEnv* env, int32_t displayId) {
+ // Set an empty list to remove all handles from the specific display.
+ std::vector<sp<InputWindowHandle>> windowHandles;
+ mInputManager->getDispatcher()->setInputWindows({{displayId, windowHandles}});
}
void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
@@ -1567,11 +1522,10 @@ static void nativeToggleCapsLock(JNIEnv* env, jclass /* clazz */,
im->getInputManager()->getReader()->toggleCapsLockState(deviceId);
}
-static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,
- jlong ptr, jobjectArray windowHandleObjArray, jint displayId) {
+static void nativeDisplayRemoved(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- im->setInputWindows(env, windowHandleObjArray, displayId);
+ im->displayRemoved(env, displayId);
}
static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
@@ -1815,8 +1769,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"nativeVerifyInputEvent", "(JLandroid/view/InputEvent;)Landroid/view/VerifiedInputEvent;",
(void*)nativeVerifyInputEvent},
{"nativeToggleCapsLock", "(JI)V", (void*)nativeToggleCapsLock},
- {"nativeSetInputWindows", "(J[Landroid/view/InputWindowHandle;I)V",
- (void*)nativeSetInputWindows},
+ {"nativeDisplayRemoved", "(JI)V", (void*)nativeDisplayRemoved},
{"nativeSetFocusedApplication", "(JILandroid/view/InputApplicationHandle;)V",
(void*)nativeSetFocusedApplication},
{"nativeSetFocusedDisplay", "(JI)V", (void*)nativeSetFocusedDisplay},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 96cdbb300000..09fab3e29fe0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4434,6 +4434,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle);
}
if (isProfileOwner(adminReceiver, userHandle)) {
+ if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ false,
+ UserHandle.of(getProfileParentId(userHandle)));
+ }
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver,
userHandle, /* parent */ false);
clearProfileOwnerLocked(admin, userHandle);
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index acdb68142178..138f9829c088 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND;
@@ -104,6 +105,7 @@ public class CrossProfileAppsServiceImplRoboTest {
private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl =
new CrossProfileAppsServiceImpl(mContext, mInjector);
private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>();
+ private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>();
@Mock private PackageManagerInternal mPackageManagerInternal;
@Mock private IPackageManager mIPackageManager;
@@ -112,12 +114,18 @@ public class CrossProfileAppsServiceImplRoboTest {
@Before
public void initializeMocks() throws Exception {
MockitoAnnotations.initMocks(this);
+ initializeInstalledApplicationsMock();
mockCrossProfileAppInstalledAndEnabledOnEachProfile();
mockCrossProfileAppRequestsInteractAcrossProfiles();
mockCrossProfileAppRegistersBroadcastReceiver();
mockCrossProfileAppWhitelisted();
}
+ private void initializeInstalledApplicationsMock() {
+ when(mPackageManagerInternal.getInstalledApplications(anyInt(), anyInt(), eq(CALLING_UID)))
+ .thenAnswer(invocation -> installedApplications.get(invocation.getArgument(1)));
+ }
+
private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() {
// They are enabled by default, so we simply have to ensure that a package info with an
// application info is returned.
@@ -138,11 +146,14 @@ public class CrossProfileAppsServiceImplRoboTest {
when(mPackageManagerInternal.getPackage(uid))
.thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
.hideAsParsed()).hideAsFinal());
+ installedApplications.putIfAbsent(userId, new ArrayList<>());
+ installedApplications.get(userId).add(packageInfo.applicationInfo);
}
private PackageInfo buildTestPackageInfo() {
PackageInfo packageInfo = new PackageInfo();
packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME;
return packageInfo;
}
@@ -451,6 +462,13 @@ public class CrossProfileAppsServiceImplRoboTest {
.isTrue();
}
+ @Test
+ public void clearInteractAcrossProfilesAppOps() {
+ explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
+ mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps();
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT);
+ }
+
private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) {
explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 3ad905476190..d2925263125d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -64,10 +64,13 @@ import com.android.internal.statusbar.IStatusBarService;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.AdditionalMatchers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Random;
+
@SmallTest
public class BiometricServiceTest {
@@ -347,9 +350,19 @@ public class BiometricServiceTest {
}
@Test
- public void testAuthenticate_happyPathWithoutConfirmation() throws Exception {
+ public void testAuthenticate_happyPathWithoutConfirmation_strongBiometric() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+ testAuthenticate_happyPathWithoutConfirmation(true /* isStrongBiometric */);
+ }
+
+ @Test
+ public void testAuthenticate_happyPathWithoutConfirmation_weakBiometric() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_WEAK);
+ testAuthenticate_happyPathWithoutConfirmation(false /* isStrongBiometric */);
+ }
+ private void testAuthenticate_happyPathWithoutConfirmation(boolean isStrongBiometric)
+ throws Exception {
// Start testing the happy path
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
@@ -397,9 +410,11 @@ public class BiometricServiceTest {
anyLong() /* sessionId */);
// Hardware authenticated
+ final byte[] HAT = generateRandomHAT();
mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
false /* requireConfirmation */,
- new byte[69] /* HAT */);
+ HAT,
+ isStrongBiometric /* isStrongBiometric */);
waitForIdle();
// Waiting for SystemUI to send dismissed callback
assertEquals(mBiometricService.mCurrentAuthSession.mState,
@@ -413,7 +428,11 @@ public class BiometricServiceTest {
null /* credentialAttestation */);
waitForIdle();
// HAT sent to keystore
- verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+ if (isStrongBiometric) {
+ verify(mBiometricService.mKeyStore).addAuthToken(AdditionalMatchers.aryEq(HAT));
+ } else {
+ verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+ }
// Send onAuthenticated to client
verify(mReceiver1).onAuthenticationSucceeded(
BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
@@ -447,16 +466,29 @@ public class BiometricServiceTest {
}
@Test
- public void testAuthenticate_happyPathWithConfirmation() throws Exception {
+ public void testAuthenticate_happyPathWithConfirmation_strongBiometric() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
+ testAuthenticate_happyPathWithConfirmation(true /* isStrongBiometric */);
+ }
+
+ @Test
+ public void testAuthenticate_happyPathWithConfirmation_weakBiometric() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK);
+ testAuthenticate_happyPathWithConfirmation(false /* isStrongBiometric */);
+ }
+
+ private void testAuthenticate_happyPathWithConfirmation(boolean isStrongBiometric)
+ throws Exception {
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */, null /* authenticators */);
// Test authentication succeeded goes to PENDING_CONFIRMATION and that the HAT is not
// sent to KeyStore yet
+ final byte[] HAT = generateRandomHAT();
mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
true /* requireConfirmation */,
- new byte[69] /* HAT */);
+ HAT,
+ isStrongBiometric /* isStrongBiometric */);
waitForIdle();
// Waiting for SystemUI to send confirmation callback
assertEquals(mBiometricService.mCurrentAuthSession.mState,
@@ -468,7 +500,11 @@ public class BiometricServiceTest {
BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
null /* credentialAttestation */);
waitForIdle();
- verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+ if (isStrongBiometric) {
+ verify(mBiometricService.mKeyStore).addAuthToken(AdditionalMatchers.aryEq(HAT));
+ } else {
+ verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+ }
verify(mReceiver1).onAuthenticationSucceeded(
BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
}
@@ -909,7 +945,8 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
true /* requireConfirmation */,
- new byte[69] /* HAT */);
+ new byte[69] /* HAT */,
+ true /* isStrongBiometric */);
mBiometricService.mInternalReceiver.onDialogDismissed(
BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
waitForIdle();
@@ -927,6 +964,7 @@ public class BiometricServiceTest {
eq(BiometricAuthenticator.TYPE_FACE),
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
eq(0 /* vendorCode */));
+ verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
assertNull(mBiometricService.mCurrentAuthSession);
}
@@ -1238,20 +1276,6 @@ public class BiometricServiceTest {
mFingerprintAuthenticator);
}
- @Test(expected = IllegalStateException.class)
- public void testRegistrationWithUnsupportedStrength_throwsIllegalStateException()
- throws Exception {
- mBiometricService = new BiometricService(mContext, mInjector);
- mBiometricService.onStart();
-
- // Only STRONG and WEAK are supported. Let's enforce that CONVENIENCE cannot be
- // registered. If there is a compelling reason, we can remove this constraint.
- mBiometricService.mImpl.registerAuthenticator(
- 0 /* id */, 2 /* modality */,
- Authenticators.BIOMETRIC_CONVENIENCE /* strength */,
- mFingerprintAuthenticator);
- }
-
@Test(expected = IllegalArgumentException.class)
public void testRegistrationWithNullAuthenticator_throwsIllegalArgumentException()
throws Exception {
@@ -1508,4 +1532,13 @@ public class BiometricServiceTest {
private static void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
+
+ private byte[] generateRandomHAT() {
+ byte[] HAT = new byte[69];
+ Random random = new Random();
+ random.nextBytes(HAT);
+ return HAT;
+ }
+
+
}
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/Android.bp b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/Android.bp
new file mode 100644
index 000000000000..eb1a2921136d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/Android.bp
@@ -0,0 +1,37 @@
+android_test {
+ name: "TunerResourceManagerTests",
+
+ // Include all test java files.
+ srcs: [
+ "*.java",
+ ],
+
+ static_libs: [
+ "frameworks-base-testutils",
+ "services.core",
+ "services.devicepolicy",
+ "guava",
+ "androidx.test.core",
+ "androidx.test.ext.truth",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "truth-prebuilt",
+ "testables",
+ "testng",
+ "servicestests-utils",
+ "service-permission",
+
+ ],
+
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ platform_apis: true,
+ test_suites: ["general-tests", "device-tests"],
+ compile_multilib: "both",
+} \ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidManifest.xml b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidManifest.xml
new file mode 100644
index 000000000000..9fa100d5a041
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.tv.tunerresourcemanager">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.tv.tunerresourcemanager"
+ android:label="Tuner Resource Manager Test Cases">
+ </instrumentation>
+</manifest>
+
+
+
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidTest.xml b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidTest.xml
new file mode 100644
index 000000000000..e3ea6a06a115
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Tests for Tuner Resource Manager">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="TunerResourceManagerTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="framework-base-presubmit" />
+ <option name="test-tag" value="TunerResourceManagerTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.server.tv.tunerresourcemanager" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration> \ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 155c6ddd4507..fcbd5072ae35 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -34,6 +34,7 @@ import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -54,6 +55,7 @@ import java.util.Map;
* Tests for {@link TunerResourceManagerService} class.
*/
@SmallTest
+@Presubmit
@RunWith(JUnit4.class)
public class TunerResourceManagerServiceTest {
private static final String TAG = "TunerResourceManagerServiceTest";
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
index ab5665ba99fc..2ff178eba3e1 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
@@ -18,6 +18,7 @@ package com.android.server.tv.tunerresourcemanager;
import static com.google.common.truth.Truth.assertThat;
import android.media.tv.TvInputService;
+import android.platform.test.annotations.Presubmit;
import android.util.Slog;
import androidx.test.filters.SmallTest;
@@ -36,6 +37,7 @@ import java.nio.charset.StandardCharsets;
* Tests for {@link UseCasePriorityHints} class.
*/
@SmallTest
+@Presubmit
@RunWith(JUnit4.class)
public class UseCasePriorityHintsTest {
private static final String TAG = "UseCasePriorityHintsTest";
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index bfb126f7052c..db7bce4c8753 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -19,10 +19,12 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -147,6 +149,61 @@ public class InsetsStateControllerTest extends WindowTestsBase {
}
@Test
+ public void testStripForDispatch_belowIme() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+
+ getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+ assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
+ }
+
+ @Test
+ public void testStripForDispatch_aboveIme() {
+ final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
+ }
+
+ @Test
+ public void testStripForDispatch_childWindow_altFocusable() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
+ child.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+
+ final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+
+ // IME cannot be the IME target.
+ ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+
+ getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+ assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
+ }
+
+ @Test
+ public void testStripForDispatch_childWindow_splitScreen() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
+ child.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+ child.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+
+ final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+
+ // IME cannot be the IME target.
+ ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+
+ getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+ assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
+ }
+
+ @Test
public void testImeForDispatch() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 406affc27b0a..f242989ab885 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -403,11 +403,11 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
wallpapers.get(0).getConfiguration().orientation);
// Wallpaper's transform state is controlled by home, so the invocation should be no-op.
- wallpaperWindowToken.clearFixedRotationTransform();
+ wallpaperWindowToken.finishFixedRotationTransform();
assertTrue(wallpaperWindowToken.hasFixedRotationTransform());
// Wallpaper's transform state should be cleared with home.
- homeActivity.clearFixedRotationTransform();
+ homeActivity.finishFixedRotationTransform();
assertFalse(wallpaperWindowToken.hasFixedRotationTransform());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 0ef25824df2a..e841e434ea82 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -788,6 +788,22 @@ public class RootActivityContainerTests extends ActivityTestsBase {
}
@Test
+ public void testGetValidLaunchStackOnDisplayWithCandidateRootTask() {
+ // Create a root task with an activity on secondary display.
+ final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mService, 300,
+ 600).build();
+ final Task task = new ActivityTestsBase.StackBuilder(mRootWindowContainer).setDisplay(
+ secondaryDisplay).build();
+ final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mService)
+ .setTask(task).build();
+
+ // Make sure the root task is valid and can be reused on default display.
+ final ActivityStack stack = mRootWindowContainer.getValidLaunchStackOnDisplay(
+ DEFAULT_DISPLAY, activity, task, null, null);
+ assertEquals(task, stack);
+ }
+
+ @Test
public void testSwitchUser_missingHomeRootTask() {
doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 85e4a1668a35..e95ccab38960 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -251,11 +251,9 @@ public class WindowStateTests extends WindowTestsBase {
// b/145812508: special legacy use-case for transparent/translucent windows.
appWindow.mAttrs.format = PixelFormat.TRANSPARENT;
- appWindow.mAttrs.alpha = 0;
assertTrue(appWindow.canBeImeTarget());
appWindow.mAttrs.format = PixelFormat.OPAQUE;
- appWindow.mAttrs.alpha = 1;
appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM;
assertFalse(appWindow.canBeImeTarget());
appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 0dca006f37c0..ffd25c08a8ba 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2633,6 +2633,7 @@ public abstract class ConnectionService extends Service {
* @param request Details about the incoming call.
* @return The {@code Connection} object to satisfy this call, or {@code null} to
* not handle the call.
+ * @hide
*/
public @Nullable Conference onCreateIncomingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2717,6 +2718,7 @@ public abstract class ConnectionService extends Service {
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The incoming connection request.
+ * @hide
*/
public void onCreateIncomingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2737,6 +2739,7 @@ public abstract class ConnectionService extends Service {
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The outgoing connection request.
+ * @hide
*/
public void onCreateOutgoingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2805,6 +2808,7 @@ public abstract class ConnectionService extends Service {
* @param request Details about the outgoing call.
* @return The {@code Conference} object to satisfy this call, or the result of an invocation
* of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
+ * @hide
*/
public @Nullable Conference onCreateOutgoingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 0b331744d922..7e02966779a2 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -442,16 +442,40 @@ public final class TelephonyPermissions {
// NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they
// will be denied access, even if they have another permission and AppOps bit if needed.
- // First, check if we can read the phone state and the SDK version is below R.
+ // First, check if the SDK version is below R
+ boolean preR = false;
try {
ApplicationInfo info = context.getPackageManager().getApplicationInfoAsUser(
callingPackage, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid()));
- if (info.targetSdkVersion <= Build.VERSION_CODES.Q) {
+ preR = info.targetSdkVersion <= Build.VERSION_CODES.Q;
+ } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+ }
+ if (preR) {
+ // SDK < R allows READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier privilege
+ try {
return checkReadPhoneState(
context, subId, pid, uid, callingPackage, callingFeatureId, message);
+ } catch (SecurityException readPhoneStateException) {
+ }
+ } else {
+ // SDK >= R allows READ_PRIVILEGED_PHONE_STATE or carrier privilege
+ try {
+ context.enforcePermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
+ // Skip checking for runtime permission since caller has privileged permission
+ return true;
+ } catch (SecurityException readPrivilegedPhoneStateException) {
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ try {
+ enforceCarrierPrivilege(context, subId, uid, message);
+ // Skip checking for runtime permission since caller has carrier privilege
+ return true;
+ } catch (SecurityException carrierPrivilegeException) {
+ }
+ }
}
- } catch (SecurityException | PackageManager.NameNotFoundException e) {
}
+
// Can be read with READ_SMS too.
try {
context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message);
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 1c92705b9422..d00049c1ebe5 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -314,6 +314,8 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements
/**
* Get the signal strength as dBm
+ *
+ * @return min(CDMA RSSI, EVDO RSSI) of the measured cell.
*/
@Override
public int getDbm() {
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 76d2df918423..9d55f109f751 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -145,6 +145,8 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P
/**
* Get the signal strength as dBm.
+ *
+ * @return the RSSI of the measured cell.
*/
@Override
public int getDbm() {
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 9be97b505a3f..f444b77b738e 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -767,7 +767,7 @@ public class AppLaunch extends InstrumentationTestCase {
.executeShellCommand(String.format("setprop iorapd.readahead.enable %b", enable));
getInstrumentation().getUiAutomation()
.executeShellCommand("start iorapd");
- sleep(2000); // give enough time for iorapd to start back up.
+ sleep(3000); // give enough time for iorapd to start back up.
if (enable) {
mIorapStatus = IorapStatus.ENABLED;
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
index 42908bef6178..35a6c26ec73f 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
@@ -167,7 +167,7 @@ public class DummyBlobData {
final byte[] actualBytes = new byte[lengthBytes];
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
- session.openWrite(0L, 0L))) {
+ session.openRead())) {
read(in, actualBytes, offsetBytes, lengthBytes);
}
@@ -190,7 +190,7 @@ public class DummyBlobData {
long offsetBytes, long lengthBytes) throws Exception {
final byte[] actualDigest;
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
- session.openWrite(0L, 0L))) {
+ session.openRead())) {
actualDigest = createSha256Digest(in, offsetBytes, lengthBytes);
}
diff --git a/tools/stats_log_api_gen/.clang-format b/tools/stats_log_api_gen/.clang-format
new file mode 100644
index 000000000000..cead3a079435
--- /dev/null
+++ b/tools/stats_log_api_gen/.clang-format
@@ -0,0 +1,17 @@
+BasedOnStyle: Google
+AllowShortIfStatementsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: false
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+AccessModifierOffset: -4
+IncludeCategories:
+ - Regex: '^"Log\.h"'
+ Priority: -1
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 47eb63e823e7..bf390935455a 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -15,11 +15,13 @@
*/
#include "Collation.h"
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include <stdio.h>
+
#include <map>
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+
namespace android {
namespace stats_log_api_gen {
@@ -32,55 +34,47 @@ using std::map;
const bool dbg = false;
-
//
// AtomDecl class
//
-AtomDecl::AtomDecl()
- :code(0),
- name()
-{
+AtomDecl::AtomDecl() : code(0), name() {
}
-AtomDecl::AtomDecl(const AtomDecl &that)
- : code(that.code),
- name(that.name),
- message(that.message),
- fields(that.fields),
- fieldNumberToAnnotations(that.fieldNumberToAnnotations),
- primaryFields(that.primaryFields),
- exclusiveField(that.exclusiveField),
- defaultState(that.defaultState),
- resetState(that.resetState),
- nested(that.nested),
- uidField(that.uidField),
- whitelisted(that.whitelisted) {}
-
-AtomDecl::AtomDecl(int c, const string& n, const string& m)
- :code(c),
- name(n),
- message(m)
-{
+AtomDecl::AtomDecl(const AtomDecl& that)
+ : code(that.code),
+ name(that.name),
+ message(that.message),
+ fields(that.fields),
+ fieldNumberToAnnotations(that.fieldNumberToAnnotations),
+ primaryFields(that.primaryFields),
+ exclusiveField(that.exclusiveField),
+ defaultState(that.defaultState),
+ resetState(that.resetState),
+ nested(that.nested),
+ uidField(that.uidField),
+ whitelisted(that.whitelisted),
+ truncateTimestamp(that.truncateTimestamp) {
}
-AtomDecl::~AtomDecl()
-{
+AtomDecl::AtomDecl(int c, const string& n, const string& m) : code(c), name(n), message(m) {
}
+AtomDecl::~AtomDecl() {
+}
/**
- * Print an error message for a FieldDescriptor, including the file name and line number.
+ * Print an error message for a FieldDescriptor, including the file name and
+ * line number.
*/
-static void
-print_error(const FieldDescriptor* field, const char* format, ...)
-{
+static void print_error(const FieldDescriptor* field, const char* format, ...) {
const Descriptor* message = field->containing_type();
const FileDescriptor* file = message->file();
SourceLocation loc;
if (field->GetSourceLocation(&loc)) {
- // TODO: this will work if we can figure out how to pass --include_source_info to protoc
+ // TODO: this will work if we can figure out how to pass
+ // --include_source_info to protoc
fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
} else {
fprintf(stderr, "%s: ", file->name().c_str());
@@ -88,15 +82,13 @@ print_error(const FieldDescriptor* field, const char* format, ...)
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
- va_end (args);
+ va_end(args);
}
/**
* Convert a protobuf type into a java type.
*/
-static java_type_t
-java_type(const FieldDescriptor* field)
-{
+static java_type_t java_type(const FieldDescriptor* field) {
int protoType = field->type();
switch (protoType) {
case FieldDescriptor::TYPE_DOUBLE:
@@ -121,12 +113,10 @@ java_type(const FieldDescriptor* field)
return JAVA_TYPE_UNKNOWN;
case FieldDescriptor::TYPE_MESSAGE:
// TODO: not the final package name
- if (field->message_type()->full_name() ==
- "android.os.statsd.AttributionNode") {
- return JAVA_TYPE_ATTRIBUTION_CHAIN;
- } else if (field->message_type()->full_name() ==
- "android.os.statsd.KeyValuePair") {
- return JAVA_TYPE_KEY_VALUE_PAIR;
+ if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
+ return JAVA_TYPE_ATTRIBUTION_CHAIN;
+ } else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
+ return JAVA_TYPE_KEY_VALUE_PAIR;
} else if (field->options().GetExtension(os::statsd::log_mode) ==
os::statsd::LogMode::MODE_BYTES) {
return JAVA_TYPE_BYTE_ARRAY;
@@ -155,307 +145,298 @@ java_type(const FieldDescriptor* field)
/**
* Gather the enums info.
*/
-void collate_enums(const EnumDescriptor &enumDescriptor, AtomField *atomField) {
+void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
for (int i = 0; i < enumDescriptor.value_count(); i++) {
atomField->enumValues[enumDescriptor.value(i)->number()] =
- enumDescriptor.value(i)->name().c_str();
+ enumDescriptor.value(i)->name().c_str();
}
}
static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
- const int annotationId, const AnnotationType annotationType,
- const AnnotationValue annotationValue) {
+ const int annotationId, const AnnotationType annotationType,
+ const AnnotationValue annotationValue) {
if (dbg) {
- printf(" Adding annotation to %s: [%d] = {id: %d, type: %d}\n",
- atomDecl->name.c_str(), fieldNumber, annotationId, annotationType);
+ printf(" Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(),
+ fieldNumber, annotationId, annotationType);
}
- atomDecl->fieldNumberToAnnotations[fieldNumber].insert(make_shared<Annotation>(
- annotationId, atomDecl->code, annotationType, annotationValue));
+ atomDecl->fieldNumberToAnnotations[fieldNumber].insert(
+ make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue));
}
-/**
- * Gather the info about an atom proto.
- */
-int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
- vector<java_type_t> *signature) {
-
- int errorCount = 0;
-
- // Build a sorted list of the fields. Descriptor has them in source file
- // order.
- map<int, const FieldDescriptor *> fields;
- for (int j = 0; j < atom->field_count(); j++) {
- const FieldDescriptor *field = atom->field(j);
- fields[field->number()] = field;
- }
-
- // Check that the parameters start at 1 and go up sequentially.
- int expectedNumber = 1;
- for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
- it != fields.end(); it++) {
- const int number = it->first;
- const FieldDescriptor *field = it->second;
- if (number != expectedNumber) {
- print_error(field,
- "Fields must be numbered consecutively starting at 1:"
- " '%s' is %d but should be %d\n",
- field->name().c_str(), number, expectedNumber);
- errorCount++;
- expectedNumber = number;
- continue;
- }
- expectedNumber++;
- }
-
- // Check that only allowed types are present. Remove any invalid ones.
- for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
- it != fields.end(); it++) {
- const FieldDescriptor *field = it->second;
- bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
- os::statsd::LogMode::MODE_BYTES;
-
- java_type_t javaType = java_type(field);
-
- if (javaType == JAVA_TYPE_UNKNOWN) {
- print_error(field, "Unkown type for field: %s\n", field->name().c_str());
- errorCount++;
- continue;
- } else if (javaType == JAVA_TYPE_OBJECT &&
- atomDecl->code < PULL_ATOM_START_ID) {
- // Allow attribution chain, but only at position 1.
- print_error(field,
- "Message type not allowed for field in pushed atoms: %s\n",
- field->name().c_str());
- errorCount++;
- continue;
- } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
- print_error(field, "Raw bytes type not allowed for field: %s\n",
- field->name().c_str());
- errorCount++;
- continue;
- }
-
- if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
- print_error(field, "Cannot mark field %s as bytes.\n",
- field->name().c_str());
- errorCount++;
- continue;
- }
-
- // Doubles are not supported yet.
- if (javaType == JAVA_TYPE_DOUBLE) {
- print_error(field, "Doubles are not supported in atoms. Please change field %s to float\n",
- field->name().c_str());
- errorCount++;
- continue;
- }
-
- if (field->is_repeated() &&
- !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
- print_error(field,
- "Repeated fields are not supported in atoms. Please make field %s not "
- "repeated.\n",
- field->name().c_str());
- errorCount++;
- continue;
- }
- }
-
- // Check that if there's an attribution chain, it's at position 1.
- for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
- it != fields.end(); it++) {
- int number = it->first;
- if (number != 1) {
- const FieldDescriptor *field = it->second;
- java_type_t javaType = java_type(field);
- if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- print_error(
- field,
- "AttributionChain fields must have field id 1, in message: '%s'\n",
- atom->name().c_str());
- errorCount++;
- }
- }
- }
-
- // Build the type signature and the atom data.
- for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
- it != fields.end(); it++) {
- const FieldDescriptor *field = it->second;
- java_type_t javaType = java_type(field);
- bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
- os::statsd::LogMode::MODE_BYTES;
-
- AtomField atField(field->name(), javaType);
- // Generate signature for pushed atoms
- if (atomDecl->code < PULL_ATOM_START_ID) {
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- signature->push_back(JAVA_TYPE_INT);
- } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
- signature->push_back(JAVA_TYPE_BYTE_ARRAY);
- } else {
- signature->push_back(javaType);
- }
- }
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- collate_enums(*field->enum_type(), &atField);
- }
- atomDecl->fields.push_back(atField);
+static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
+ const int fieldNumber, const java_type_t& javaType) {
+ int errorCount = 0;
if (field->options().HasExtension(os::statsd::state_field_option)) {
const int option = field->options().GetExtension(os::statsd::state_field_option).option();
if (option != STATE_OPTION_UNSET) {
- addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_OPTION,
- ANNOTATION_TYPE_INT, AnnotationValue(option));
+ addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_OPTION,
+ ANNOTATION_TYPE_INT, AnnotationValue(option));
}
if (option == STATE_OPTION_PRIMARY) {
- if (javaType == JAVA_TYPE_UNKNOWN ||
- javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
- javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
- print_error(
- field,
- "Invalid primary state field: '%s'\n",
- atom->name().c_str());
+ if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
+ javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
+ print_error(field, "Invalid primary state field: '%s'\n",
+ atomDecl->message.c_str());
errorCount++;
- continue;
}
- atomDecl->primaryFields.push_back(it->first);
-
+ atomDecl->primaryFields.push_back(fieldNumber);
}
if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) {
if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
- print_error(
- field,
- "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: '%s'\n",
- atom->name().c_str());
+ print_error(field,
+ "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: "
+ "'%s'\n",
+ atomDecl->message.c_str());
errorCount++;
- continue;
} else {
atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
}
}
if (option == STATE_OPTION_EXCLUSIVE) {
- if (javaType == JAVA_TYPE_UNKNOWN ||
- javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
- javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
- print_error(
- field,
- "Invalid exclusive state field: '%s'\n",
- atom->name().c_str());
+ if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
+ javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
+ print_error(field, "Invalid exclusive state field: '%s'\n",
+ atomDecl->message.c_str());
errorCount++;
- continue;
}
if (atomDecl->exclusiveField == 0) {
- atomDecl->exclusiveField = it->first;
+ atomDecl->exclusiveField = fieldNumber;
} else {
- print_error(
- field,
- "Cannot have more than one exclusive state field in an atom: '%s'\n",
- atom->name().c_str());
+ print_error(field,
+ "Cannot have more than one exclusive state field in an "
+ "atom: '%s'\n",
+ atomDecl->message.c_str());
errorCount++;
- continue;
}
if (field->options()
.GetExtension(os::statsd::state_field_option)
.has_default_state_value()) {
- const int defaultState =
- field->options().GetExtension(os::statsd::state_field_option)
- .default_state_value();
+ const int defaultState = field->options()
+ .GetExtension(os::statsd::state_field_option)
+ .default_state_value();
atomDecl->defaultState = defaultState;
- addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_DEFAULT_STATE,
- ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
+ addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
+ ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
}
- if (field->options().GetExtension(os::statsd::state_field_option)
- .has_reset_state_value()) {
- const int resetState = field->options()
+ if (field->options()
.GetExtension(os::statsd::state_field_option)
- .reset_state_value();
+ .has_reset_state_value()) {
+ const int resetState = field->options()
+ .GetExtension(os::statsd::state_field_option)
+ .reset_state_value();
atomDecl->resetState = resetState;
- addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_RESET_STATE,
- ANNOTATION_TYPE_INT, AnnotationValue(resetState));
+ addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_RESET_STATE,
+ ANNOTATION_TYPE_INT, AnnotationValue(resetState));
}
- if (field->options().GetExtension(os::statsd::state_field_option)
- .has_nested()) {
+ if (field->options().GetExtension(os::statsd::state_field_option).has_nested()) {
const bool nested =
field->options().GetExtension(os::statsd::state_field_option).nested();
atomDecl->nested = nested;
- addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_NESTED,
- ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
+ addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
+ ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
}
}
-
}
+
if (field->options().GetExtension(os::statsd::is_uid) == true) {
if (javaType != JAVA_TYPE_INT) {
- print_error(
- field,
- "is_uid annotation can only be applied to int32 fields: '%s'\n",
- atom->name().c_str());
+ print_error(field, "is_uid annotation can only be applied to int32 fields: '%s'\n",
+ atomDecl->message.c_str());
errorCount++;
- continue;
}
if (atomDecl->uidField == 0) {
- atomDecl->uidField = it->first;
+ atomDecl->uidField = fieldNumber;
- addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_IS_UID,
- ANNOTATION_TYPE_BOOL, AnnotationValue(true));
+ addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
+ ANNOTATION_TYPE_BOOL, AnnotationValue(true));
} else {
- print_error(
- field,
- "Cannot have more than one field in an atom with is_uid annotation: '%s'\n",
- atom->name().c_str());
+ print_error(field,
+ "Cannot have more than one field in an atom with is_uid "
+ "annotation: '%s'\n",
+ atomDecl->message.c_str());
errorCount++;
+ }
+ }
+
+ return errorCount;
+}
+
+/**
+ * Gather the info about an atom proto.
+ */
+int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature) {
+ int errorCount = 0;
+
+ // Build a sorted list of the fields. Descriptor has them in source file
+ // order.
+ map<int, const FieldDescriptor*> fields;
+ for (int j = 0; j < atom->field_count(); j++) {
+ const FieldDescriptor* field = atom->field(j);
+ fields[field->number()] = field;
+ }
+
+ // Check that the parameters start at 1 and go up sequentially.
+ int expectedNumber = 1;
+ for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+ it++) {
+ const int number = it->first;
+ const FieldDescriptor* field = it->second;
+ if (number != expectedNumber) {
+ print_error(field,
+ "Fields must be numbered consecutively starting at 1:"
+ " '%s' is %d but should be %d\n",
+ field->name().c_str(), number, expectedNumber);
+ errorCount++;
+ expectedNumber = number;
continue;
}
+ expectedNumber++;
}
- }
- return errorCount;
+ // Check that only allowed types are present. Remove any invalid ones.
+ for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+ it++) {
+ const FieldDescriptor* field = it->second;
+ bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+ os::statsd::LogMode::MODE_BYTES;
+
+ java_type_t javaType = java_type(field);
+
+ if (javaType == JAVA_TYPE_UNKNOWN) {
+ print_error(field, "Unknown type for field: %s\n", field->name().c_str());
+ errorCount++;
+ continue;
+ } else if (javaType == JAVA_TYPE_OBJECT && atomDecl->code < PULL_ATOM_START_ID) {
+ // Allow attribution chain, but only at position 1.
+ print_error(field, "Message type not allowed for field in pushed atoms: %s\n",
+ field->name().c_str());
+ errorCount++;
+ continue;
+ } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
+ print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str());
+ errorCount++;
+ continue;
+ }
+
+ if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
+ print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str());
+ errorCount++;
+ continue;
+ }
+
+ // Doubles are not supported yet.
+ if (javaType == JAVA_TYPE_DOUBLE) {
+ print_error(field,
+ "Doubles are not supported in atoms. Please change field %s "
+ "to float\n",
+ field->name().c_str());
+ errorCount++;
+ continue;
+ }
+
+ if (field->is_repeated() &&
+ !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
+ print_error(field,
+ "Repeated fields are not supported in atoms. Please make "
+ "field %s not "
+ "repeated.\n",
+ field->name().c_str());
+ errorCount++;
+ continue;
+ }
+ }
+
+ // Check that if there's an attribution chain, it's at position 1.
+ for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+ it++) {
+ int number = it->first;
+ if (number != 1) {
+ const FieldDescriptor* field = it->second;
+ java_type_t javaType = java_type(field);
+ if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ print_error(field,
+ "AttributionChain fields must have field id 1, in message: '%s'\n",
+ atom->name().c_str());
+ errorCount++;
+ }
+ }
+ }
+
+ // Build the type signature and the atom data.
+ for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+ it++) {
+ const FieldDescriptor* field = it->second;
+ java_type_t javaType = java_type(field);
+ bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+ os::statsd::LogMode::MODE_BYTES;
+
+ AtomField atField(field->name(), javaType);
+
+ if (javaType == JAVA_TYPE_ENUM) {
+ // All enums are treated as ints when it comes to function signatures.
+ collate_enums(*field->enum_type(), &atField);
+ }
+
+ // Generate signature for pushed atoms
+ if (atomDecl->code < PULL_ATOM_START_ID) {
+ if (javaType == JAVA_TYPE_ENUM) {
+ // All enums are treated as ints when it comes to function signatures.
+ signature->push_back(JAVA_TYPE_INT);
+ } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
+ signature->push_back(JAVA_TYPE_BYTE_ARRAY);
+ } else {
+ signature->push_back(javaType);
+ }
+ }
+
+ atomDecl->fields.push_back(atField);
+
+ errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
+ }
+
+ return errorCount;
}
-// This function flattens the fields of the AttributionNode proto in an Atom proto and generates
-// the corresponding atom decl and signature.
-bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
- vector<java_type_t> *signature) {
+// This function flattens the fields of the AttributionNode proto in an Atom
+// proto and generates the corresponding atom decl and signature.
+bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl,
+ vector<java_type_t>* signature) {
// Build a sorted list of the fields. Descriptor has them in source file
// order.
- map<int, const FieldDescriptor *> fields;
+ map<int, const FieldDescriptor*> fields;
for (int j = 0; j < atom->field_count(); j++) {
- const FieldDescriptor *field = atom->field(j);
+ const FieldDescriptor* field = atom->field(j);
fields[field->number()] = field;
}
AtomDecl attributionDecl;
vector<java_type_t> attributionSignature;
- collate_atom(android::os::statsd::AttributionNode::descriptor(),
- &attributionDecl, &attributionSignature);
+ collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
+ &attributionSignature);
// Build the type signature and the atom data.
bool has_attribution_node = false;
- for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
- it != fields.end(); it++) {
- const FieldDescriptor *field = it->second;
+ for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+ it++) {
+ const FieldDescriptor* field = it->second;
java_type_t javaType = java_type(field);
if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- atomDecl->fields.insert(
- atomDecl->fields.end(),
- attributionDecl.fields.begin(), attributionDecl.fields.end());
- signature->insert(
- signature->end(),
- attributionSignature.begin(), attributionSignature.end());
+ atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(),
+ attributionDecl.fields.end());
+ signature->insert(signature->end(), attributionSignature.begin(),
+ attributionSignature.end());
has_attribution_node = true;
} else {
@@ -473,118 +454,129 @@ bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
return has_attribution_node;
}
-static void populateFieldNumberToAnnotations(
- const AtomDecl& atomDecl,
- FieldNumberToAnnotations* fieldNumberToAnnotations) {
+static void populateFieldNumberToAnnotations(const AtomDecl& atomDecl,
+ FieldNumberToAnnotations* fieldNumberToAnnotations) {
for (FieldNumberToAnnotations::const_iterator it = atomDecl.fieldNumberToAnnotations.begin();
- it != atomDecl.fieldNumberToAnnotations.end(); it++) {
+ it != atomDecl.fieldNumberToAnnotations.end(); it++) {
const int fieldNumber = it->first;
const set<shared_ptr<Annotation>>& insertAnnotationsSource = it->second;
set<shared_ptr<Annotation>>& insertAnnotationsTarget =
(*fieldNumberToAnnotations)[fieldNumber];
- insertAnnotationsTarget.insert(
- insertAnnotationsSource.begin(),
- insertAnnotationsSource.end());
+ insertAnnotationsTarget.insert(insertAnnotationsSource.begin(),
+ insertAnnotationsSource.end());
}
}
/**
* Gather the info about the atoms.
*/
-int collate_atoms(const Descriptor *descriptor, const string& moduleName, Atoms *atoms) {
- int errorCount = 0;
-
- int maxPushedAtomId = 2;
- for (int i = 0; i < descriptor->field_count(); i++) {
- const FieldDescriptor *atomField = descriptor->field(i);
-
- if (moduleName != DEFAULT_MODULE_NAME) {
- const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
- int j;
- for (j = 0; j < moduleCount; ++j) {
- const string atomModuleName = atomField->options().GetExtension(os::statsd::module, j);
- if (atomModuleName == moduleName) {
- break;
+int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) {
+ int errorCount = 0;
+
+ int maxPushedAtomId = 2;
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor* atomField = descriptor->field(i);
+
+ if (moduleName != DEFAULT_MODULE_NAME) {
+ const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
+ int j;
+ for (j = 0; j < moduleCount; ++j) {
+ const string atomModuleName =
+ atomField->options().GetExtension(os::statsd::module, j);
+ if (atomModuleName == moduleName) {
+ break;
+ }
}
- }
- // This atom is not in the module we're interested in; skip it.
- if (moduleCount == j) {
- if (dbg) {
- printf(" Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
+ // This atom is not in the module we're interested in; skip it.
+ if (moduleCount == j) {
+ if (dbg) {
+ printf(" Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
+ }
+ continue;
}
- continue;
}
- }
- if (dbg) {
- printf(" %s (%d)\n", atomField->name().c_str(), atomField->number());
- }
+ if (dbg) {
+ printf(" %s (%d)\n", atomField->name().c_str(), atomField->number());
+ }
- // StatsEvent only has one oneof, which contains only messages. Don't allow
- // other types.
- if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
- print_error(atomField,
- "Bad type for atom. StatsEvent can only have message type "
- "fields: %s\n",
- atomField->name().c_str());
- errorCount++;
- continue;
- }
+ // StatsEvent only has one oneof, which contains only messages. Don't allow
+ // other types.
+ if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
+ print_error(atomField,
+ "Bad type for atom. StatsEvent can only have message type "
+ "fields: %s\n",
+ atomField->name().c_str());
+ errorCount++;
+ continue;
+ }
- const Descriptor *atom = atomField->message_type();
- AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
+ const Descriptor* atom = atomField->message_type();
+ AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
- if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
- atomDecl.whitelisted = true;
- }
+ if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
+ atomDecl.whitelisted = true;
+ if (dbg) {
+ printf("%s is whitelisted\n", atomField->name().c_str());
+ }
+ }
- vector<java_type_t> signature;
- errorCount += collate_atom(atom, &atomDecl, &signature);
- if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
- print_error(atomField,
- "Cannot have a primary field without an exclusive field: %s\n",
- atomField->name().c_str());
- errorCount++;
- continue;
- }
+ if (atomDecl.code < PULL_ATOM_START_ID &&
+ atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
+ addAnnotationToAtomDecl(&atomDecl, ATOM_ID_FIELD_NUMBER,
+ ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
+ AnnotationValue(true));
+ if (dbg) {
+ printf("%s can have timestamp truncated\n", atomField->name().c_str());
+ }
+ }
- atoms->decls.insert(atomDecl);
- FieldNumberToAnnotations& fieldNumberToAnnotations = atoms->signatureInfoMap[signature];
- populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
+ vector<java_type_t> signature;
+ errorCount += collate_atom(atom, &atomDecl, &signature);
+ if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
+ print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
+ atomField->name().c_str());
+ errorCount++;
+ continue;
+ }
- AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
- vector<java_type_t> nonChainedSignature;
- if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
- atoms->non_chained_decls.insert(nonChainedAtomDecl);
- FieldNumberToAnnotations& fieldNumberToAnnotations =
- atoms->nonChainedSignatureInfoMap[nonChainedSignature];
+ atoms->decls.insert(atomDecl);
+ FieldNumberToAnnotations& fieldNumberToAnnotations = atoms->signatureInfoMap[signature];
populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
- }
- if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) {
- maxPushedAtomId = atomDecl.code;
+ AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
+ vector<java_type_t> nonChainedSignature;
+ if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
+ atoms->non_chained_decls.insert(nonChainedAtomDecl);
+ FieldNumberToAnnotations& fieldNumberToAnnotations =
+ atoms->nonChainedSignatureInfoMap[nonChainedSignature];
+ populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
+ }
+
+ if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) {
+ maxPushedAtomId = atomDecl.code;
+ }
}
- }
-
- atoms->maxPushedAtomId = maxPushedAtomId;
-
- if (dbg) {
- printf("signatures = [\n");
- for (map<vector<java_type_t>, FieldNumberToAnnotations>::const_iterator it =
- atoms->signatureInfoMap.begin();
- it != atoms->signatureInfoMap.end(); it++) {
- printf(" ");
- for (vector<java_type_t>::const_iterator jt = it->first.begin();
- jt != it->first.end(); jt++){
- printf(" %d", (int)*jt);
- }
- printf("\n");
+
+ atoms->maxPushedAtomId = maxPushedAtomId;
+
+ if (dbg) {
+ printf("signatures = [\n");
+ for (map<vector<java_type_t>, FieldNumberToAnnotations>::const_iterator it =
+ atoms->signatureInfoMap.begin();
+ it != atoms->signatureInfoMap.end(); it++) {
+ printf(" ");
+ for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
+ jt++) {
+ printf(" %d", (int)*jt);
+ }
+ printf("\n");
+ }
+ printf("]\n");
}
- printf("]\n");
- }
- return errorCount;
+ return errorCount;
}
} // namespace stats_log_api_gen
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index c6dad1d07d89..2aedb216b9c1 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -17,24 +17,24 @@
#ifndef ANDROID_STATS_LOG_API_GEN_COLLATION_H
#define ANDROID_STATS_LOG_API_GEN_COLLATION_H
-
#include <google/protobuf/descriptor.h>
-#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h"
+#include <map>
#include <set>
#include <vector>
-#include <map>
+
+#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h"
namespace android {
namespace stats_log_api_gen {
+using google::protobuf::Descriptor;
+using google::protobuf::FieldDescriptor;
using std::map;
using std::set;
using std::shared_ptr;
using std::string;
using std::vector;
-using google::protobuf::Descriptor;
-using google::protobuf::FieldDescriptor;
const int PULL_ATOM_START_ID = 10000;
@@ -52,26 +52,28 @@ const int STATE_OPTION_EXCLUSIVE = os::statsd::StateField::EXCLUSIVE_STATE;
const int STATE_OPTION_PRIMARY_FIELD_FIRST_UID = os::statsd::StateField::PRIMARY_FIELD_FIRST_UID;
const int STATE_OPTION_PRIMARY = os::statsd::StateField::PRIMARY_FIELD;
+const int ATOM_ID_FIELD_NUMBER = -1;
+
const string DEFAULT_MODULE_NAME = "DEFAULT";
/**
* The types for atom parameters.
*/
typedef enum {
- JAVA_TYPE_UNKNOWN = 0,
-
- JAVA_TYPE_ATTRIBUTION_CHAIN = 1,
- JAVA_TYPE_BOOLEAN = 2,
- JAVA_TYPE_INT = 3,
- JAVA_TYPE_LONG = 4,
- JAVA_TYPE_FLOAT = 5,
- JAVA_TYPE_DOUBLE = 6,
- JAVA_TYPE_STRING = 7,
- JAVA_TYPE_ENUM = 8,
- JAVA_TYPE_KEY_VALUE_PAIR = 9,
-
- JAVA_TYPE_OBJECT = -1,
- JAVA_TYPE_BYTE_ARRAY = -2,
+ JAVA_TYPE_UNKNOWN = 0,
+
+ JAVA_TYPE_ATTRIBUTION_CHAIN = 1,
+ JAVA_TYPE_BOOLEAN = 2,
+ JAVA_TYPE_INT = 3,
+ JAVA_TYPE_LONG = 4,
+ JAVA_TYPE_FLOAT = 5,
+ JAVA_TYPE_DOUBLE = 6,
+ JAVA_TYPE_STRING = 7,
+ JAVA_TYPE_ENUM = 8,
+ JAVA_TYPE_KEY_VALUE_PAIR = 9,
+
+ JAVA_TYPE_OBJECT = -1,
+ JAVA_TYPE_BYTE_ARRAY = -2,
} java_type_t;
enum AnnotationType {
@@ -84,8 +86,10 @@ union AnnotationValue {
int intValue;
bool boolValue;
- AnnotationValue(const int value): intValue(value) {}
- AnnotationValue(const bool value): boolValue(value) {}
+ AnnotationValue(const int value) : intValue(value) {
+ }
+ AnnotationValue(const bool value) : boolValue(value) {
+ }
};
struct Annotation {
@@ -95,16 +99,18 @@ struct Annotation {
AnnotationValue value;
inline Annotation(unsigned char annotationId, int atomId, AnnotationType type,
- AnnotationValue value):
- annotationId(annotationId), atomId(atomId), type(type), value(value) {}
- inline ~Annotation() {}
+ AnnotationValue value)
+ : annotationId(annotationId), atomId(atomId), type(type), value(value) {
+ }
+ inline ~Annotation() {
+ }
inline bool operator<(const Annotation& that) const {
return atomId == that.atomId ? annotationId < that.annotationId : atomId < that.atomId;
}
};
-using FieldNumberToAnnotations = map<int, set<shared_ptr<Annotation>>>;
+using FieldNumberToAnnotations = map<int, set<shared_ptr<Annotation>>>;
/**
* The name and type for an atom field.
@@ -113,16 +119,20 @@ struct AtomField {
string name;
java_type_t javaType;
- // If the field is of type enum, the following map contains the list of enum values.
+ // If the field is of type enum, the following map contains the list of enum
+ // values.
map<int /* numeric value */, string /* value name */> enumValues;
- inline AtomField() :name(), javaType(JAVA_TYPE_UNKNOWN) {}
- inline AtomField(const AtomField& that) :name(that.name),
- javaType(that.javaType),
- enumValues(that.enumValues) {}
+ inline AtomField() : name(), javaType(JAVA_TYPE_UNKNOWN) {
+ }
+ inline AtomField(const AtomField& that)
+ : name(that.name), javaType(that.javaType), enumValues(that.enumValues) {
+ }
- inline AtomField(string n, java_type_t jt) :name(n), javaType(jt) {}
- inline ~AtomField() {}
+ inline AtomField(string n, java_type_t jt) : name(n), javaType(jt) {
+ }
+ inline ~AtomField() {
+ }
};
/**
@@ -147,6 +157,8 @@ struct AtomDecl {
bool whitelisted = false;
+ bool truncateTimestamp = false;
+
AtomDecl();
AtomDecl(const AtomDecl& that);
AtomDecl(int code, const string& name, const string& message);
@@ -169,10 +181,9 @@ struct Atoms {
* Gather the information about the atoms. Returns the number of errors.
*/
int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms);
-int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, vector<java_type_t> *signature);
+int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature);
} // namespace stats_log_api_gen
} // namespace android
-
-#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
+#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
index 4f66f68e6d8c..69447527efc8 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.cpp
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -15,12 +15,13 @@
*/
#include "atoms_info_writer.h"
-#include "utils.h"
#include <map>
#include <set>
#include <vector>
+#include "utils.h"
+
namespace android {
namespace stats_log_api_gen {
@@ -42,32 +43,27 @@ static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) {
" const static std::set<int> "
"kTruncatingTimestampAtomBlackList;\n");
fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
- fprintf(out,
- " const static std::set<int> kAtomsWithAttributionChain;\n");
+ fprintf(out, " const static std::set<int> kAtomsWithAttributionChain;\n");
fprintf(out,
" const static std::map<int, StateAtomFieldOptions> "
"kStateAtomsFieldOptions;\n");
- fprintf(out,
- " const static std::set<int> kWhitelistedAtoms;\n");
+ fprintf(out, " const static std::set<int> kWhitelistedAtoms;\n");
fprintf(out, "};\n");
fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId);
-
}
static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
- std::set<string> kTruncatingAtomNames = {
- "mobile_radio_power_state_changed",
- "audio_state_changed",
- "call_state_changed",
- "phone_signal_strength_changed",
- "mobile_bytes_transfer_by_fg_bg",
- "mobile_bytes_transfer"
- };
+ std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
+ "audio_state_changed",
+ "call_state_changed",
+ "phone_signal_strength_changed",
+ "mobile_bytes_transfer_by_fg_bg",
+ "mobile_bytes_transfer"};
fprintf(out,
"const std::set<int> "
"AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
if (kTruncatingAtomNames.find(atom->name) != kTruncatingAtomNames.end()) {
const string constant = make_constant_name(atom->name);
fprintf(out, " %d, // %s\n", atom->code, constant.c_str());
@@ -77,10 +73,9 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
fprintf(out, "};\n");
fprintf(out, "\n");
- fprintf(out,
- "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ fprintf(out, "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -94,10 +89,9 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
fprintf(out, "};\n");
fprintf(out, "\n");
- fprintf(out,
- "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ fprintf(out, "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
if (atom->whitelisted) {
const string constant = make_constant_name(atom->name);
fprintf(out, " %d, // %s\n", atom->code, constant.c_str());
@@ -109,8 +103,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
fprintf(out, " std::map<int, int> uidField;\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
if (atom->uidField == 0) {
continue;
}
@@ -118,8 +112,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"\n // Adding uid field for atom "
"(%d)%s\n",
atom->code, atom->name.c_str());
- fprintf(out, " uidField[%d /* %s */] = %d;\n",
- atom->code, make_constant_name(atom->name).c_str(), atom->uidField);
+ fprintf(out, " uidField[%d /* %s */] = %d;\n", atom->code,
+ make_constant_name(atom->name).c_str(), atom->uidField);
}
fprintf(out, " return uidField;\n");
@@ -134,8 +128,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"getStateAtomFieldOptions() {\n");
fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
fprintf(out, " StateAtomFieldOptions* opt;\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
continue;
}
@@ -143,8 +137,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"\n // Adding primary and exclusive fields for atom "
"(%d)%s\n",
atom->code, atom->name.c_str());
- fprintf(out, " opt = &(options[%d /* %s */]);\n",
- atom->code, make_constant_name(atom->name).c_str());
+ fprintf(out, " opt = &(options[%d /* %s */]);\n", atom->code,
+ make_constant_name(atom->name).c_str());
fprintf(out, " opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size());
for (const auto& field : atom->primaryFields) {
fprintf(out, " opt->primaryFields.push_back(%d);\n", field);
@@ -174,7 +168,7 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"getStateAtomFieldOptions();\n");
}
-int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespaceStr) {
+int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -195,8 +189,8 @@ int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespa
return 0;
}
-int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr,
- const string& importHeader) {
+int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
+ const string& importHeader) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h
index d04e65a1b060..ffe9e439d7ff 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.h
+++ b/tools/stats_log_api_gen/atoms_info_writer.h
@@ -16,18 +16,18 @@
#pragma once
-#include "Collation.h"
-
#include <stdio.h>
#include <string.h>
+#include "Collation.h"
+
namespace android {
namespace stats_log_api_gen {
using namespace std;
int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
- const string& importHeader);
+ const string& importHeader);
int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 18508d2a6d4d..5a22b5c4cd6b 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -15,6 +15,7 @@
*/
#include "java_writer.h"
+
#include "java_writer_q.h"
#include "utils.h"
@@ -22,9 +23,8 @@ namespace android {
namespace stats_log_api_gen {
static int write_java_q_logger_class(
- FILE* out,
- const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
- const AtomDecl &attributionDecl) {
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+ const AtomDecl& attributionDecl) {
fprintf(out, "\n");
fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n");
fprintf(out, " private static class QLogger {\n");
@@ -34,29 +34,27 @@ static int write_java_q_logger_class(
// Print Q write methods.
fprintf(out, "\n");
fprintf(out, " // Write methods.\n");
- write_java_methods_q_schema(
- out, signatureInfoMap, attributionDecl, " ");
+ write_java_methods_q_schema(out, signatureInfoMap, attributionDecl, " ");
fprintf(out, " }\n");
return 0;
}
-static void write_annotations(
- FILE* out, int argIndex,
- const FieldNumberToAnnotations& fieldNumberToAnnotations) {
+static void write_annotations(FILE* out, int argIndex,
+ const FieldNumberToAnnotations& fieldNumberToAnnotations) {
auto it = fieldNumberToAnnotations.find(argIndex);
if (it == fieldNumberToAnnotations.end()) {
return;
}
const set<shared_ptr<Annotation>>& annotations = it->second;
- for (auto& annotation: annotations) {
+ for (auto& annotation : annotations) {
// TODO(b/151744250): Group annotations for same atoms.
// TODO(b/151786433): Write atom constant name instead of atom id literal.
fprintf(out, " if (code == %d) {\n", annotation->atomId);
- switch(annotation->type) {
+ switch (annotation->type) {
case ANNOTATION_TYPE_INT:
- // TODO(b/151776731): Check for reset state annotation and only include reset state
- // when field value == default state annotation value.
+ // TODO(b/151776731): Check for reset state annotation and only include
+ // reset state when field value == default state annotation value.
// TODO(b/151786433): Write annotation constant name instead of
// annotation id literal.
fprintf(out, " builder.addIntAnnotation((byte) %d, %d);\n",
@@ -66,8 +64,7 @@ static void write_annotations(
// TODO(b/151786433): Write annotation constant name instead of
// annotation id literal.
fprintf(out, " builder.addBooleanAnnotation((byte) %d, %s);\n",
- annotation->annotationId,
- annotation->value.boolValue ? "true" : "false");
+ annotation->annotationId, annotation->value.boolValue ? "true" : "false");
break;
default:
break;
@@ -77,24 +74,21 @@ static void write_annotations(
}
static int write_java_methods(
- FILE* out,
- const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
- const AtomDecl &attributionDecl,
- const bool supportQ
- ) {
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+ const AtomDecl& attributionDecl, const bool supportQ) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static void write(int code");
const vector<java_type_t>& signature = signatureInfoMapIt->first;
const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second;
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s",
- java_type_name(chainField.javaType), chainField.name.c_str());
+ fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
+ chainField.name.c_str());
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", android.util.SparseArray<Object> valueMap");
@@ -108,134 +102,134 @@ static int write_java_methods(
// Print method body.
string indent("");
if (supportQ) {
- // TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
+ // TODO(b/146235828): Use just SDK_INT check once it is incremented from
+ // Q.
fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
- fprintf(out, " || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n");
+ fprintf(out,
+ " || (Build.VERSION.SDK_INT == "
+ "Build.VERSION_CODES.Q\n");
fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
indent = " ";
}
// Start StatsEvent.Builder.
- fprintf(out, "%s final StatsEvent.Builder builder = StatsEvent.newBuilder();\n",
+ fprintf(out,
+ "%s final StatsEvent.Builder builder = "
+ "StatsEvent.newBuilder();\n",
indent.c_str());
// Write atom code.
fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations);
// Write the args.
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out, "%s builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n",
- indent.c_str(), argIndex, argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN:
- {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
+ fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out,
+ "%s builder.writeByteArray(null == arg%d ? new byte[0] : "
+ "arg%d);\n",
+ indent.c_str(), argIndex, argIndex);
+ break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
- fprintf(out, "%s null == %s ? new int[0] : %s,\n",
- indent.c_str(), uidName, uidName);
- fprintf(out, "%s null == %s ? new String[0] : %s);\n",
- indent.c_str(), tagName, tagName);
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR:
- fprintf(out, "\n");
- fprintf(out,
- "%s // Write KeyValuePairs.\n", indent.c_str());
- fprintf(out,
- "%s final int count = valueMap.size();\n", indent.c_str());
- fprintf(out,
- "%s android.util.SparseIntArray intMap = null;\n",
- indent.c_str());
- fprintf(out,
- "%s android.util.SparseLongArray longMap = null;\n",
- indent.c_str());
- fprintf(out,
- "%s android.util.SparseArray<String> stringMap = null;\n",
- indent.c_str());
- fprintf(out,
- "%s android.util.SparseArray<Float> floatMap = null;\n",
- indent.c_str());
- fprintf(out,
- "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
- fprintf(out,
- "%s final int key = valueMap.keyAt(i);\n", indent.c_str());
- fprintf(out,
- "%s final Object value = valueMap.valueAt(i);\n",
- indent.c_str());
- fprintf(out,
- "%s if (value instanceof Integer) {\n", indent.c_str());
- fprintf(out,
- "%s if (null == intMap) {\n", indent.c_str());
- fprintf(out,
- "%s intMap = new android.util.SparseIntArray();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s intMap.put(key, (Integer) value);\n", indent.c_str());
- fprintf(out,
- "%s } else if (value instanceof Long) {\n", indent.c_str());
- fprintf(out,
- "%s if (null == longMap) {\n", indent.c_str());
- fprintf(out,
- "%s longMap = new android.util.SparseLongArray();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s longMap.put(key, (Long) value);\n", indent.c_str());
- fprintf(out,
- "%s } else if (value instanceof String) {\n", indent.c_str());
- fprintf(out,
- "%s if (null == stringMap) {\n", indent.c_str());
- fprintf(out,
- "%s stringMap = new android.util.SparseArray<>();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s stringMap.put(key, (String) value);\n", indent.c_str());
- fprintf(out,
- "%s } else if (value instanceof Float) {\n", indent.c_str());
- fprintf(out,
- "%s if (null == floatMap) {\n", indent.c_str());
- fprintf(out,
- "%s floatMap = new android.util.SparseArray<>();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s floatMap.put(key, (Float) value);\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s builder.writeKeyValuePairs("
- "intMap, longMap, stringMap, floatMap);\n", indent.c_str());
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
+ fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
+ fprintf(out, "%s null == %s ? new int[0] : %s,\n",
+ indent.c_str(), uidName, uidName);
+ fprintf(out, "%s null == %s ? new String[0] : %s);\n",
+ indent.c_str(), tagName, tagName);
+ break;
+ }
+ case JAVA_TYPE_KEY_VALUE_PAIR:
+ fprintf(out, "\n");
+ fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
+ fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
+ fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
+ fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
+ indent.c_str());
+ fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
+ indent.c_str());
+ fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
+ fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s intMap = new "
+ "android.util.SparseIntArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s intMap.put(key, (Integer) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Long) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s longMap = new "
+ "android.util.SparseLongArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s longMap.put(key, (Long) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof String) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s stringMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s stringMap.put(key, (String) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Float) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s floatMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s floatMap.put(key, (Float) value);\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out,
+ "%s builder.writeKeyValuePairs("
+ "intMap, longMap, stringMap, floatMap);\n",
+ indent.c_str());
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE.
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
}
write_annotations(out, argIndex, fieldNumberToAnnotations);
argIndex++;
@@ -251,7 +245,7 @@ static int write_java_methods(
fprintf(out, " QLogger.write(code");
argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -266,20 +260,18 @@ static int write_java_methods(
argIndex++;
}
fprintf(out, ");\n");
- fprintf(out, " }\n"); // if
+ fprintf(out, " }\n"); // if
}
- fprintf(out, " }\n"); // method
+ fprintf(out, " }\n"); // method
fprintf(out, "\n");
}
return 0;
-
}
-int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& javaClass,
- const string& javaPackage, const bool supportQ,
- const bool supportWorkSource) {
+int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+ const string& javaClass, const string& javaPackage, const bool supportQ,
+ const bool supportWorkSource) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -308,17 +300,14 @@ int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attribut
// Print write methods.
fprintf(out, " // Write methods\n");
- errors += write_java_methods(
- out, atoms.signatureInfoMap, attributionDecl, supportQ);
- errors += write_java_non_chained_methods(
- out, atoms.nonChainedSignatureInfoMap);
+ errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+ errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
}
if (supportQ) {
- errors += write_java_q_logger_class(
- out, atoms.signatureInfoMap, attributionDecl);
+ errors += write_java_q_logger_class(out, atoms.signatureInfoMap, attributionDecl);
}
fprintf(out, "}\n");
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 4e1365e8dcce..8b3b50588efc 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -16,25 +16,23 @@
#pragma once
-#include "Collation.h"
+#include <stdio.h>
+#include <string.h>
#include <map>
#include <set>
#include <vector>
-#include <stdio.h>
-#include <string.h>
+#include "Collation.h"
namespace android {
namespace stats_log_api_gen {
using namespace std;
-int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& javaClass,
- const string& javaPackage, const bool supportQ,
+int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+ const string& javaClass, const string& javaPackage, const bool supportQ,
const bool supportWorkSource);
} // namespace stats_log_api_gen
} // namespace android
-
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index 329c25def441..7d225834aba2 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -15,6 +15,7 @@
*/
#include "java_writer_q.h"
+
#include "utils.h"
namespace android {
@@ -24,7 +25,8 @@ void write_java_q_logging_constants(FILE* out, const string& indent) {
fprintf(out, "%s// Payload limits.\n", indent.c_str());
fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str());
fprintf(out,
- "%sprivate static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n",
+ "%sprivate static final int MAX_EVENT_PAYLOAD = "
+ "LOGGER_ENTRY_MAX_PAYLOAD - 4;\n",
indent.c_str());
// Value types. Must match with EventLog.java and log.h.
@@ -37,36 +39,36 @@ void write_java_q_logging_constants(FILE* out, const string& indent) {
fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str());
// Size of each value type.
- // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value.
+ // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for
+ // the value.
fprintf(out, "\n");
fprintf(out, "%s// Size of each value type.\n", indent.c_str());
fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str());
fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str());
// Longs take 9 bytes, 1 for the type and 8 for the value.
fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str());
- // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length.
+ // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the
+ // length.
fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str());
fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str());
}
int write_java_methods_q_schema(
- FILE* out,
- const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
- const AtomDecl &attributionDecl,
- const string& indent) {
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+ const AtomDecl& attributionDecl, const string& indent) {
int requiredHelpers = 0;
for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
vector<java_type_t> signature = signatureInfoMapIt->first;
fprintf(out, "%spublic static void write(int code", indent.c_str());
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s",
- java_type_name(chainField.javaType), chainField.name.c_str());
+ fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
+ chainField.name.c_str());
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", android.util.SparseArray<Object> valueMap");
@@ -81,190 +83,174 @@ int write_java_methods_q_schema(
fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n",
indent.c_str());
fprintf(out,
- "%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n",
+ "%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + "
+ "INT_TYPE_SIZE;\n",
indent.c_str());
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- case JAVA_TYPE_INT:
- case JAVA_TYPE_FLOAT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_LONG:
- // Longs take 9 bytes, 1 for the type and 8 for the value.
- fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_STRING:
- // Strings take 5 metadata bytes + length of byte encoded string.
- fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
- fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex);
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out,
- "%s byte[] arg%dBytes = "
- "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- // Byte arrays take 5 metadata bytes + length of byte array.
- fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
- fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex);
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN:
- {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- // Null checks on the params.
- fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName);
- fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName,
- java_type_name(attributionDecl.fields.front().javaType));
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName);
- fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName,
- java_type_name(attributionDecl.fields.back().javaType));
- fprintf(out, "%s }\n", indent.c_str());
-
- // First check that the lengths of the uid and tag arrays are the same.
- fprintf(out, "%s if (%s.length != %s.length) {\n",
- indent.c_str(), uidName, tagName);
- fprintf(out, "%s return;\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
- fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n",
- indent.c_str(), tagName);
- fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
- indent.c_str(), argIndex, tagName, tagName);
- fprintf(out,
- "%s int str%dlen = "
- "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out,
- "%s attrSize += "
- "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n",
- indent.c_str(), argIndex);
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s needed += attrSize;\n", indent.c_str());
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR:
- {
- fprintf(out,
- "%s // Calculate bytes needed by Key Value Pairs.\n",
- indent.c_str());
- fprintf(out,
- "%s final int count = valueMap.size();\n", indent.c_str());
- fprintf(out,
- "%s android.util.SparseIntArray intMap = null;\n", indent.c_str());
- fprintf(out,
- "%s android.util.SparseLongArray longMap = null;\n", indent.c_str());
- fprintf(out,
- "%s android.util.SparseArray<String> stringMap = null;\n",
- indent.c_str());
- fprintf(out,
- "%s android.util.SparseArray<Float> floatMap = null;\n", indent.c_str());
- fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
- fprintf(out,
- "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
- fprintf(out,
- "%s final int key = valueMap.keyAt(i);\n", indent.c_str());
- fprintf(out,
- "%s final Object value = valueMap.valueAt(i);\n",
- indent.c_str());
- fprintf(out,
- "%s if (value instanceof Integer) {\n", indent.c_str());
- fprintf(out,
- "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
- indent.c_str());
- fprintf(out,
- "%s + INT_TYPE_SIZE + INT_TYPE_SIZE;\n",
- indent.c_str());
- fprintf(out,
- "%s if (null == intMap) {\n", indent.c_str());
- fprintf(out,
- "%s intMap = new android.util.SparseIntArray();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s intMap.put(key, (Integer) value);\n", indent.c_str());
- fprintf(out,
- "%s } else if (value instanceof Long) {\n", indent.c_str());
- fprintf(out,
- "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
- indent.c_str());
- fprintf(out,
- "%s + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n",
- indent.c_str());
- fprintf(out,
- "%s if (null == longMap) {\n", indent.c_str());
- fprintf(out,
- "%s longMap = new android.util.SparseLongArray();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s longMap.put(key, (Long) value);\n", indent.c_str());
- fprintf(out,
- "%s } else if (value instanceof String) {\n", indent.c_str());
- fprintf(out,
- "%s final String str = (value == null) ? \"\" : "
- "(String) value;\n",
- indent.c_str());
- fprintf(out,
- "%s final int len = "
- "str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
- indent.c_str());
- fprintf(out,
- "%s keyValuePairSize += LIST_TYPE_OVERHEAD + INT_TYPE_SIZE\n",
- indent.c_str());
- fprintf(out,
- "%s + STRING_TYPE_OVERHEAD + len;\n",
- indent.c_str());
- fprintf(out,
- "%s if (null == stringMap) {\n", indent.c_str());
- fprintf(out,
- "%s stringMap = new android.util.SparseArray<>();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s stringMap.put(key, str);\n", indent.c_str());
- fprintf(out,
- "%s } else if (value instanceof Float) {\n", indent.c_str());
- fprintf(out,
- "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
- indent.c_str());
- fprintf(out,
- "%s + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n",
- indent.c_str());
- fprintf(out,
- "%s if (null == floatMap) {\n", indent.c_str());
- fprintf(out,
- "%s floatMap = new android.util.SparseArray<>();\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s floatMap.put(key, (Float) value);\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out,
- "%s }\n", indent.c_str());
- fprintf(out, "%s needed += keyValuePairSize;\n", indent.c_str());
- break;
- }
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr, "Module logging does not yet support Object and Double.\n");
- return 1;
+ case JAVA_TYPE_BOOLEAN:
+ case JAVA_TYPE_INT:
+ case JAVA_TYPE_FLOAT:
+ case JAVA_TYPE_ENUM:
+ fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str());
+ break;
+ case JAVA_TYPE_LONG:
+ // Longs take 9 bytes, 1 for the type and 8 for the value.
+ fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str());
+ break;
+ case JAVA_TYPE_STRING:
+ // Strings take 5 metadata bytes + length of byte encoded string.
+ fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
+ fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex);
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out,
+ "%s byte[] arg%dBytes = "
+ "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
+ indent.c_str(), argIndex, argIndex);
+ fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+ indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ // Byte arrays take 5 metadata bytes + length of byte array.
+ fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
+ fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex);
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n",
+ indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+ // Null checks on the params.
+ fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName);
+ fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName,
+ java_type_name(attributionDecl.fields.front().javaType));
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName);
+ fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName,
+ java_type_name(attributionDecl.fields.back().javaType));
+ fprintf(out, "%s }\n", indent.c_str());
+
+ // First check that the lengths of the uid and tag arrays are the
+ // same.
+ fprintf(out, "%s if (%s.length != %s.length) {\n", indent.c_str(), uidName,
+ tagName);
+ fprintf(out, "%s return;\n", indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
+ fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(),
+ tagName);
+ fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
+ indent.c_str(), argIndex, tagName, tagName);
+ fprintf(out,
+ "%s int str%dlen = "
+ "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8)."
+ "length;\n",
+ indent.c_str(), argIndex, argIndex);
+ fprintf(out,
+ "%s attrSize += "
+ "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + "
+ "str%dlen;\n",
+ indent.c_str(), argIndex);
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s needed += attrSize;\n", indent.c_str());
+ break;
+ }
+ case JAVA_TYPE_KEY_VALUE_PAIR: {
+ fprintf(out, "%s // Calculate bytes needed by Key Value Pairs.\n",
+ indent.c_str());
+ fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
+ fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n",
+ indent.c_str());
+ fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
+ fprintf(out, "%s final int key = valueMap.keyAt(i);\n", indent.c_str());
+ fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
+ indent.c_str());
+ fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
+ fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
+ indent.c_str());
+ fprintf(out, "%s + INT_TYPE_SIZE + INT_TYPE_SIZE;\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
+ fprintf(out, "%s intMap = new android.util.SparseIntArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s intMap.put(key, (Integer) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Long) {\n", indent.c_str());
+ fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
+ indent.c_str());
+ fprintf(out, "%s + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s longMap = new "
+ "android.util.SparseLongArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s longMap.put(key, (Long) value);\n", indent.c_str());
+ fprintf(out, "%s } else if (value instanceof String) {\n",
+ indent.c_str());
+ fprintf(out,
+ "%s final String str = (value == null) ? \"\" : "
+ "(String) value;\n",
+ indent.c_str());
+ fprintf(out,
+ "%s final int len = "
+ "str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
+ indent.c_str());
+ fprintf(out,
+ "%s keyValuePairSize += LIST_TYPE_OVERHEAD + "
+ "INT_TYPE_SIZE\n",
+ indent.c_str());
+ fprintf(out, "%s + STRING_TYPE_OVERHEAD + len;\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s stringMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s stringMap.put(key, str);\n", indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Float) {\n",
+ indent.c_str());
+ fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
+ indent.c_str());
+ fprintf(out, "%s + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s floatMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s floatMap.put(key, (Float) value);\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s needed += keyValuePairSize;\n", indent.c_str());
+ break;
+ }
+ default:
+ // Unsupported types: OBJECT, DOUBLE.
+ fprintf(stderr, "Module logging does not yet support Object and Double.\n");
+ return 1;
}
argIndex++;
}
- // Now we have the size that is needed. Check for overflow and return if needed.
+ // Now we have the size that is needed. Check for overflow and return if
+ // needed.
fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str());
fprintf(out, "%s return;\n", indent.c_str());
fprintf(out, "%s }\n", indent.c_str());
@@ -279,7 +265,8 @@ int write_java_methods_q_schema(
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
// Write timestamp.
- fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n", indent.c_str());
+ fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n",
+ indent.c_str());
fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str());
fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
@@ -291,77 +278,82 @@ int write_java_methods_q_schema(
// Write the args.
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n",
- indent.c_str(), argIndex);
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex);
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_FLOAT:
- requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
- fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex);
- fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex);
- fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n",
- indent.c_str(), argIndex);
- fprintf(out, "%s System.arraycopy("
- "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n",
- indent.c_str(), argIndex);
- fprintf(out, "%s System.arraycopy("
- "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN:
- {
- requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
-
- fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n", indent.c_str(),
- uidName, tagName);
- fprintf(out, "%s pos += attrSize;\n", indent.c_str());
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR:
- requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
- requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
- fprintf(out,
- "%s writeKeyValuePairs(buff, pos, (byte) count, intMap, longMap, "
- "stringMap, floatMap);\n",
- indent.c_str());
- fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str());
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr,
- "Object and Double are not supported in module logging");
- return 1;
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
+ fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", indent.c_str(),
+ argIndex);
+ fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
+ break;
+ case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
+ fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
+ fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(),
+ argIndex);
+ fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
+ break;
+ case JAVA_TYPE_FLOAT:
+ requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
+ fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str());
+ fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(),
+ argIndex);
+ fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
+ fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(),
+ argIndex);
+ fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
+ fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n",
+ indent.c_str(), argIndex);
+ fprintf(out,
+ "%s System.arraycopy("
+ "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
+ "arg%dBytes.length);\n",
+ indent.c_str(), argIndex, argIndex);
+ fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+ indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
+ fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", indent.c_str(),
+ argIndex);
+ fprintf(out,
+ "%s System.arraycopy("
+ "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
+ indent.c_str(), argIndex, argIndex);
+ fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n",
+ indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+
+ fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n",
+ indent.c_str(), uidName, tagName);
+ fprintf(out, "%s pos += attrSize;\n", indent.c_str());
+ break;
+ }
+ case JAVA_TYPE_KEY_VALUE_PAIR:
+ requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
+ requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
+ fprintf(out,
+ "%s writeKeyValuePairs(buff, pos, (byte) count, intMap, "
+ "longMap, "
+ "stringMap, floatMap);\n",
+ indent.c_str());
+ fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str());
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE.
+ fprintf(stderr, "Object and Double are not supported in module logging");
+ return 1;
}
argIndex++;
}
@@ -376,11 +368,8 @@ int write_java_methods_q_schema(
return 0;
}
-void write_java_helpers_for_q_schema_methods(
- FILE* out,
- const AtomDecl &attributionDecl,
- const int requiredHelpers,
- const string& indent) {
+void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
+ const int requiredHelpers, const string& indent) {
fprintf(out, "\n");
fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str());
fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n",
@@ -420,8 +409,7 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
indent.c_str());
for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s",
- java_type_name(chainField.javaType), chainField.name.c_str());
+ fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
}
fprintf(out, ") {\n");
@@ -437,8 +425,8 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName);
// Write the list begin.
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = %lu;\n",
- indent.c_str(), attributionDecl.fields.size());
+ fprintf(out, "%s buff[pos + 1] = %lu;\n", indent.c_str(),
+ attributionDecl.fields.size());
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
// Write the uid.
@@ -447,18 +435,20 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
// Write the tag.
- fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n",
- indent.c_str(), tagName, tagName, tagName);
- fprintf(out, "%s byte[] %sByte = "
+ fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", indent.c_str(),
+ tagName, tagName, tagName);
+ fprintf(out,
+ "%s byte[] %sByte = "
"%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
indent.c_str(), tagName, tagName);
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName);
- fprintf(out, "%s System.arraycopy("
+ fprintf(out,
+ "%s System.arraycopy("
"%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
indent.c_str(), tagName, tagName);
- fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n",
- indent.c_str(), tagName);
+ fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", indent.c_str(),
+ tagName);
fprintf(out, "%s }\n", indent.c_str());
fprintf(out, "%s}\n", indent.c_str());
fprintf(out, "\n");
@@ -466,7 +456,8 @@ void write_java_helpers_for_q_schema_methods(
if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) {
fprintf(out,
- "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, byte numPairs,\n",
+ "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, "
+ "byte numPairs,\n",
indent.c_str());
fprintf(out, "%s final android.util.SparseIntArray intMap,\n", indent.c_str());
fprintf(out, "%s final android.util.SparseLongArray longMap,\n", indent.c_str());
@@ -515,7 +506,9 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s }\n", indent.c_str());
// Write Strings.
- fprintf(out, "%s final int stringMapSize = null == stringMap ? 0 : stringMap.size();\n",
+ fprintf(out,
+ "%s final int stringMapSize = null == stringMap ? 0 : "
+ "stringMap.size();\n",
indent.c_str());
fprintf(out, "%s for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
@@ -523,7 +516,8 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
fprintf(out, "%s final int key = stringMap.keyAt(i);\n", indent.c_str());
fprintf(out, "%s final String value = stringMap.valueAt(i);\n", indent.c_str());
- fprintf(out, "%s final byte[] valueBytes = "
+ fprintf(out,
+ "%s final byte[] valueBytes = "
"value.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
indent.c_str());
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
@@ -531,15 +525,19 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
fprintf(out, "%s copyInt(buff, pos + 1, valueBytes.length);\n", indent.c_str());
- fprintf(out, "%s System.arraycopy("
- "valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, valueBytes.length);\n",
+ fprintf(out,
+ "%s System.arraycopy("
+ "valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
+ "valueBytes.length);\n",
indent.c_str());
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + valueBytes.length;\n",
indent.c_str());
fprintf(out, "%s }\n", indent.c_str());
// Write floats.
- fprintf(out, "%s final int floatMapSize = null == floatMap ? 0 : floatMap.size();\n",
+ fprintf(out,
+ "%s final int floatMapSize = null == floatMap ? 0 : "
+ "floatMap.size();\n",
indent.c_str());
fprintf(out, "%s for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
@@ -559,12 +557,11 @@ void write_java_helpers_for_q_schema_methods(
}
}
-// This method is called in main.cpp to generate StatsLog for modules that's compatible with
-// Q at compile-time.
+// This method is called in main.cpp to generate StatsLog for modules that's
+// compatible with Q at compile-time.
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
- const AtomDecl &attributionDecl,
- const string& javaClass, const string& javaPackage,
- const bool supportWorkSource) {
+ const AtomDecl& attributionDecl, const string& javaClass,
+ const string& javaPackage, const bool supportWorkSource) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -590,8 +587,7 @@ int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
int errors = 0;
// Print write methods
fprintf(out, " // Write methods\n");
- errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl,
- " ");
+ errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl, " ");
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 0f33b6cf94a1..f1cfc44494e5 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -16,14 +16,14 @@
#pragma once
-#include "Collation.h"
+#include <stdio.h>
+#include <string.h>
#include <map>
#include <set>
#include <vector>
-#include <stdio.h>
-#include <string.h>
+#include "Collation.h"
namespace android {
namespace stats_log_api_gen {
@@ -33,20 +33,15 @@ using namespace std;
void write_java_q_logging_constants(FILE* out, const string& indent);
int write_java_methods_q_schema(
- FILE* out,
- const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
- const AtomDecl &attributionDecl,
- const string& indent);
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+ const AtomDecl& attributionDecl, const string& indent);
-void write_java_helpers_for_q_schema_methods(
- FILE * out,
- const AtomDecl &attributionDecl,
- const int requiredHelpers,
- const string& indent);
+void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
+ const int requiredHelpers, const string& indent);
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
- const AtomDecl &attributionDecl, const string& javaClass,
- const string& javaPackage, const bool supportWorkSource);
+ const AtomDecl& attributionDecl, const string& javaClass,
+ const string& javaPackage, const bool supportWorkSource);
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 4f791a35be7b..fda57369d7bf 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1,22 +1,21 @@
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
#include "Collation.h"
#include "atoms_info_writer.h"
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include "java_writer.h"
#include "java_writer_q.h"
#include "native_writer.h"
#include "utils.h"
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
using namespace google::protobuf;
using namespace std;
@@ -25,25 +24,34 @@ namespace stats_log_api_gen {
using android::os::statsd::Atom;
-static void
-print_usage()
-{
+static void print_usage() {
fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
fprintf(stderr, "\n");
fprintf(stderr, "OPTIONS\n");
fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n");
fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n");
fprintf(stderr,
- " --atomsInfoCpp FILENAME the header file to output for statsd metadata\n");
- fprintf(stderr, " --atomsInfoHeader FILENAME the cpp file to output for statsd metadata\n");
+ " --atomsInfoCpp FILENAME the header file to output for "
+ "statsd metadata\n");
+ fprintf(stderr,
+ " --atomsInfoHeader FILENAME the cpp file to output for statsd "
+ "metadata\n");
fprintf(stderr, " --help this message\n");
fprintf(stderr, " --java FILENAME the java file to output\n");
fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
- fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n");
- fprintf(stderr, " comma separated namespace of the files\n");
- fprintf(stderr," --importHeader NAME required for cpp/jni to say which header to import "
+ fprintf(stderr,
+ " --namespace COMMA,SEP,NAMESPACE required for cpp/header with "
+ "module\n");
+ fprintf(stderr,
+ " comma separated namespace of "
+ "the files\n");
+ fprintf(stderr,
+ " --importHeader NAME required for cpp/jni to say which header to "
+ "import "
"for write helpers\n");
- fprintf(stderr," --atomsInfoImportHeader NAME required for cpp to say which header to import "
+ fprintf(stderr,
+ " --atomsInfoImportHeader NAME required for cpp to say which "
+ "header to import "
"for statsd metadata\n");
fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n");
fprintf(stderr, " required for java with module\n");
@@ -51,17 +59,18 @@ print_usage()
fprintf(stderr, " Optional for Java with module.\n");
fprintf(stderr, " Default is \"StatsLogInternal\"\n");
fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
- fprintf(stderr, " --worksource Include support for logging WorkSource objects.\n");
- fprintf(stderr, " --compileQ Include compile-time support for Android Q "
+ fprintf(stderr,
+ " --worksource Include support for logging WorkSource "
+ "objects.\n");
+ fprintf(stderr,
+ " --compileQ Include compile-time support for Android Q "
"(Java only).\n");
}
/**
* Do the argument parsing and execute the tasks.
*/
-static int
-run(int argc, char const*const* argv)
-{
+static int run(int argc, char const* const* argv) {
string cppFilename;
string headerFilename;
string javaFilename;
@@ -171,11 +180,8 @@ run(int argc, char const*const* argv)
index++;
}
- if (cppFilename.size() == 0
- && headerFilename.size() == 0
- && javaFilename.size() == 0
- && atomsInfoHeaderFilename.size() == 0
- && atomsInfoCppFilename.size() == 0) {
+ if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0 &&
+ atomsInfoHeaderFilename.size() == 0 && atomsInfoCppFilename.size() == 0) {
print_usage();
return 1;
}
@@ -201,8 +207,8 @@ run(int argc, char const*const* argv)
AtomDecl attributionDecl;
vector<java_type_t> attributionSignature;
- collate_atom(android::os::statsd::AttributionNode::descriptor(),
- &attributionDecl, &attributionSignature);
+ collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
+ &attributionSignature);
// Write the atoms info .cpp file
if (atomsInfoCppFilename.size() != 0) {
@@ -211,8 +217,8 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str());
return 1;
}
- errorCount = android::stats_log_api_gen::write_atoms_info_cpp(
- out, atoms, cppNamespace, atomsInfoCppHeaderImport);
+ errorCount = android::stats_log_api_gen::write_atoms_info_cpp(out, atoms, cppNamespace,
+ atomsInfoCppHeaderImport);
fclose(out);
}
@@ -227,7 +233,6 @@ run(int argc, char const*const* argv)
fclose(out);
}
-
// Write the .cpp file
if (cppFilename.size() != 0) {
FILE* out = fopen(cppFilename.c_str(), "w");
@@ -240,13 +245,14 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
return 1;
}
- // If this is for a specific module, the header file to import must also be provided.
+ // If this is for a specific module, the header file to import must also be
+ // provided.
if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
return 1;
}
errorCount = android::stats_log_api_gen::write_stats_log_cpp(
- out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ);
+ out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ);
fclose(out);
}
@@ -261,8 +267,8 @@ run(int argc, char const*const* argv)
if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
}
- errorCount = android::stats_log_api_gen::write_stats_log_header(
- out, atoms, attributionDecl, cppNamespace);
+ errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms, attributionDecl,
+ cppNamespace);
fclose(out);
}
@@ -291,8 +297,7 @@ run(int argc, char const*const* argv)
if (compileQ) {
errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
- out, atoms, attributionDecl, javaClass, javaPackage,
- supportWorkSource);
+ out, atoms, attributionDecl, javaClass, javaPackage, supportWorkSource);
} else {
errorCount = android::stats_log_api_gen::write_stats_log_java(
out, atoms, attributionDecl, javaClass, javaPackage, supportQ,
@@ -311,9 +316,7 @@ run(int argc, char const*const* argv)
/**
* Main.
*/
-int
-main(int argc, char const*const* argv)
-{
+int main(int argc, char const* const* argv) {
GOOGLE_PROTOBUF_VERIFY_VERSION;
return android::stats_log_api_gen::run(argc, argv);
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 90dcae4197a2..0cf3225e7708 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -15,45 +15,38 @@
*/
#include "native_writer.h"
+
#include "utils.h"
namespace android {
namespace stats_log_api_gen {
-static void write_annotations(
- FILE* out, int argIndex,
- const FieldNumberToAnnotations& fieldNumberToAnnotations,
- const string& methodPrefix,
- const string& methodSuffix) {
+static void write_annotations(FILE* out, int argIndex,
+ const FieldNumberToAnnotations& fieldNumberToAnnotations,
+ const string& methodPrefix, const string& methodSuffix) {
auto fieldNumberToAnnotationsIt = fieldNumberToAnnotations.find(argIndex);
if (fieldNumberToAnnotationsIt == fieldNumberToAnnotations.end()) {
return;
}
- const set<shared_ptr<Annotation>>& annotations =
- fieldNumberToAnnotationsIt->second;
+ const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotationsIt->second;
for (const shared_ptr<Annotation>& annotation : annotations) {
// TODO(b/151744250): Group annotations for same atoms.
// TODO(b/151786433): Write atom constant name instead of atom id literal.
fprintf(out, " if (code == %d) {\n", annotation->atomId);
- switch(annotation->type) {
- // TODO(b/151776731): Check for reset state annotation and only include reset state
- // when field value == default state annotation value.
+ switch (annotation->type) {
+ // TODO(b/151776731): Check for reset state annotation and only include
+ // reset state when field value == default state annotation value.
case ANNOTATION_TYPE_INT:
// TODO(b/151786433): Write annotation constant name instead of
// annotation id literal.
- fprintf(out, " %saddInt32Annotation(%s%d, %d);\n",
- methodPrefix.c_str(),
- methodSuffix.c_str(),
- annotation->annotationId,
- annotation->value.intValue);
+ fprintf(out, " %saddInt32Annotation(%s%d, %d);\n", methodPrefix.c_str(),
+ methodSuffix.c_str(), annotation->annotationId, annotation->value.intValue);
break;
case ANNOTATION_TYPE_BOOL:
// TODO(b/151786433): Write annotation constant name instead of
// annotation id literal.
- fprintf(out, " %saddBoolAnnotation(%s%d, %s);\n",
- methodPrefix.c_str(),
- methodSuffix.c_str(),
- annotation->annotationId,
+ fprintf(out, " %saddBoolAnnotation(%s%d, %s);\n", methodPrefix.c_str(),
+ methodSuffix.c_str(), annotation->annotationId,
annotation->value.boolValue ? "true" : "false");
break;
default:
@@ -61,29 +54,28 @@ static void write_annotations(
}
fprintf(out, " }\n");
}
-
}
static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const bool supportQ) {
+ const AtomDecl& attributionDecl, const bool supportQ) {
fprintf(out, "\n");
for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
- signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
+ signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first;
const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second;
// Key value pairs not supported in native.
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
continue;
}
- write_native_method_signature(out, "int stats_write", signature,
- attributionDecl, " {");
+ write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
int argIndex = 1;
if (supportQ) {
fprintf(out, " StatsEventCompat event;\n");
fprintf(out, " event.setAtomId(code);\n");
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "event.", "");
for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ arg != signature.end(); arg++) {
switch (*arg) {
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
const char* uidName = attributionDecl.fields.front().name.c_str();
@@ -99,7 +91,7 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
case JAVA_TYPE_BOOLEAN:
fprintf(out, " event.writeBool(arg%d);\n", argIndex);
break;
- case JAVA_TYPE_INT: // Fall through.
+ case JAVA_TYPE_INT: // Fall through.
case JAVA_TYPE_ENUM:
fprintf(out, " event.writeInt32(arg%d);\n", argIndex);
break;
@@ -124,8 +116,10 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
} else {
fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "AStatsEvent_",
+ "event, ");
for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ arg != signature.end(); arg++) {
switch (*arg) {
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
const char* uidName = attributionDecl.fields.front().name.c_str();
@@ -140,13 +134,14 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
case JAVA_TYPE_BYTE_ARRAY:
fprintf(out,
" AStatsEvent_writeByteArray(event, "
- "reinterpret_cast<const uint8_t*>(arg%d.arg), arg%d.arg_length);\n",
+ "reinterpret_cast<const uint8_t*>(arg%d.arg), "
+ "arg%d.arg_length);\n",
argIndex, argIndex);
break;
case JAVA_TYPE_BOOLEAN:
fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
break;
- case JAVA_TYPE_INT: // Fall through.
+ case JAVA_TYPE_INT: // Fall through.
case JAVA_TYPE_ENUM:
fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
break;
@@ -165,7 +160,7 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
return 1;
}
write_annotations(out, argIndex, fieldNumberToAnnotations, "AStatsEvent_",
- "event, ");
+ "event, ");
argIndex++;
}
fprintf(out, " const int ret = AStatsEvent_write(event);\n");
@@ -178,10 +173,10 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
}
static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl) {
+ const AtomDecl& attributionDecl) {
fprintf(out, "\n");
for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
- signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
+ signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
vector<java_type_t> signature = signature_it->first;
// Key value pairs not supported in native.
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
@@ -189,7 +184,7 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms&
}
write_native_method_signature(out, "int stats_write_non_chained", signature,
- attributionDecl, " {");
+ attributionDecl, " {");
vector<java_type_t> newSignature;
@@ -212,17 +207,14 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms&
fprintf(out, "}\n\n");
}
-
}
static void write_native_method_header(
- FILE* out,
- const string& methodName,
+ FILE* out, const string& methodName,
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
- const AtomDecl &attributionDecl) {
-
+ const AtomDecl& attributionDecl) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first;
// Key value pairs not supported in native.
@@ -233,9 +225,9 @@ static void write_native_method_header(
}
}
-int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
- const string& cppNamespace,
- const string& importHeader, const bool supportQ) {
+int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+ const string& cppNamespace, const string& importHeader,
+ const bool supportQ) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -260,8 +252,8 @@ int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributi
return 0;
}
-int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& cppNamespace) {
+int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+ const string& cppNamespace) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -286,21 +278,18 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attrib
fprintf(out, "//\n");
fprintf(out, "// Constants for enum values\n");
fprintf(out, "//\n\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
-
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
+ field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ENUM) {
- fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
- field->name.c_str());
+ fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), field->name.c_str());
for (map<int, string>::const_iterator value = field->enumValues.begin();
- value != field->enumValues.end(); value++) {
+ value != field->enumValues.end(); value++) {
fprintf(out, "const int32_t %s__%s__%s = %d;\n",
- make_constant_name(atom->message).c_str(),
- make_constant_name(field->name).c_str(),
- make_constant_name(value->second).c_str(),
- value->first);
+ make_constant_name(atom->message).c_str(),
+ make_constant_name(field->name).c_str(),
+ make_constant_name(value->second).c_str(), value->first);
}
fprintf(out, "\n");
}
@@ -325,8 +314,8 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attrib
fprintf(out, "//\n");
fprintf(out, "// Write flattened methods\n");
fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write_non_chained",
- atoms.nonChainedSignatureInfoMap, attributionDecl);
+ write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
+ attributionDecl);
fprintf(out, "\n");
write_closing_namespace(out, cppNamespace);
diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h
index 6e603259600d..264d4db29fc9 100644
--- a/tools/stats_log_api_gen/native_writer.h
+++ b/tools/stats_log_api_gen/native_writer.h
@@ -16,22 +16,22 @@
#pragma once
-#include "Collation.h"
-
#include <stdio.h>
#include <string.h>
+#include "Collation.h"
+
namespace android {
namespace stats_log_api_gen {
using namespace std;
-int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
- const string& cppNamespace, const string& importHeader,
- const bool supportQ);
+int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+ const string& cppNamespace, const string& importHeader,
+ const bool supportQ);
-int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& cppNamespace);
+int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+ const string& cppNamespace);
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 5032ac088f4f..9878926bb045 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -15,11 +15,10 @@
*/
#include <gtest/gtest.h>
+#include <stdio.h>
-#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
#include "Collation.h"
-
-#include <stdio.h>
+#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
namespace android {
namespace stats_log_api_gen {
@@ -31,14 +30,13 @@ using std::vector;
/**
* Return whether the map contains a vector of the elements provided.
*/
-static bool
-map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s, int count, ...)
-{
+static bool map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s,
+ int count, ...) {
va_list args;
vector<java_type_t> v;
va_start(args, count);
- for (int i=0; i<count; i++) {
+ for (int i = 0; i < count; i++) {
v.push_back((java_type_t)va_arg(args, int));
}
va_end(args);
@@ -49,34 +47,33 @@ map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s,
/**
* Expect that the provided map contains the elements provided.
*/
-#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \
- do { \
- int count = sizeof((int[]){__VA_ARGS__})/sizeof(int); \
+#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \
+ do { \
+ int count = sizeof((int[]){__VA_ARGS__}) / sizeof(int); \
EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \
- } while(0)
+ } while (0)
/** Expects that the provided atom has no enum values for any field. */
-#define EXPECT_NO_ENUM_FIELD(atom) \
- do { \
+#define EXPECT_NO_ENUM_FIELD(atom) \
+ do { \
for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
- field != atom->fields.end(); field++) { \
- EXPECT_TRUE(field->enumValues.empty()); \
- } \
- } while(0)
+ field != atom->fields.end(); field++) { \
+ EXPECT_TRUE(field->enumValues.empty()); \
+ } \
+ } while (0)
/** Expects that exactly one specific field has expected enum values. */
-#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \
- do { \
+#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \
+ do { \
for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
- field != atom->fields.end(); field++) { \
- if (field->name == field_name) { \
- EXPECT_EQ(field->enumValues, values); \
- } else { \
- EXPECT_TRUE(field->enumValues.empty()); \
- } \
- } \
- } while(0)
-
+ field != atom->fields.end(); field++) { \
+ if (field->name == field_name) { \
+ EXPECT_EQ(field->enumValues, values); \
+ } else { \
+ EXPECT_TRUE(field->enumValues.empty()); \
+ } \
+ } \
+ } while (0)
/**
* Test a correct collation, with all the types.
@@ -95,23 +92,22 @@ TEST(CollationTest, CollateStats) {
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT);
// AllTypesAtom
- EXPECT_MAP_CONTAINS_SIGNATURE(
- atoms.signatureInfoMap,
- JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
- JAVA_TYPE_FLOAT, // float
- JAVA_TYPE_LONG, // int64
- JAVA_TYPE_LONG, // uint64
- JAVA_TYPE_INT, // int32
- JAVA_TYPE_LONG, // fixed64
- JAVA_TYPE_INT, // fixed32
- JAVA_TYPE_BOOLEAN, // bool
- JAVA_TYPE_STRING, // string
- JAVA_TYPE_INT, // uint32
- JAVA_TYPE_INT, // AnEnum
- JAVA_TYPE_INT, // sfixed32
- JAVA_TYPE_LONG, // sfixed64
- JAVA_TYPE_INT, // sint32
- JAVA_TYPE_LONG // sint64
+ EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap,
+ JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
+ JAVA_TYPE_FLOAT, // float
+ JAVA_TYPE_LONG, // int64
+ JAVA_TYPE_LONG, // uint64
+ JAVA_TYPE_INT, // int32
+ JAVA_TYPE_LONG, // fixed64
+ JAVA_TYPE_INT, // fixed32
+ JAVA_TYPE_BOOLEAN, // bool
+ JAVA_TYPE_STRING, // string
+ JAVA_TYPE_INT, // uint32
+ JAVA_TYPE_INT, // AnEnum
+ JAVA_TYPE_INT, // sfixed32
+ JAVA_TYPE_LONG, // sfixed64
+ JAVA_TYPE_INT, // sint32
+ JAVA_TYPE_LONG // sint64
);
set<AtomDecl>::const_iterator atom = atoms.decls.begin();
@@ -156,7 +152,8 @@ TEST(CollationTest, NonMessageTypeFails) {
}
/**
- * Test that atoms that have non-primitive types or repeated fields are rejected.
+ * Test that atoms that have non-primitive types or repeated fields are
+ * rejected.
*/
TEST(CollationTest, FailOnBadTypes) {
Atoms atoms;
@@ -170,18 +167,20 @@ TEST(CollationTest, FailOnBadTypes) {
*/
TEST(CollationTest, FailOnSkippedFieldsSingle) {
Atoms atoms;
- int errorCount = collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+ int errorCount =
+ collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms);
EXPECT_EQ(1, errorCount);
}
/**
- * Test that atoms that skip field numbers (not in the first position, and multiple
- * times) are rejected.
+ * Test that atoms that skip field numbers (not in the first position, and
+ * multiple times) are rejected.
*/
TEST(CollationTest, FailOnSkippedFieldsMultiple) {
Atoms atoms;
- int errorCount = collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+ int errorCount =
+ collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms);
EXPECT_EQ(2, errorCount);
}
@@ -191,11 +190,11 @@ TEST(CollationTest, FailOnSkippedFieldsMultiple) {
* rejected.
*/
TEST(CollationTest, FailBadAttributionNodePosition) {
- Atoms atoms;
- int errorCount =
- collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+ Atoms atoms;
+ int errorCount =
+ collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_EQ(1, errorCount);
+ EXPECT_EQ(1, errorCount);
}
TEST(CollationTest, FailOnBadStateAtomOptions) {
@@ -270,8 +269,8 @@ TEST(CollationTest, RecognizeModuleAtom) {
const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotations.at(1);
EXPECT_EQ(2u, annotations.size());
for (const shared_ptr<Annotation> annotation : annotations) {
- EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID
- || annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
+ EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID ||
+ annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
if (ANNOTATION_ID_IS_UID == annotation->annotationId) {
EXPECT_EQ(1, annotation->atomId);
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
@@ -303,12 +302,11 @@ TEST(CollationTest, RecognizeModule1Atom) {
EXPECT_EQ(1u, fieldNumberToAnnotations.size());
int fieldNumber = 1;
EXPECT_NE(fieldNumberToAnnotations.end(), fieldNumberToAnnotations.find(fieldNumber));
- const set<shared_ptr<Annotation>>& annotations =
- fieldNumberToAnnotations.at(fieldNumber);
+ const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotations.at(fieldNumber);
EXPECT_EQ(2u, annotations.size());
for (const shared_ptr<Annotation> annotation : annotations) {
- EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID
- || annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
+ EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID ||
+ annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
if (ANNOTATION_ID_IS_UID == annotation->annotationId) {
EXPECT_EQ(1, annotation->atomId);
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 7314127d5dfd..0262488e8501 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -22,9 +22,9 @@ namespace android {
namespace stats_log_api_gen {
static void build_non_chained_decl_map(const Atoms& atoms,
- std::map<int, set<AtomDecl>::const_iterator>* decl_map) {
+ std::map<int, set<AtomDecl>::const_iterator>* decl_map) {
for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
- atom != atoms.non_chained_decls.end(); atom++) {
+ atom != atoms.non_chained_decls.end(); atom++) {
decl_map->insert(std::make_pair(atom->code, atom));
}
}
@@ -36,7 +36,7 @@ string make_constant_name(const string& str) {
string result;
const int N = str.size();
bool underscore_next = false;
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
char c = str[i];
if (c >= 'A' && c <= 'Z') {
if (underscore_next) {
@@ -99,7 +99,8 @@ const char* java_type_name(java_type_t type) {
}
// Native
-// Writes namespaces for the cpp and header files, returning the number of namespaces written.
+// Writes namespaces for the cpp and header files, returning the number of
+// namespaces written.
void write_namespace(FILE* out, const string& cppNamespaces) {
vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
for (string cppNamespace : cppNamespaceVec) {
@@ -115,35 +116,31 @@ void write_closing_namespace(FILE* out, const string& cppNamespaces) {
}
}
-static void write_cpp_usage(
- FILE* out, const string& method_name, const string& atom_code_name,
- const AtomDecl& atom, const AtomDecl &attributionDecl) {
- fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(),
- atom_code_name.c_str());
+static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name,
+ const AtomDecl& atom, const AtomDecl& attributionDecl) {
+ fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
- for (vector<AtomField>::const_iterator field = atom.fields.begin();
- field != atom.fields.end(); field++) {
+ for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
+ field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", const std::vector<%s>& %s",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str());
+ fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
+ chainField.name.c_str());
} else {
fprintf(out, ", const %s* %s, size_t %s_length",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str(), chainField.name.c_str());
+ cpp_type_name(chainField.javaType), chainField.name.c_str(),
+ chainField.name.c_str());
}
}
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int32_t>& %s_int"
- ", const std::map<int, int64_t>& %s_long"
- ", const std::map<int, char const*>& %s_str"
- ", const std::map<int, float>& %s_float",
- field->name.c_str(),
- field->name.c_str(),
- field->name.c_str(),
- field->name.c_str());
+ fprintf(out,
+ ", const std::map<int, int32_t>& %s_int"
+ ", const std::map<int, int64_t>& %s_long"
+ ", const std::map<int, char const*>& %s_str"
+ ", const std::map<int, float>& %s_float",
+ field->name.c_str(), field->name.c_str(), field->name.c_str(),
+ field->name.c_str());
} else {
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
}
@@ -162,8 +159,8 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
size_t i = 0;
// Print atom constants
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
string constant = make_constant_name(atom->name);
fprintf(out, "\n");
fprintf(out, " /**\n");
@@ -173,7 +170,7 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
- attributionDecl);
+ attributionDecl);
}
fprintf(out, " */\n");
char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
@@ -186,30 +183,30 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
}
void write_native_method_signature(FILE* out, const string& methodName,
- const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
- const string& closer) {
+ const vector<java_type_t>& signature,
+ const AtomDecl& attributionDecl, const string& closer) {
fprintf(out, "%s(int32_t code", methodName.c_str());
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", const std::vector<%s>& %s",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str());
+ fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
+ chainField.name.c_str());
} else {
- fprintf(out, ", const %s* %s, size_t %s_length",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str(), chainField.name.c_str());
+ fprintf(out, ", const %s* %s, size_t %s_length",
+ cpp_type_name(chainField.javaType), chainField.name.c_str(),
+ chainField.name.c_str());
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
- "const std::map<int, int64_t>& arg%d_2, "
- "const std::map<int, char const*>& arg%d_3, "
- "const std::map<int, float>& arg%d_4",
- argIndex, argIndex, argIndex, argIndex);
+ fprintf(out,
+ ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -219,27 +216,27 @@ void write_native_method_signature(FILE* out, const string& methodName,
}
void write_native_method_call(FILE* out, const string& methodName,
- const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex) {
+ const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
+ int argIndex) {
fprintf(out, "%s(code", methodName.c_str());
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", %s",
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, ", %s", chainField.name.c_str());
+ } else {
+ fprintf(out, ", %s, %s_length", chainField.name.c_str(),
chainField.name.c_str());
- } else {
- fprintf(out, ", %s, %s_length",
- chainField.name.c_str(), chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
- argIndex, argIndex, argIndex);
- } else {
- fprintf(out, ", arg%d", argIndex);
- }
- argIndex++;
+ }
+ }
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, argIndex, argIndex,
+ argIndex);
+ } else {
+ fprintf(out, ", arg%d", argIndex);
+ }
+ argIndex++;
}
fprintf(out, ");\n");
}
@@ -252,8 +249,8 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms) {
build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
// Print constants for the atom codes.
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
string constant = make_constant_name(atom->name);
fprintf(out, "\n");
fprintf(out, " /**\n");
@@ -271,20 +268,19 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms) {
void write_java_enum_values(FILE* out, const Atoms& atoms) {
fprintf(out, " // Constants for enum values.\n\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+ atom++) {
for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
+ field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ENUM) {
fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
- field->name.c_str());
+ field->name.c_str());
for (map<int, string>::const_iterator value = field->enumValues.begin();
- value != field->enumValues.end(); value++) {
+ value != field->enumValues.end(); value++) {
fprintf(out, " public static final int %s__%s__%s = %d;\n",
- make_constant_name(atom->message).c_str(),
- make_constant_name(field->name).c_str(),
- make_constant_name(value->second).c_str(),
- value->first);
+ make_constant_name(atom->message).c_str(),
+ make_constant_name(field->name).c_str(),
+ make_constant_name(value->second).c_str(), value->first);
}
fprintf(out, "\n");
}
@@ -293,11 +289,11 @@ void write_java_enum_values(FILE* out, const Atoms& atoms) {
}
void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
- const AtomDecl& atom) {
- fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s",
- method_name.c_str(), atom_code_name.c_str());
- for (vector<AtomField>::const_iterator field = atom.fields.begin();
- field != atom.fields.end(); field++) {
+ const AtomDecl& atom) {
+ fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", method_name.c_str(),
+ atom_code_name.c_str());
+ for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
+ field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(out, ", android.os.WorkSource workSource");
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
@@ -312,16 +308,15 @@ void write_java_usage(FILE* out, const string& method_name, const string& atom_c
}
int write_java_non_chained_methods(
- FILE* out,
- const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static void write_non_chained(int code");
vector<java_type_t> signature = signatureInfoMapIt->first;
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(stderr, "Non chained signatures should not have attribution chains.\n");
return 1;
@@ -337,8 +332,8 @@ int write_java_non_chained_methods(
fprintf(out, " write(code");
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
// First two args are uid and tag of attribution chain.
if (argIndex == 1) {
fprintf(out, ", new int[] {arg%d}", argIndex);
@@ -357,23 +352,24 @@ int write_java_non_chained_methods(
}
int write_java_work_source_methods(
- FILE* out,
- const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
fprintf(out, " // WorkSource methods.\n");
for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first;
// Determine if there is Attribution in this signature.
int attributionArg = -1;
int argIndexMax = 0;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
argIndexMax++;
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
if (attributionArg > -1) {
fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
- fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n");
+ fprintf(out,
+ "\n// Invalid for WorkSource: more than one attribution "
+ "chain.\n");
return 1;
}
attributionArg = argIndexMax;
@@ -387,8 +383,8 @@ int write_java_work_source_methods(
// Method header (signature)
fprintf(out, " public static void write(int code");
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(out, ", android.os.WorkSource ws");
} else {
@@ -398,36 +394,40 @@ int write_java_work_source_methods(
}
fprintf(out, ") {\n");
- // write_non_chained() component. TODO: Remove when flat uids are no longer needed.
+ // write_non_chained() component. TODO: Remove when flat uids are no longer
+ // needed.
fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
fprintf(out, " write_non_chained(code");
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
if (argIndex == attributionArg) {
fprintf(out, ", ws.getUid(i), ws.getPackageName(i)");
} else {
- fprintf(out, ", arg%d", argIndex);
+ fprintf(out, ", arg%d", argIndex);
}
}
fprintf(out, ");\n");
- fprintf(out, " }\n"); // close for-loop
+ fprintf(out, " }\n"); // close for-loop
// write() component.
- fprintf(out, " java.util.List<android.os.WorkSource.WorkChain> workChains = "
+ fprintf(out,
+ " java.util.List<android.os.WorkSource.WorkChain> workChains = "
"ws.getWorkChains();\n");
fprintf(out, " if (workChains != null) {\n");
- fprintf(out, " for (android.os.WorkSource.WorkChain wc : workChains) {\n");
+ fprintf(out,
+ " for (android.os.WorkSource.WorkChain wc : workChains) "
+ "{\n");
fprintf(out, " write(code");
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
if (argIndex == attributionArg) {
fprintf(out, ", wc.getUids(), wc.getTags()");
} else {
- fprintf(out, ", arg%d", argIndex);
+ fprintf(out, ", arg%d", argIndex);
}
}
fprintf(out, ");\n");
- fprintf(out, " }\n"); // close for-loop
- fprintf(out, " }\n"); // close if
- fprintf(out, " }\n"); // close method
+ fprintf(out, " }\n"); // close for-loop
+ fprintf(out, " }\n"); // close if
+ fprintf(out, " }\n"); // close method
}
return 0;
}
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index a6b3ef9fe99e..468f3233d77f 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -16,14 +16,14 @@
#pragma once
-#include "Collation.h"
+#include <stdio.h>
+#include <string.h>
#include <map>
#include <set>
#include <vector>
-#include <stdio.h>
-#include <string.h>
+#include "Collation.h"
namespace android {
namespace stats_log_api_gen {
@@ -52,11 +52,12 @@ void write_closing_namespace(FILE* out, const string& cppNamespaces);
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
void write_native_method_signature(FILE* out, const string& methodName,
- const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
- const string& closer);
+ const vector<java_type_t>& signature,
+ const AtomDecl& attributionDecl, const string& closer);
void write_native_method_call(FILE* out, const string& methodName,
- const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex = 1);
+ const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
+ int argIndex = 1);
// Common Java helpers.
void write_java_atom_codes(FILE* out, const Atoms& atoms);
@@ -64,14 +65,13 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms);
void write_java_enum_values(FILE* out, const Atoms& atoms);
void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
- const AtomDecl& atom);
+ const AtomDecl& atom);
-int write_java_non_chained_methods(FILE* out, const map<vector<java_type_t>,
- FieldNumberToAnnotations>& signatureInfoMap);
+int write_java_non_chained_methods(
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
int write_java_work_source_methods(
- FILE* out,
- const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
+ FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
} // namespace stats_log_api_gen
} // namespace android
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 9d9a495d68ef..d0f1a26f7dbf 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -170,24 +170,23 @@ droidstubs {
java_library {
name: "framework-wifi-stubs-publicapi",
srcs: [":framework-wifi-stubs-srcs-publicapi"],
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
+ // TODO(b/151134996): remove this
sdk_version: "current",
- installable: false,
}
java_library {
name: "framework-wifi-stubs-systemapi",
srcs: [":framework-wifi-stubs-srcs-systemapi"],
- sdk_version: "system_current",
libs: ["framework-annotations-lib"],
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
java_library {
name: "framework-wifi-stubs-module_libs_api",
srcs: [":framework-wifi-stubs-srcs-module_libs_api"],
- sdk_version: "module_current",
libs: ["framework-annotations-lib"],
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
}
// defaults for tests that need to build against framework-wifi's @hide APIs
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index a269e17a8cff..457e0db9dc54 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -516,9 +516,6 @@ public final class SoftApConfiguration implements Parcelable {
public WifiConfiguration toWifiConfiguration() {
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = mSsid;
- if (mBssid != null) {
- wifiConfig.BSSID = mBssid.toString();
- }
wifiConfig.preSharedKey = mPassphrase;
wifiConfig.hiddenSSID = mHiddenSsid;
wifiConfig.apChannel = mChannel;
@@ -662,8 +659,6 @@ public final class SoftApConfiguration implements Parcelable {
/**
* Specifies a BSSID for the AP.
* <p>
- * Only supported when configuring a local-only hotspot.
- * <p>
* <li>If not set, defaults to null.</li>
* @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
* responsible for avoiding collisions.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ba68d170364c..b110a6139429 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2356,6 +2356,8 @@ public class WifiConfiguration implements Parcelable {
sbuf.append(" lcuid=" + lastConnectUid);
sbuf.append(" allowAutojoin=" + allowAutojoin);
sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
+ sbuf.append(" mostRecentlyConnected=" + isMostRecentlyConnected);
+
sbuf.append(" ");
if (this.lastConnected != 0) {
@@ -2964,4 +2966,11 @@ public class WifiConfiguration implements Parcelable {
return mPasspointUniqueId;
}
+ /**
+ * If network is one of the most recently connected.
+ * For framework internal use only. Do not parcel.
+ * @hide
+ */
+ public boolean isMostRecentlyConnected = false;
+
}