diff options
105 files changed, 2724 insertions, 1922 deletions
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/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/statsd/Android.bp b/cmds/statsd/Android.bp index 4529dff0dc5c..6fe098c2a123 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -378,55 +378,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/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/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/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/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/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index a68cc3dfe0e4..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; 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/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/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/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/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/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/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/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..4f16031741bc 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; @@ -136,6 +138,9 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private FloatingContentCoordinator mFloatingContentCoordinator; + private SysUiState mSysUiState; + private boolean mSysUiStateBubblesExpanded; + @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor; @Captor @@ -229,6 +234,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 +267,8 @@ public class BubbleControllerTest extends SysuiTestCase { mNotifPipeline, mFeatureFlagsOldPipeline, mDumpManager, - mFloatingContentCoordinator); + mFloatingContentCoordinator, + mSysUiState); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -277,6 +288,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleController.hasBubbles()); verify(mBubbleStateChangeListener).onHasBubblesChanged(true); + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -284,6 +296,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertFalse(mBubbleController.hasBubbles()); mBubbleController.updateBubble(mRow.getEntry()); assertTrue(mBubbleController.hasBubbles()); + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -300,6 +313,8 @@ public class BubbleControllerTest extends SysuiTestCase { assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey())); verify(mNotificationEntryManager, times(2)).updateNotifications(anyString()); verify(mBubbleStateChangeListener).onHasBubblesChanged(false); + + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -323,6 +338,8 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mNotificationEntryManager, times(1)).performRemoveNotification( eq(mRow.getEntry().getSbn()), anyInt()); assertFalse(mBubbleController.hasBubbles()); + + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -340,6 +357,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 +382,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 +393,8 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey()); assertFalse(mBubbleController.isStackExpanded()); assertFalse(mNotificationShadeWindowController.getBubbleExpanded()); + + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -395,6 +418,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 +441,8 @@ public class BubbleControllerTest extends SysuiTestCase { // Collapse mBubbleController.collapseStack(); assertFalse(mBubbleController.isStackExpanded()); + + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -437,6 +464,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 +492,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 +524,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 +555,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 +576,8 @@ public class BubbleControllerTest extends SysuiTestCase { // # of bubbles should change verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); + + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -559,6 +596,8 @@ public class BubbleControllerTest extends SysuiTestCase { // # of bubbles should change verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); + + assertTrue(mSysUiStateBubblesExpanded); } @Test @@ -579,6 +618,8 @@ public class BubbleControllerTest extends SysuiTestCase { // # of bubbles should change verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); + + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -605,6 +646,8 @@ public class BubbleControllerTest extends SysuiTestCase { // # of bubbles should change verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); + + assertFalse(mSysUiStateBubblesExpanded); } @Test @@ -619,6 +662,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/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index 2fbba68f1e03..00d0d9c428ff 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 { diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index bb9446078da6..9018caa8d7b6 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; @@ -903,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) -> { @@ -1779,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(); 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/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/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..6c5428c69377 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"). @@ -4016,6 +4025,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 */); 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/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/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/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/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/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/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/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/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; + } |